package org.bitseal.services;

import org.bitseal.R;
import org.bitseal.activities.InboxActivity;
import org.bitseal.activities.LockScreenActivity;

import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.util.Log;

public class NotificationsService extends IntentService
{
	public static final String EXTRA_NEW_MESSAGES_NOTIFICATION_CLEARED = "extraNewMessagesNotificationCleared";
	public static final String KEY_NEW_MESSAGES_NOTIFICATION_CURRENTLY_DISPLAYED = "keyNewMessagesNotificationCurrentlyDisplayed";
	public static final String EXTRA_DISPLAY_NEW_MESSAGES_NOTIFICATION = "displayNewMessagesNotification";
	
	public static final String EXTRA_DISPLAY_UNLOCK_NOTIFICATION = "extraDisplayUnlockNotification";
	
	/** A random value used as a unique ID number of the 'new messages received' notification */
	private static final int NEW_MESSAGES_NOTIFICATION_ID = 43282372;
	
	/** A random value used as a unique ID number of the 'new messages received' notification */
	private static final int UNLOCK_NOTIFICATION_ID = 749385039; 
	
	/** A key for storing the number of new messages referred to in the current 'new messages received' notification */
	private static final String NEW_MESSAGES_NOTIFICATION_KEY = "newMessagesNotificationKey";
	
	private static final String UNLOCK_NOTIFICATION_TITLE = "Unlock Bitseal";
	private static final String UNLOCK_NOTIFICATION_TEXT = "Touch to unlock Bitseal";
	
	public static final String TAG = "NOTIFICATIONS_SERVICE";
	
	public NotificationsService()
	{
		super("NotificationsService");
	}
	
	public static int getNewMessagesNotificationId()
	{
		return NEW_MESSAGES_NOTIFICATION_ID;
	}
	
	public static int getUnlockNotificationId()
	{
		return UNLOCK_NOTIFICATION_ID;
	}

	@Override
	protected void onHandleIntent(Intent intent)
	{
		if (intent.hasExtra(EXTRA_NEW_MESSAGES_NOTIFICATION_CLEARED))
		{
			// Set the 'new messages notification currently displayed' shared preference to false
			SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
			SharedPreferences.Editor editor = prefs.edit();
		    editor.putBoolean(KEY_NEW_MESSAGES_NOTIFICATION_CURRENTLY_DISPLAYED, false);
		    editor.commit();
		    
		    Log.i(TAG, "Recorded dismissal of new messages notification");
		}
		else if (intent.hasExtra(EXTRA_DISPLAY_NEW_MESSAGES_NOTIFICATION))
		{
			int newMessages = intent.getExtras().getInt(EXTRA_DISPLAY_NEW_MESSAGES_NOTIFICATION);
			
			displayNewMessagesNotification(newMessages);
		}
		else if (intent.hasExtra(EXTRA_DISPLAY_UNLOCK_NOTIFICATION))
		{
			displayUnlockNotification();
		}
	}
	
	/**
	 * Shows an Android notification that new messages have been received
	 * 
	 * @param newMessages - An int representing the number of new messages received
	 */
	private void displayNewMessagesNotification(int newMessages)
	{		
		int notificationNewMessages; // The number of new messages that this notification will advertise to the user
		
		// Check whether there is already a 'new messages' notification being displayed to the user
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
		boolean newMessagesNotificationCurrentlyDisplayed = prefs.getBoolean(NotificationsService.KEY_NEW_MESSAGES_NOTIFICATION_CURRENTLY_DISPLAYED, false);
		
		// If there is, cancel the current notification and show a new one that takes account of the number of messages referred to in the last notification
		if (newMessagesNotificationCurrentlyDisplayed)
		{
			NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
			notificationManager.cancel(NEW_MESSAGES_NOTIFICATION_ID);
			
			int oldNotificationMessages = prefs.getInt(NEW_MESSAGES_NOTIFICATION_KEY, 0);
			notificationNewMessages = newMessages + oldNotificationMessages;
		}
		else
		{
			notificationNewMessages = newMessages;
		}
		
		Log.i(TAG, "Showing notification for " + notificationNewMessages + " new message(s) received");
		
		// Create and display the new notification
		if (notificationNewMessages == 1)
		{
			displayNewMessagesNotification("1 new message received", "Touch to open Bitseal inbox");
		}
		else
		{
			displayNewMessagesNotification(notificationNewMessages + " new messages received", "Touch to open Bitseal inbox");
		}
		
		// Store the number of new messages referred to in this notification so that it can be updated later
		SharedPreferences.Editor editor = prefs.edit();
	    editor.putInt(NEW_MESSAGES_NOTIFICATION_KEY, notificationNewMessages);
	    editor.commit();
	    
	    // Set the 'new messages notification currently displayed' shared preference to true
	    editor.putBoolean(NotificationsService.KEY_NEW_MESSAGES_NOTIFICATION_CURRENTLY_DISPLAYED, true);
	    editor.commit();
	}
	
	/**
	 * Displays an Android notification to the user, informing them that new messages
	 * have been received.<br><br>
	 * 
	 * Note: This method is adapted from the example here: <br>
	 * https://developer.android.com/guide/topics/ui/notifiers/notifications.html
	 * 
	 * @param title - A String containing the title of the notification to display
	 * @param text - A String containing the text of the notification to display
	 */
	private void displayNewMessagesNotification(String title, String text)
	{
		NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
		builder.setContentTitle(title);
		builder.setContentText(text);
		builder.setAutoCancel(true);
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
		{
			builder.setSmallIcon(R.drawable.notification_icon_lollipop);
			builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC); // All we show is the number of new messages received
		}
		else
		{
			builder.setSmallIcon(R.drawable.notification_icon);
		}
		
		// Set a sound for the notification
		Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
		builder.setSound(alarmSound);
		
		// Creates an intent to open the Inbox Activity if the user selects the notification
		Intent openNotificationIntent = new Intent(this, InboxActivity.class);
		openNotificationIntent.putExtra(NotificationsService.EXTRA_NEW_MESSAGES_NOTIFICATION_CLEARED, true);
		
		// Creates an intent to run the notifications service if the user clears the notification
		Intent clearNotificationIntent = new Intent(getApplicationContext(), NotificationsService.class);
		clearNotificationIntent.putExtra(NotificationsService.EXTRA_NEW_MESSAGES_NOTIFICATION_CLEARED, true);
		PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 0, clearNotificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
		builder.setDeleteIntent(pendingIntent);
		
		// The stack builder object will contain an artificial back stack for the
		// started Activity. This ensures that navigating backward from the Activity leads out of
		// your application to the Home screen.
		TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
		
		// Adds the back stack for the Intent (but not the Intent itself)
		stackBuilder.addParentStack(InboxActivity.class);
		
		// Adds the Intent that starts the Activity to the top of the stack
		stackBuilder.addNextIntent(openNotificationIntent);
		PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
		builder.setContentIntent(resultPendingIntent);
		NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
		
		// The notification ID number allows you to update the notification later on.
		notificationManager.notify(NEW_MESSAGES_NOTIFICATION_ID, builder.build());
	}
	
	/**
	 * Displays an Android notification to the user, informing them that the app
	 * needs to be unlocked (decrypting the database). 
	 * 
	 * Note: This method is adapted from the example here: <br>
	 * https://developer.android.com/guide/topics/ui/notifiers/notifications.html
	 */
	private void displayUnlockNotification()
	{
		NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
		builder.setContentTitle(UNLOCK_NOTIFICATION_TITLE);
		builder.setContentText(UNLOCK_NOTIFICATION_TEXT);
		builder.setAutoCancel(true);
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
		{
			builder.setSmallIcon(R.drawable.notification_icon_lollipop);
			builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
		}
		else
		{
			builder.setSmallIcon(R.drawable.notification_icon);
		}
		
		// Creates an intent to open the lock screen activity if the user selects the notification
		Intent openNotificationIntent = new Intent(this, LockScreenActivity.class);
		openNotificationIntent.putExtra(NotificationsService.EXTRA_NEW_MESSAGES_NOTIFICATION_CLEARED, true);
		
		// Creates an intent to run the notifications service if the user clears the notification
		Intent clearNotificationIntent = new Intent(getApplicationContext(), NotificationsService.class);
		clearNotificationIntent.putExtra(NotificationsService.EXTRA_NEW_MESSAGES_NOTIFICATION_CLEARED, true);
		PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 0, clearNotificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
		builder.setDeleteIntent(pendingIntent);
		
		// The stack builder object will contain an artificial back stack for the
		// started Activity. This ensures that navigating backward from the Activity leads out of
		// your application to the Home screen.
		TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
		
		// Adds the back stack for the Intent (but not the Intent itself)
		stackBuilder.addParentStack(LockScreenActivity.class);
		
		// Adds the Intent that starts the Activity to the top of the stack
		stackBuilder.addNextIntent(openNotificationIntent);
		PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
		builder.setContentIntent(resultPendingIntent);
		NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
		
		// The notification ID number allows you to update the notification later on.
		notificationManager.notify(UNLOCK_NOTIFICATION_ID, builder.build());
	}
}