package ca.etsmtl.applets.etsmobile.ui.fragment;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorDescription;
import android.accounts.OnAccountsUpdateListener;
import android.content.ContentProviderOperation;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import com.octo.android.robospice.persistence.exception.SpiceException;

import java.util.ArrayList;
import java.util.Iterator;

import ca.etsmtl.applets.etsmobile2.R;

public class ContactAdderFragment extends HttpFragment implements
		OnAccountsUpdateListener {
	public static final String TAG = "ContactsAdder";
	public static final String ACCOUNT_NAME = "com.example.android.contactmanager.ContactsAdder.ACCOUNT_NAME";
	public static final String ACCOUNT_TYPE = "com.example.android.contactmanager.ContactsAdder.ACCOUNT_TYPE";

	private ArrayList<AccountData> mAccounts;
	private AccountAdapter mAccountAdapter;
	private Spinner mAccountSpinner;
	private EditText mContactEmailEditText;
	private ArrayList<Integer> mContactEmailTypes;
	private Spinner mContactEmailTypeSpinner;
	private EditText mContactNameEditText;
	private EditText mContactPhoneEditText;
	private EditText mContactAddressEditText;
	private ArrayList<Integer> mContactPhoneTypes;
	private Spinner mContactPhoneTypeSpinner;
	private Button mContactSaveButton;
	private AccountData mSelectedAccount;
	private String prenom;
	private String service;
	private String empl;
	private String titre;
	private String courriel;
	private String phone;
	private String nom;

	public static ContactAdderFragment newInstance(Bundle args) {

		ContactAdderFragment fragment = new ContactAdderFragment();
		if (args != null) {

			fragment.setArguments(args);
		}
		return fragment;

	}

	/**
	 * Called when the activity is first created. Responsible for initializing
	 * the UI.
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		if (getArguments() != null) {

			Bundle bundle = getArguments();
			nom = bundle.getString(BottinDetailsFragment.NOM);
			prenom = bundle.getString(BottinDetailsFragment.PRENOM);
			titre = bundle.getString(BottinDetailsFragment.TITRE);
			service = bundle.getString(BottinDetailsFragment.SERVICE);
			empl = bundle.getString(BottinDetailsFragment.EMPLACEMENT);
			phone = bundle.getString(BottinDetailsFragment.TELBUREAU);
			courriel = bundle.getString(BottinDetailsFragment.COURRIEL);

		}
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {

		View v = inflater.inflate(R.layout.contactadder, container, false);

		Log.v(TAG, "Activity State: onCreate()");

		// final Bundle extras = getArguments();
		//
		// nom = BottinDetailsFragment.NOM;
		// prenom = BottinDetailsFragment.PRENOM;
		// service = BottinDetailsFragment.SERVICE;
		// // empl = extras.getString("empl");
		// titre = BottinDetailsFragment.TITRE;
		// courriel = BottinDetailsFragment.COURRIEL;
		// phone = BottinDetailsFragment.TELBUREAU;

		// Obtain handles to UI objects
		mAccountSpinner = (Spinner) v.findViewById(R.id.accountSpinner);

		mContactNameEditText = (EditText) v
				.findViewById(R.id.contactNameEditText);
		System.out.println(prenom);
		mContactNameEditText.setText(prenom + " " + nom);
		mContactPhoneEditText = (EditText) v
				.findViewById(R.id.contactPhoneEditText);
		mContactPhoneEditText.setText(phone);
		mContactEmailEditText = (EditText) v
				.findViewById(R.id.contactEmailEditText);
		mContactEmailEditText.setText(courriel);

		mContactPhoneTypeSpinner = (Spinner) v
				.findViewById(R.id.contactPhoneTypeSpinner);
		mContactEmailTypeSpinner = (Spinner) v
				.findViewById(R.id.contactEmailTypeSpinner);

		mContactAddressEditText = (EditText) v
				.findViewById(R.id.addressEditText);
		mContactAddressEditText.setText(empl);

		mContactSaveButton = (Button) v.findViewById(R.id.contactSaveButton);

		// Prepare list of supported account types
		// Note: Other types are available in ContactsContract.CommonDataKinds
		// Also, be aware that type IDs differ between Phone and Email, and MUST
		// be computed
		// separately.
		mContactPhoneTypes = new ArrayList<Integer>();
		mContactPhoneTypes
				.add(ContactsContract.CommonDataKinds.Phone.TYPE_HOME);
		mContactPhoneTypes
				.add(ContactsContract.CommonDataKinds.Phone.TYPE_WORK);
		mContactPhoneTypes
				.add(ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
		mContactPhoneTypes
				.add(ContactsContract.CommonDataKinds.Phone.TYPE_OTHER);
		mContactEmailTypes = new ArrayList<Integer>();
		mContactEmailTypes
				.add(ContactsContract.CommonDataKinds.Email.TYPE_HOME);
		mContactEmailTypes
				.add(ContactsContract.CommonDataKinds.Email.TYPE_WORK);
		mContactEmailTypes
				.add(ContactsContract.CommonDataKinds.Email.TYPE_MOBILE);
		mContactEmailTypes
				.add(ContactsContract.CommonDataKinds.Email.TYPE_OTHER);

		// Prepare model for account spinner
		mAccounts = new ArrayList<AccountData>();
		mAccountAdapter = new AccountAdapter(getActivity(), mAccounts);
		mAccountSpinner.setAdapter(mAccountAdapter);

		// Populate list of account types for phone
		ArrayAdapter<String> adapter;
		adapter = new ArrayAdapter<String>(getActivity(),
				android.R.layout.simple_spinner_item);
		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		Iterator<Integer> iter;
		iter = mContactPhoneTypes.iterator();
		while (iter.hasNext()) {
			adapter.add(ContactsContract.CommonDataKinds.Phone.getTypeLabel(
					this.getResources(), iter.next(), "undefined").toString());
		}
		mContactPhoneTypeSpinner.setAdapter(adapter);
		mContactPhoneTypeSpinner.setPrompt("select");

		// Populate list of account types for email
		adapter = new ArrayAdapter<String>(getActivity(),
				android.R.layout.simple_spinner_item);
		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		iter = mContactEmailTypes.iterator();
		while (iter.hasNext()) {
			adapter.add(ContactsContract.CommonDataKinds.Email.getTypeLabel(
					this.getResources(), iter.next(), "undefined").toString());
		}
		mContactEmailTypeSpinner.setAdapter(adapter);
		mContactEmailTypeSpinner.setPrompt("select");

		// Prepare the system account manager. On registering the listener
		// below, we also ask for
		// an initial callback to pre-populate the account list.
		AccountManager.get(getActivity()).addOnAccountsUpdatedListener(this,
				null, true);

		// Register handlers for UI elements
		mAccountSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
			@Override
			public void onItemSelected(AdapterView<?> parent, View view,
					int position, long i) {
				updateAccountSelection();
			}

			@Override
			public void onNothingSelected(AdapterView<?> parent) {
				// We don't need to worry about nothing being selected, since
				// Spinners don't allow
				// this.
			}
		});
		mContactSaveButton.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				onSaveButtonClicked();
			}
		});

		return v;
	}

	@Override
	public String getFragmentTitle() {
		return "";
	}

	/**
	 * Actions for when the Save button is clicked. Creates a contact entry and
	 * terminates the activity.
	 */
	private void onSaveButtonClicked() {
		Log.v(TAG, "Save button clicked");
		createContactEntry();
		getActivity().finish();
	}

	/**
	 * Creates a contact entry from the current UI values in the account named
	 * by mSelectedAccount.
	 */
	protected void createContactEntry() {
		// Get values from UI
		final String name = mContactNameEditText.getText().toString();
		final String phone = mContactPhoneEditText.getText().toString();
		final String email = mContactEmailEditText.getText().toString();
		final int phoneType = mContactPhoneTypes.get(mContactPhoneTypeSpinner
				.getSelectedItemPosition());
		final int emailType = mContactEmailTypes.get(mContactEmailTypeSpinner
				.getSelectedItemPosition());

		// Prepare contact creation request
		//
		// Note: We use RawContacts because this data must be associated with a
		// particular account.
		// The system will aggregate this with any other data for this contact
		// and create a
		// coresponding entry in the ContactsContract.Contacts provider for us.
		final ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
		ops.add(ContentProviderOperation
				.newInsert(ContactsContract.RawContacts.CONTENT_URI)
				.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE,
						mSelectedAccount.getType())
				.withValue(ContactsContract.RawContacts.ACCOUNT_NAME,
						mSelectedAccount.getName()).build());
		ops.add(ContentProviderOperation
				.newInsert(ContactsContract.Data.CONTENT_URI)
				.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
				.withValue(
						ContactsContract.Data.MIMETYPE,
						ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
				.withValue(
						ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
						name)
				// .withValue(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME,name)
				// .withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME,prenom)
				.build());
		ops.add(ContentProviderOperation
				.newInsert(ContactsContract.Data.CONTENT_URI)
				.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
				.withValue(
						ContactsContract.Data.MIMETYPE,
						ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
				.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
				.withValue(ContactsContract.CommonDataKinds.Phone.TYPE,
						phoneType).build());
		ops.add(ContentProviderOperation
				.newInsert(ContactsContract.Data.CONTENT_URI)
				.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
				.withValue(
						ContactsContract.Data.MIMETYPE,
						ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
				.withValue(ContactsContract.CommonDataKinds.Email.DATA, email)
				.withValue(ContactsContract.CommonDataKinds.Email.TYPE,
						emailType).build());
		ops.add(ContentProviderOperation
				.newInsert(ContactsContract.Data.CONTENT_URI)
				.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
				.withValue(
						ContactsContract.Data.MIMETYPE,
						ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE)
				.withValue(
						ContactsContract.CommonDataKinds.Organization.COMPANY,
						"École de technologie supérieure")
				.withValue(
						ContactsContract.CommonDataKinds.Organization.DEPARTMENT,
						service)
				.withValue(ContactsContract.CommonDataKinds.Organization.TITLE,
						titre).build());
		ops.add(ContentProviderOperation
				.newInsert(ContactsContract.Data.CONTENT_URI)
				.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
				.withValue(
						ContactsContract.Data.MIMETYPE,
						ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE)
				.withValue(
						ContactsContract.CommonDataKinds.StructuredPostal.DATA,
						empl).build());

		// Ask the Contact provider to create a new contact
		Log.i(TAG, "Selected account: " + mSelectedAccount.getName() + " ("
				+ mSelectedAccount.getType() + ")");
		Log.i(TAG, "Creating contact: " + name);
		try {
			getActivity().getContentResolver().applyBatch(
					ContactsContract.AUTHORITY, ops);
		} catch (final Exception e) {
			// Display warning
			final Context ctx = getActivity();
			final CharSequence txt = getString(R.string.contact_creation_failed);
			final int duration = Toast.LENGTH_SHORT;
			final Toast toast = Toast.makeText(ctx, txt, duration);
			toast.show();

			// Log exception
			Log.e(TAG, "Exceptoin encoutered while inserting contact: " + e);
		}
	}

	/**
	 * Called when this activity is about to be destroyed by the system.
	 */
	@Override
	public void onDestroy() {
		// Remove AccountManager callback
		AccountManager.get(getActivity()).removeOnAccountsUpdatedListener(this);
		super.onDestroy();
	}

	/**
	 * Updates account list spinner when the list of Accounts on the system
	 * changes. Satisfies OnAccountsUpdateListener implementation.
	 */
	@Override
	public void onAccountsUpdated(Account[] a) {
		Log.i(TAG, "Account list update detected");
		// Clear out any old data to prevent duplicates
		mAccounts.clear();

		// Get account data from system
		final AuthenticatorDescription[] accountTypes = AccountManager.get(
				getActivity()).getAuthenticatorTypes();

		// Populate tables
		for (final Account element : a) {
			// The user may have multiple accounts with the same name, so we
			// need to construct a
			// meaningful display name for each.
			final String systemAccountType = element.type;
			final AuthenticatorDescription ad = getAuthenticatorDescription(
					systemAccountType, accountTypes);
			final AccountData data = new AccountData(element.name, ad);
			mAccounts.add(data);
		}

		// Update the account spinner
		mAccountAdapter.notifyDataSetChanged();
	}

	/**
	 * Obtain the AuthenticatorDescription for a given account type.
	 * 
	 * @param type
	 *            The account type to locate.
	 * @param dictionary
	 *            An array of AuthenticatorDescriptions, as returned by
	 *            AccountManager.
	 * @return The description for the specified account type.
	 */
	private static AuthenticatorDescription getAuthenticatorDescription(
			String type, AuthenticatorDescription[] dictionary) {
		for (final AuthenticatorDescription element : dictionary) {
			if (element.type.equals(type)) {
				return element;
			}
		}
		// No match found
		throw new RuntimeException("Unable to find matching authenticator");
	}

	/**
	 * Update account selection. If NO_ACCOUNT is selected, then we prohibit
	 * inserting new contacts.
	 */
	private void updateAccountSelection() {
		// Read current account selection
		mSelectedAccount = (AccountData) mAccountSpinner.getSelectedItem();
	}

	/**
	 * A container class used to repreresent all known information about an
	 * account.
	 */
	private class AccountData {
		private final String mName;
		private String mType;
		private CharSequence mTypeLabel;
		private Drawable mIcon;

		/**
		 * @param name
		 *            The name of the account. This is usually the user's email
		 *            address or username.
		 * @param description
		 *            The description for this account. This will be dictated by
		 *            the type of account returned, and can be obtained from the
		 *            system AccountManager.
		 */
		public AccountData(String name, AuthenticatorDescription description) {
			mName = name;
			if (description != null) {
				mType = description.type;

				// The type string is stored in a resource, so we need to
				// convert it into something
				// human readable.
				final String packageName = description.packageName;
				final PackageManager pm = getActivity().getPackageManager();

				if (description.labelId != 0) {
					mTypeLabel = pm.getText(packageName, description.labelId,
							null);
					if (mTypeLabel == null) {
						throw new IllegalArgumentException(
								"LabelID provided, but label not found");
					}
				} else {
					mTypeLabel = "";
				}

				if (description.iconId != 0) {
					mIcon = pm.getDrawable(packageName, description.iconId,
							null);
					if (mIcon == null) {
						throw new IllegalArgumentException(
								"IconID provided, but drawable not " + "found");
					}
				} else {
					mIcon = getResources().getDrawable(
							android.R.drawable.sym_def_app_icon);
				}
			}
		}

		public String getName() {
			return mName;
		}

		public String getType() {
			return mType;
		}

		public CharSequence getTypeLabel() {
			return mTypeLabel;
		}

		public Drawable getIcon() {
			return mIcon;
		}

		@Override
		public String toString() {
			return mName;
		}
	}

	/**
	 * Custom adapter used to display account icons and descriptions in the
	 * account spinner.
	 */
	private class AccountAdapter extends ArrayAdapter<AccountData> {
		public AccountAdapter(Context context,
				ArrayList<AccountData> accountData) {
			super(context, android.R.layout.simple_spinner_item, accountData);
			setDropDownViewResource(R.layout.account_entry);
		}

		@Override
		public View getDropDownView(int position, View convertView,
				ViewGroup parent) {
			// Inflate a view template
			if (convertView == null) {
				final LayoutInflater layoutInflater = getActivity()
						.getLayoutInflater();
				convertView = layoutInflater.inflate(R.layout.account_entry,
						parent, false);
			}
			final TextView firstAccountLine = (TextView) convertView
					.findViewById(R.id.firstAccountLine);
			final TextView secondAccountLine = (TextView) convertView
					.findViewById(R.id.secondAccountLine);
			final ImageView accountIcon = (ImageView) convertView
					.findViewById(R.id.accountIcon);

			// Populate template
			final AccountData data = getItem(position);
			firstAccountLine.setText(data.getName());
			secondAccountLine.setText(data.getTypeLabel());
			Drawable icon = data.getIcon();
			if (icon == null) {
				icon = getResources().getDrawable(
						android.R.drawable.ic_menu_search);
			}
			accountIcon.setImageDrawable(icon);
			return convertView;
		}
	}

	@Override
	public void onRequestFailure(SpiceException arg0) {
	}

	@Override
	public void onRequestSuccess(Object arg0) {
	}

	@Override
	void updateUI() {
	}
}