package org.bitseal.activities;

import info.guardianproject.cacheword.CacheWordHandler;
import info.guardianproject.cacheword.ICacheWordSubscriber;

import java.util.ArrayList;
import java.util.Collections;

import org.bitseal.R;
import org.bitseal.core.AddressProcessor;
import org.bitseal.data.Address;
import org.bitseal.data.AddressBookRecord;
import org.bitseal.data.Message;
import org.bitseal.database.AddressBookRecordProvider;
import org.bitseal.database.AddressBookRecordsTable;
import org.bitseal.database.AddressProvider;
import org.bitseal.database.AddressesTable;
import org.bitseal.database.MessageProvider;
import org.bitseal.services.BackgroundService;
import org.bitseal.services.AppLockHandler;
import org.bitseal.util.ColourCalculator;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;

/**
 * The Activity class for the app's "Compose" screen. 
 * 
 * @author Jonathan Coe
 */
public class ComposeActivity extends Activity implements ICacheWordSubscriber
{	
	public static final String EXTRA_TO_ADDRESS = "composeActivity.TO_ADDRESS";
	public static final String EXTRA_FROM_ADDRESS = "composeActivity.FROM_ADDRESS";
	public static final String EXTRA_SUBJECT = "composeActivity.SUBJECT";
	public static final String EXTRA_BODY = "composeActivity.BODY";
	
	public static final String EXTRA_COLOUR_R = "composeActivity.COLOUR_R";
	public static final String EXTRA_COLOUR_G = "composeActivity.COLOUR_G";
	public static final String EXTRA_COLOUR_B = "composeActivity.COLOUR_B";
	
	public static final String KEY_TO_ADDRESS = "toAddress";
	public static final String KEY_FROM_ADDRESS = "fromAddress";
	public static final String KEY_SUBJECT = "subject";
	public static final String KEY_BODY = "body";
	
	private ArrayList<AddressBookRecord> mAddressBookRecords;
	private ArrayList<Address> mAddresses;
	
	private AddressBookRecordAdapter mToAddressesAdapter;
	private AddressAdapter mFromAddressesAdapter;
	
	private String mToAddress = "";
	private String mFromAddress = "";
	private String mSubject = "";
	private String mBody = "";
	
	private View mMainView;
		
	private ListView mToAddressSelectionListView;
	private ListView mFromAddressSelectionListView;
	
	private EditText mToAddressEditText;
	private EditText mFromAddressEditText;
	private EditText mSubjectEditText;
	private EditText mBodyEditText;
		
	private TextView mToAddressSelectionListItemLabelTextView;
	private TextView mToAddressSelectionListItemAddressTextView;
	private TextView mFromAddressSelectionListItemLabelTextView;
	private TextView mFromAddressSelectionListItemAddressTextView;
	
	private int mColourR;
	private int mColourG;
	private int mColourB;
	
	private static final String KEY_TO_ADDRESS_DIALOG_SELECTION = "toAddressDialogSelection";
	private static final String KEY_FROM_ADDRESS_DIALOG_SELECTION = "fromAddressDialogSelection";
	private static final String KEY_ON_PAUSE_CALLED = "onPauseCalled";
		
	private static final int COMPOSE_COLOURS_ALPHA_VALUE = 70;
	
	/**
	 * The maximum permissible size for a message's text (subject + body), in bytes. The maximum size
	 * of an object in Bitmessage protocol version 3 is 256kB. We allow some extra room for the rest of 
	 * the msg object which this message which eventually be transformed into. 
	 */
	private static final int MAXIMUM_MESSAGE_TEXT_SIZE = 250000;
	
    /** The key for a boolean variable that records whether or not a user-defined database encryption passphrase has been saved */
    private static final String KEY_DATABASE_PASSPHRASE_SAVED = "databasePassphraseSaved"; 
    
    private CacheWordHandler mCacheWordHandler;
	
    private static final String TAG = "COMPOSE_ACTIVITY";
	
	@Override
	protected void onCreate(Bundle savedInstanceState) 
	{
		super.onCreate(savedInstanceState);
		
        // Check whether the user has set a database encryption passphrase
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
		if (prefs.getBoolean(KEY_DATABASE_PASSPHRASE_SAVED, false))
		{
			// Connect to the CacheWordService
			mCacheWordHandler = new CacheWordHandler(this);
			mCacheWordHandler.connectToService();
		}
		
		setLayout();
		createDialogs();
		
		useExtras(getIntent()); // Use any extras bundled with the Intent that started this activity
		autoSetFromAddress(); // If we have only one address, auto-set mFromAddress
		setColours();
		
		populateEditTexts();
	}
	
	@Override
	protected void onResume() 
	{
		super.onResume();
		
		useAddressLabels();
		formatEditTexts();
		positionCursor();
	}
	
	@Override
	protected void onPause()
	{
		super.onPause();
		
		// We need to clear the saved dialog selections so that they aren't used in future openings of this activity
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
		SharedPreferences.Editor editor = prefs.edit();
	    editor.putString(KEY_TO_ADDRESS_DIALOG_SELECTION, "");
	    editor.putString(KEY_FROM_ADDRESS_DIALOG_SELECTION, "");
	    
	    // Used to detect screen rotation while the to or from address selection dialogs are open
	    editor.putBoolean(KEY_ON_PAUSE_CALLED, true);
	    
	    editor.commit();
	}
	
	@Override
	protected void onSaveInstanceState (Bundle savedInstanceState) 
	{
	    super.onSaveInstanceState(savedInstanceState);
	        
	    savedInstanceState.putString(KEY_TO_ADDRESS, mToAddress);
	    savedInstanceState.putString(KEY_FROM_ADDRESS, mFromAddress);
	    savedInstanceState.putString(KEY_SUBJECT, mSubject);
	    savedInstanceState.putString(KEY_BODY, mBody);
	}
	
	@Override
	public void onRestoreInstanceState(Bundle savedInstanceState) 
	{
	    super.onRestoreInstanceState(savedInstanceState);
	    
    	mToAddress = savedInstanceState.getString(KEY_TO_ADDRESS);
	    mFromAddress = savedInstanceState.getString(KEY_FROM_ADDRESS);
	    mSubject = savedInstanceState.getString(KEY_SUBJECT);
	    mBody = savedInstanceState.getString(KEY_BODY);
	}
	
    @Override
    /**
     * Deals with the result of the QR code scan
     */
    public void onActivityResult(int requestCode, int resultCode, Intent intent) 
    {
       // Get the result of the QR code scan
       IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
       if (result != null)
       {
	       String contents = result.getContents();
	       if (contents != null)
	       {
	    	   contents = contents.trim(); // Remove leading or trailing spaces
	       		
	    	   Log.i(TAG, "Found QRcode with the following contents: " + contents);
	       		
	    	   if (new AddressProcessor().validateAddress(contents))
	    	   {
	    		   mToAddress = contents;
	    		   mToAddressEditText.setTextSize((float) 12.5);
	    		   
		           int[] colourValues = ColourCalculator.calculateColoursFromAddress(contents);
		           mColourR = colourValues[0];
		           mColourG = colourValues[1];
		           mColourB = colourValues[2];
		           
		  		   getIntent().putExtra(EXTRA_COLOUR_R, colourValues[0]);
		  		   getIntent().putExtra(EXTRA_COLOUR_G, colourValues[1]);
		  		   getIntent().putExtra(EXTRA_COLOUR_B, colourValues[2]);
	    		   
		  		   setColours();
	    		   populateEditTexts();
	    		   positionCursor();
	       		}
	       		else
	       		{
	       			Toast.makeText(getApplicationContext(), R.string.compose_toast_qr_address_invalid, Toast.LENGTH_LONG).show();
	       		}
	       	}
	       else
	       {
	    	   Log.i(TAG, "No QRcode found");
	       }
	    }
    }
	
	/**
	 * Sets up the basic layout for this activity
	 */
	private void setLayout()
	{
		setContentView(R.layout.activity_compose);
		
		mToAddressEditText = (EditText) findViewById(R.id.compose_toAddress_EditText);
		mFromAddressEditText = (EditText) findViewById(R.id.compose_fromAddress_EditText);
		mSubjectEditText = (EditText) findViewById(R.id.compose_subject_EditText);
		mBodyEditText = (EditText) findViewById(R.id.compose_body_EditText);
	}
	
	/**
	 * Executed when the user presses the 'Send' button
	 */
	private void sendMessage()
	{
		Log.i(TAG, "Send Button pressed");
		
		String toAddress = mToAddressEditText.getText().toString();
		String fromAddress = mFromAddressEditText.getText().toString();
		
		// Check that the 'to address' entered by the user is either a valid Bitmessage address or a valid label from the address book
		try
		{
			if (toAddress.equals(""))
			{
				Toast.makeText(getApplicationContext(), R.string.compose_toast_enter_to_address, Toast.LENGTH_LONG).show();
				return;
			}
			AddressProcessor addProc = new AddressProcessor();
			boolean toAddressValid = addProc.validateAddress(toAddress);
			if (toAddressValid == false)
			{
				AddressBookRecordProvider addBookProv = AddressBookRecordProvider.get(getApplicationContext());
				ArrayList<AddressBookRecord> retrievedRecords = addBookProv.searchAddressBookRecords(AddressBookRecordsTable.COLUMN_LABEL, toAddress);
				if (retrievedRecords.size() > 0)
				{
					toAddress = retrievedRecords.get(0).getAddress();
				}
				else
				{
					Toast.makeText(getApplicationContext(), R.string.compose_toast_to_address_invalid, Toast.LENGTH_LONG).show();
					return;
				}
			}
		}
		catch (Exception e)
		{
			Log.e(TAG, "Exception occurred in ComposeActivity.sendMessage(). \n" +
					"The exception messsage was: " + e.getMessage());
			Toast.makeText(getApplicationContext(), R.string.compose_toast_to_address_error, Toast.LENGTH_LONG).show();
			return;
		}	
		
		// Check that the 'from address' entered by the user is either a valid Bitmessage address owned by the user or the label of one
		// of those addresses
		try
		{
			if (fromAddress.equals(""))
			{
				Toast.makeText(getApplicationContext(), R.string.compose_toast_enter_from_address, Toast.LENGTH_LONG).show();
				return;
			}
	
	       	AddressProvider addProv = AddressProvider.get(getApplicationContext());
	        ArrayList<Address> retrievedAddresses = addProv.searchAddresses(AddressesTable.COLUMN_ADDRESS, fromAddress);
			if (retrievedAddresses.size() == 0)
			{
				retrievedAddresses = addProv.searchAddresses(AddressesTable.COLUMN_LABEL, fromAddress);
				if (retrievedAddresses.size() > 0)
				{
					fromAddress = retrievedAddresses.get(0).getAddress();
				}
				else
				{
					Toast.makeText(getApplicationContext(), R.string.compose_toast_from_address_invalid, Toast.LENGTH_LONG).show();
					return;
				}
			}
		}
		catch (Exception e)
		{
			Log.e(TAG, "Exception occurred in ComposeActivity.sendMessage(). \n" +
					"The exception messsage was: " + e.getMessage());
			Toast.makeText(getApplicationContext(), R.string.compose_toast_from_address_error, Toast.LENGTH_LONG).show();
			return;
		}
		
		// Check that the size of the message text is below the maximum permissible value
		String subject = mSubjectEditText.getText().toString();
		String body = mBodyEditText.getText().toString();
		String combinedMessageText = subject.concat(body);
		int messageTextSize = combinedMessageText.getBytes().length;
		if (messageTextSize > MAXIMUM_MESSAGE_TEXT_SIZE)
		{
			Log.e(TAG, "The user attempted to send a message with a combined text (subject + body) size greater than the maximum value allowed. \n" +
					"The size of the combined message text was " + messageTextSize + " bytes.");
			Toast.makeText(getApplicationContext(), R.string.compose_toast_message_too_long, Toast.LENGTH_LONG).show();
			return;
		}
		
		// --------------------------------- Send the message! -------------------------------------------
	    try
	    {
    		// Create a new Message object and populate its fields
    		Message messageToSend = new Message();
			messageToSend.setBelongsToMe(true); // If I create and send a message then it 'belongs to me'. If I receive a message from someone else then it does not.
			messageToSend.setTime(System.currentTimeMillis() / 1000);
			messageToSend.setToAddress(toAddress);
			messageToSend.setFromAddress(fromAddress);
			messageToSend.setSubject(subject);
			messageToSend.setBody(body);
			messageToSend.setStatus(getBaseContext().getString(R.string.message_status_preparing_to_send));
			
			// Save the Message to the database
			MessageProvider msgProv = MessageProvider.get(getApplicationContext());
			long messageId = msgProv.addMessage(messageToSend);
			messageToSend.setId(messageId);

			// Start the BackgroundService to complete the 'send message' task
    		Intent intent = new Intent(getBaseContext(), BackgroundService.class);		    
		    intent.putExtra(BackgroundService.UI_REQUEST, BackgroundService.UI_REQUEST_SEND_MESSAGE);	    
		    intent.putExtra(BackgroundService.MESSAGE_ID, messageId);	    
		    BackgroundService.sendWakefulWork(getBaseContext(), intent);
			
			Toast.makeText(getApplicationContext(), R.string.compose_toast_sending_message, Toast.LENGTH_LONG).show();
			
			mToAddressEditText.setText("");
			mFromAddressEditText.setText("");
			mSubjectEditText.setText("");
			mBodyEditText.setText("");
			
			// Open the Sent Activity
	        Intent i = new Intent(getBaseContext(), SentActivity.class);
	        startActivityForResult(i, 0);
	    }		    
	    catch (Exception e)
	    {
	    	Log.e(TAG, "Exception occured in ComposeActivity while running mSendButton.onClick()");
	    	e.printStackTrace();
			Toast.makeText(getApplicationContext(), R.string.compose_toast_error, Toast.LENGTH_LONG).show();
			return;
	    }
	    // ----------------------------------------------------------------------------------------------
	}
	
	/**
	 * Creates 'to address selection' and 'from address selection' dialogs
	 */
	private void createDialogs()
	{
		final Dialog toAddressSelectionDialog = new Dialog(ComposeActivity.this);
		toAddressSelectionDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);	// This line has to be here so that it is not called repeatedly, which causes a crash
		mToAddressEditText.setOnClickListener(new View.OnClickListener()
		{
			@Override
			public void onClick(View v)
			{
				Log.i(TAG, "To address edit text clicked");
				
				// Get all AddressBookRecords from the application's database
				AddressBookRecordProvider addBookProv = AddressBookRecordProvider.get(getApplicationContext());
				addBookProv = AddressBookRecordProvider.get(getApplicationContext());
			    mAddressBookRecords = addBookProv.getAllAddressBookRecords();
				
				if (mAddressBookRecords.size() > 0)
				{
					// Open a dialog to select a 'to' address
					LinearLayout dialogLayout = (LinearLayout) View.inflate(ComposeActivity.this, R.layout.dialog_compose_to_address_selection, null);
					toAddressSelectionDialog.setContentView(dialogLayout);
					
					WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
				    lp.copyFrom(toAddressSelectionDialog.getWindow().getAttributes());
				    lp.width = WindowManager.LayoutParams.MATCH_PARENT;
					
				    toAddressSelectionDialog.show();
				    toAddressSelectionDialog.getWindow().setAttributes(lp);
				    
				    Button scanQRCodeButton = (Button) dialogLayout.findViewById(R.id.compose_dialog_to_address_selection_scan_qr_code_button);
				    scanQRCodeButton.setOnClickListener(new View.OnClickListener()
					{
						@Override
						public void onClick(View v)
						{
							Log.i(TAG, "To address selection dialog scan qr code button pressed");
							
							toAddressSelectionDialog.dismiss();
							
							IntentIntegrator integrator = new IntentIntegrator(ComposeActivity.this);
			                integrator.initiateScan(IntentIntegrator.QR_CODE_TYPES);
						}
					});
				    
				    Button cancelButton = (Button) dialogLayout.findViewById(R.id.compose_dialog_to_address_selection_cancel_button);
				    cancelButton.setOnClickListener(new View.OnClickListener()
					{
						@Override
						public void onClick(View v)
						{
							Log.i(TAG, "To address selection dialog cancel button pressed");
							
							toAddressSelectionDialog.dismiss();
						}
					});
				    
				    mToAddressesAdapter = new AddressBookRecordAdapter(mAddressBookRecords);
				    
		    		// Sort the AddressBookRecords by label, in alphabetical order
		    		Collections.sort(mAddressBookRecords);
				    
				    mToAddressSelectionListView = new ListView(ComposeActivity.this);
				    mToAddressSelectionListView = (ListView) toAddressSelectionDialog.findViewById(android.R.id.list);
				    mToAddressSelectionListView.setAdapter(mToAddressesAdapter);
				    
				    // Used to detect screen rotation while the to or from address selection dialogs are open
					SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
					SharedPreferences.Editor editor = prefs.edit();
				    editor.putBoolean(KEY_ON_PAUSE_CALLED, false);
				    editor.commit();
				    
				    mToAddressSelectionListView.setOnItemClickListener(new AdapterView.OnItemClickListener() 
				    {
				        @Override
				        public void onItemClick(AdapterView<?> parent, final View view, int position, long id) 
				        {
				        	// Get the AddressBookRecord selected from the adapter
				  		    final AddressBookRecord listAddressBookRecord = (AddressBookRecord) parent.getItemAtPosition(position);
				  		    
				  		    int r = listAddressBookRecord.getColourR();
				  		    int g = listAddressBookRecord.getColourG();
				  		    int b = listAddressBookRecord.getColourB();
				  		    
				  		    // Check whether the activity has been paused while this dialog has been open (e.g. because of screen rotation)
				  		    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
				  		    if (prefs.getBoolean(KEY_ON_PAUSE_CALLED, false))
				  		    {
					  		    // If we just set the text of the edit text directly then the selection will not appear if the screen is rotated
					  		    // while the dialog is open
								SharedPreferences.Editor editor = prefs.edit();
							    editor.putString(KEY_TO_ADDRESS_DIALOG_SELECTION, listAddressBookRecord.getLabel());
							    editor.commit();
							    
								Intent i = new Intent(getBaseContext(), ComposeActivity.class);
						        i.putExtra(EXTRA_TO_ADDRESS, listAddressBookRecord.getLabel());
						        i.putExtra(EXTRA_FROM_ADDRESS, mFromAddressEditText.getText().toString());
						        i.putExtra(EXTRA_SUBJECT, mSubjectEditText.getText().toString());
						        i.putExtra(EXTRA_BODY, mBodyEditText.getText().toString());
		                        i.putExtra(EXTRA_COLOUR_R, r);
		                        i.putExtra(EXTRA_COLOUR_G, g);
		                        i.putExtra(EXTRA_COLOUR_B, b);
						        startActivityForResult(i, 0);
				  		    }
				  		    else
				  		    {
				  		    	// If onPause() has not been called while this dialog has been open, we can just set the value of the edit text directly
				  		    	mToAddressEditText.setText(listAddressBookRecord.getLabel());
				  		    }
				  		    
				  		    // Set the colour member variables and extras for this activity to match those of this address book record
				  		    mColourR = r;
				  		    mColourG = g;
				  		    mColourB = b;
				  		    getIntent().putExtra(EXTRA_COLOUR_R, r);
				  		    getIntent().putExtra(EXTRA_COLOUR_G, g);
				  		    getIntent().putExtra(EXTRA_COLOUR_B, b);
				  		    
				  		    setColours();
				  			formatEditTexts();
				  			positionCursor();
				  			
				  		    toAddressSelectionDialog.dismiss();
						}
					});
				}
			}	
		});
		
		final Dialog fromAddressSelectionDialog = new Dialog(ComposeActivity.this);
		fromAddressSelectionDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); // This line has to be here so that it is not called repeatedly, which causes a crash
		mFromAddressEditText.setOnClickListener(new View.OnClickListener()
		{
			
			@Override
			public void onClick(View v)
			{
				Log.i(TAG, "From address edit text clicked");
				
				// Get all Addresses from the application's database
				AddressProvider addProv = AddressProvider.get(getApplicationContext());
				addProv = AddressProvider.get(getApplicationContext());
			    mAddresses = addProv.getAllAddresses();
			    
			    if (mAddresses.size() > 0)
			    {
			        // Open a dialog to select a from address				
					LinearLayout dialogLayout = (LinearLayout) View.inflate(ComposeActivity.this, R.layout.dialog_compose_from_address_selection, null);
					fromAddressSelectionDialog.setContentView(dialogLayout);
					
					WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
				    lp.copyFrom(fromAddressSelectionDialog.getWindow().getAttributes());
				    lp.width = WindowManager.LayoutParams.MATCH_PARENT;
					
				    fromAddressSelectionDialog.show();
				    fromAddressSelectionDialog.getWindow().setAttributes(lp);
				     
				    Button cancelButton = (Button) dialogLayout.findViewById(R.id.compose_dialog_from_address_selection_cancel_button);
				    cancelButton.setOnClickListener(new View.OnClickListener()
					{
						@Override
						public void onClick(View v)
						{
							Log.i(TAG, "From address selection dialog cancel button pressed");
							
							fromAddressSelectionDialog.dismiss();
						}
					});
				    
				    mFromAddressesAdapter = new AddressAdapter(mAddresses);
				    
				    mFromAddressSelectionListView = new ListView(ComposeActivity.this);
				    mFromAddressSelectionListView = (ListView) fromAddressSelectionDialog.findViewById(android.R.id.list);
				    mFromAddressSelectionListView.setAdapter(mFromAddressesAdapter);
				    
				    // Used to detect screen rotation while the to or from address selection dialogs are open
					SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
					SharedPreferences.Editor editor = prefs.edit();
				    editor.putBoolean(KEY_ON_PAUSE_CALLED, false);
				    editor.commit();
				    
				    mFromAddressSelectionListView.setOnItemClickListener(new AdapterView.OnItemClickListener() 
				    {
				        @Override
				        public void onItemClick(AdapterView<?> parent, final View view, int position, long id) 
				        {
					  		// Get the Address selected from the adapter
					  		final Address listAddress = (Address) parent.getItemAtPosition(position);
					  	    
				  		    // Check whether the activity has been paused while this dialog has been open (e.g. because of screen rotation)
				  		    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
				  		    if (prefs.getBoolean(KEY_ON_PAUSE_CALLED, false))
				  		    {
					  		    // If we just set the text of the edit text directly then the selection will not appear if the screen is rotated
					  		    // while the dialog is open
								SharedPreferences.Editor editor = prefs.edit();
							    editor.putString(KEY_FROM_ADDRESS_DIALOG_SELECTION, listAddress.getLabel());
							    editor.commit();
							    
								Intent i = new Intent(getBaseContext(), ComposeActivity.class);
						        i.putExtra(EXTRA_TO_ADDRESS, mToAddressEditText.getText().toString());
						        i.putExtra(EXTRA_FROM_ADDRESS, listAddress.getLabel());
						        i.putExtra(EXTRA_SUBJECT, mSubjectEditText.getText().toString());
						        i.putExtra(EXTRA_BODY, mBodyEditText.getText().toString());
						        startActivityForResult(i, 0);
				  		    }
				  		    else
				  		    {
				  		    	// If onPause() has not been called while this dialog has been open, we can just set the value of the edit text directly
				  		    	mFromAddressEditText.setText(listAddress.getLabel());
				  		    }
				  		    
				  			formatEditTexts();
				  			positionCursor();
				  		    fromAddressSelectionDialog.dismiss();
						}
					});
			    }
			}
		});
	}
	
	/**
	 * Takes any extras bundled with the Intent that started this Activity
	 * and uses them. 
	 * 
	 * @param extras - The Intent
	 */
	private void useExtras(Intent intent)
	{
		Bundle extras = intent.getExtras();
		
		if(intent.hasExtra(EXTRA_TO_ADDRESS))
		{
			mToAddress = extras.getString(EXTRA_TO_ADDRESS);
		}

		if(intent.hasExtra(EXTRA_FROM_ADDRESS))
		{
			mFromAddress = extras.getString(EXTRA_FROM_ADDRESS);		
		}
		
		if(intent.hasExtra(EXTRA_SUBJECT))
		{
			mSubject = extras.getString(EXTRA_SUBJECT);
		}
		
		if(intent.hasExtra(EXTRA_BODY))
		{
			mBody = extras.getString(EXTRA_BODY);
		}
		
		if(intent.hasExtra(EXTRA_COLOUR_R))
		{
			mColourR = extras.getInt(EXTRA_COLOUR_R);
		}
		
		if(intent.hasExtra(EXTRA_COLOUR_G))
		{
			mColourG = extras.getInt(EXTRA_COLOUR_G);
		}
		
		if(intent.hasExtra(EXTRA_COLOUR_B))
		{
			mColourB = extras.getInt(EXTRA_COLOUR_B);
		}
	}
	
	/**
	 * If we only have one address, auto-fill the 'from address'
	 * edit text
	 */
	private void autoSetFromAddress()
	{
		// If we only have one address, auto-fill the 'from' field
       	AddressProvider addProv = AddressProvider.get(getApplicationContext());
        ArrayList<Address> myAddresses = addProv.getAllAddresses();
        if (myAddresses.size() == 1)
        {	
        	mFromAddress = myAddresses.get(0).getLabel();
        }
	}
	
	/**
	 * Sets the colours to use in this activity
	 */
	private void setColours()
	{
		// Set the colors inherited from the sent list view
		int color = Color.argb(0, mColourR, mColourG, mColourB);
		mToAddressEditText.setBackgroundColor(color);
		mFromAddressEditText.setBackgroundColor(color);
		mSubjectEditText.setBackgroundColor(color);
		mBodyEditText.setBackgroundColor(color);
		
		if (getIntent().hasExtra(EXTRA_COLOUR_R))
		{
			int backgroundColor = Color.argb(COMPOSE_COLOURS_ALPHA_VALUE, mColourR, mColourG, mColourB);
			mMainView = (View) findViewById(R.id.compose_scrollView);
			mMainView.setBackgroundColor(backgroundColor);
		}
		else
		{
			int backgroundColor = Color.argb(0, mColourR, mColourG, mColourB);
			mMainView = (View) findViewById(R.id.compose_scrollView);
			mMainView.setBackgroundColor(backgroundColor);
		}
	}
	
	/**
	 * Populates the edit texts
	 */
	private void populateEditTexts()
	{
		mToAddressEditText.setText(mToAddress);
		mFromAddressEditText.setText(mFromAddress);
		mSubjectEditText.setText(mSubject);
		mBodyEditText.setText(mBody);
		
		// If we have stored values to use for the 'to' or 'from' address, use them
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
		String toAddressSelection = prefs.getString(KEY_TO_ADDRESS_DIALOG_SELECTION, "");
		if (toAddressSelection.equals("") == false)
		{
			mToAddressEditText.setText(toAddressSelection);
		}
		String fromAddressSelection = prefs.getString(KEY_FROM_ADDRESS_DIALOG_SELECTION, "");
		if (fromAddressSelection.equals("") == false)
		{
			mFromAddressEditText.setText(fromAddressSelection);
		}
	}
	
	/**
	 * Substitutes labels for addresses where possible. 
	 */
	private void useAddressLabels()
	{
		AddressBookRecordProvider addBookProv = AddressBookRecordProvider.get(getApplicationContext());
		AddressProvider addProv = AddressProvider.get(getApplicationContext());
		
		// Attempt to use a label for the 'to address'
		ArrayList<AddressBookRecord> addressBookRecords = addBookProv.searchAddressBookRecords(AddressBookRecordsTable.COLUMN_ADDRESS, mToAddressEditText.getText().toString());
		if (addressBookRecords.size() == 1)
		{
			mToAddressEditText.setText(addressBookRecords.get(0).getLabel());
		}
		
		// Attempt to use a label for the 'from address'
		ArrayList<Address> addresses = addProv.searchAddresses(AddressesTable.COLUMN_ADDRESS, mFromAddressEditText.getText().toString());
		if (addresses.size() == 1)
		{
			mFromAddressEditText.setText(addresses.get(0).getLabel());
		}
	}
	
	/**
	 * Formats the edit texts
	 */
	private void formatEditTexts()
	{
		AddressBookRecordProvider addBookProv = AddressBookRecordProvider.get(getApplicationContext());
		AddressProvider addProv = AddressProvider.get(getApplicationContext());
		
		// Format the 'to address' edit text
		ArrayList<AddressBookRecord> addressBookRecords = addBookProv.searchAddressBookRecords(AddressBookRecordsTable.COLUMN_LABEL, mToAddressEditText.getText().toString());
		if (addressBookRecords.size() > 0)
		{
			mToAddressEditText.setTextSize(15);
		}
		
		// Format the 'from address' edit text
		ArrayList<Address> addresses = addProv.searchAddresses(AddressesTable.COLUMN_LABEL, mFromAddressEditText.getText().toString());
		if (addresses.size() > 0)
		{
			mFromAddressEditText.setTextSize(15);
		}
	}
	
	/**
	 * Puts the cursor in the correct place.
	 */
	private void positionCursor()
	{
		if (mToAddressEditText.getText().toString().trim().equals(""))	
		{
			mToAddressEditText.requestFocus();
		}
		else if (mFromAddressEditText.getText().toString().trim().equals(""))	
		{
			mFromAddressEditText.requestFocus();
		}
		else if (mSubjectEditText.getText().toString().trim().equals(""))
		{
			mSubjectEditText.requestFocus();
		}
		else
		{
			mBodyEditText.requestFocus();
		}
	}
	
	/** An inner class used for the listview in the to address selection dialog */
    private class AddressBookRecordAdapter extends ArrayAdapter<AddressBookRecord> 
    {
       public AddressBookRecordAdapter(ArrayList<AddressBookRecord> addressBookRecords) 
       {
           super(getBaseContext(), android.R.layout.simple_list_item_1, addressBookRecords);
       }

       @Override
       public View getView(int position, View convertView, ViewGroup parent) 
       {
           // If we weren't given a view, inflate one
           if (null == convertView) 
           {
           	convertView = getLayoutInflater().inflate(R.layout.list_item_address_book, parent, false);
           }

           // Configure the view for this Address Book Record
           AddressBookRecord a = getItem(position);
           
           // Set the label
           mToAddressSelectionListItemLabelTextView = (TextView)convertView.findViewById(R.id.addressBook_list_item_label_textview);
           
           if (a.getLabel() == null)
           {
        	   mToAddressSelectionListItemLabelTextView.setText("[No label]");
           }
           
           else
           {
        	   mToAddressSelectionListItemLabelTextView.setText(a.getLabel());
           }
           
           // Set the 'to' address
           mToAddressSelectionListItemAddressTextView = (TextView)convertView.findViewById(R.id.addressBook_list_item_address_textview);
           mToAddressSelectionListItemAddressTextView.setText(a.getAddress());
           
           // Set the colour for this view
			int r = a.getColourR();
			int g = a.getColourG();
			int b = a.getColourB();
			 
           convertView.setBackgroundColor(Color.argb(COMPOSE_COLOURS_ALPHA_VALUE, r, g, b));

           int color = Color.argb(0, r, g, b);
           mToAddressSelectionListItemLabelTextView.setBackgroundColor(color);
           mToAddressSelectionListItemAddressTextView.setBackgroundColor(color);      

           return convertView;
       }
   }
    
    /** 
     * An inner class used for the ListView in the 'from address' selection dialog 
     */
    private class AddressAdapter extends ArrayAdapter<Address> 
    {
       public AddressAdapter(ArrayList<Address> addresses) 
       {
           super(getBaseContext(), android.R.layout.simple_list_item_1, addresses);
       }

       @Override
       public View getView(int position, View convertView, ViewGroup parent) 
       {
          // If we weren't given a view, inflate one
          if (null == convertView) 
          {
           	 convertView = getLayoutInflater().inflate(R.layout.list_item_identities, parent, false);
          }

          // Configure the view for this Address
          Address a = getItem(position);

          mFromAddressSelectionListItemLabelTextView = (TextView)convertView.findViewById(R.id.identities_list_item_options_label_textview);
           
          if (a.getLabel() == null)
          {
        	  mFromAddressSelectionListItemLabelTextView.setText("[No label]");
          }
           
          else
          {
             mFromAddressSelectionListItemLabelTextView.setText(a.getLabel());
          }
           
          mFromAddressSelectionListItemAddressTextView = (TextView)convertView.findViewById(R.id.identities_list_item_options_address_textview);
          mFromAddressSelectionListItemAddressTextView.setText(a.getAddress());
          
          // Set the colours for this view
          int[] colourValues = ColourCalculator.calculateColoursFromAddress(a.getAddress());  
          convertView.setBackgroundColor(Color.argb(COMPOSE_COLOURS_ALPHA_VALUE, colourValues[0], colourValues[1], colourValues[2]));

          int color = Color.argb(0, colourValues[0], colourValues[1], colourValues[2]);
          mFromAddressSelectionListItemLabelTextView.setBackgroundColor(color);
          mFromAddressSelectionListItemAddressTextView.setBackgroundColor(color);

          return convertView;
      }
   }
	
 	@Override
 	public boolean onCreateOptionsMenu(Menu menu) 
 	{
 		// Inflate the menu; this adds items to the action bar if it is present.
 		getMenuInflater().inflate(R.menu.compose_activity_actions, menu);
 		return true;
 	}
     
     @Override
     public boolean onPrepareOptionsMenu(Menu menu)
     {
     	SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
     	if (prefs.getBoolean(KEY_DATABASE_PASSPHRASE_SAVED, false) == false)
 		{
 			menu.removeItem(R.id.menu_item_lock);
 		}
         return super.onPrepareOptionsMenu(menu);
     }
 	
 	@SuppressLint("InlinedApi")
 	@Override
 	public boolean onOptionsItemSelected(MenuItem item) 
 	{
 	    switch(item.getItemId()) 
 	    {
	 	   case R.id.action_send:
	 			sendMessage();
	 			break;
 	    
 	    	case R.id.menu_item_inbox:
 		        Intent intent1 = new Intent(this, InboxActivity.class);
 		        intent1.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
 		        startActivity(intent1);
 		        break;
 		        
 		    case R.id.menu_item_sent:
 		        Intent intent2 = new Intent(this, SentActivity.class);
 		        intent2.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
 		        startActivity(intent2);
 		        break;  
 		        
 		    case R.id.menu_item_compose:
 		    	// We are already here, so there's nothing to do
 		        break;
 		        
 		    case R.id.menu_item_identities:
 		        Intent intent4 = new Intent(this, IdentitiesActivity.class);
 		        intent4.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
 		        startActivity(intent4);
 		        break;
 		        
 		    case R.id.menu_item_addressBook:
 		        Intent intent5 = new Intent(this, AddressBookActivity.class);
 		        intent5.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
 		        startActivity(intent5);
 		        break;
 		        
 		    case R.id.menu_item_settings:
 		        Intent intent6 = new Intent(this, SettingsActivity.class);
 		        intent6.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
 		        startActivity(intent6);
 		        break;
 		        
 		    case R.id.menu_item_lock:
		    	AppLockHandler.runLockRoutine(mCacheWordHandler);
		        break;
 		        
 		    default:
 		        return super.onOptionsItemSelected(item);
 	    }

 	    return true;
 	}
     
     @Override
     protected void onStop()
     {
     	super.onStop();
     	if (mCacheWordHandler != null)
     	{
         	mCacheWordHandler.disconnectFromService();
     	}
      }
 	
 	@SuppressLint("InlinedApi")
 	@Override
 	public void onCacheWordLocked()
 	{
 		// Redirect to the lock screen activity
         Intent intent = new Intent(getBaseContext(), LockScreenActivity.class);
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) // FLAG_ACTIVITY_CLEAR_TASK only exists in API 11 and later 
         {
         	intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);// Clear the stack of activities
         }
         else
         {
         	intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         }
         startActivity(intent);
 	}

 	@Override
 	public void onCacheWordOpened()
 	{
 		// Nothing to do here currently
 	}
 	
 	@Override
 	public void onCacheWordUninitialized()
 	{
 		// Database encryption is currently not enabled by default, so there is nothing to do here
 	}
}