/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.

  Keepass2Android is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 2 of the License, or
  (at your option) any later version.

  Keepass2Android is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with Keepass2Android.  If not, see <http://www.gnu.org/licenses/>.
  */

using System;
using System.Collections.Generic;
using System.Linq;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Views;
using Android.Widget;
using Android.Preferences;
using KeePassLib.Utility;
using KeePassLib;
using Android.Text;
using KeePassLib.Security;
using Android.Content.PM;
using System.IO;
using System.Globalization;

namespace keepass2android
{
	[Activity (Label = "@string/app_name", ConfigurationChanges=ConfigChanges.Orientation|ConfigChanges.KeyboardHidden, Theme="@style/NoTitleBar")]			
	public class EntryEditActivity : LockCloseActivity {
		public const String KeyEntry = "entry";
		public const String KeyParent = "parent";
		
		public const int ResultOkIconPicker = (int)Result.FirstUser + 1000;
		public const int ResultOkPasswordGenerator = ResultOkIconPicker + 1;

		const string IntentContinueWithEditing = "ContinueWithEditing";

		EntryEditActivityState State
		{
			get { return App.Kp2a.EntryEditActivityState; }
		}

		public static void Launch(Activity act, PwEntry pw, AppTask appTask) {
			Intent i = new Intent(act, typeof(EntryEditActivity));
			
			i.PutExtra(KeyEntry, pw.Uuid.ToHexString());
			
			appTask.ToIntent(i);

			act.StartActivityForResult(i, 0);
		}
		
		public static void Launch(Activity act, PwGroup pw, AppTask appTask) {
			Intent i = new Intent(act, typeof(EntryEditActivity));
			
			PwGroup parent = pw;
			i.PutExtra(KeyParent, parent.Uuid.ToHexString());

			appTask.ToIntent(i);

			act.StartActivityForResult(i, 0);
		}

		bool _closeForReload;

		AppTask _appTask;
		
		protected override void OnCreate(Bundle savedInstanceState)
		{
			base.OnCreate(savedInstanceState);

			if (LastNonConfigurationInstance != null)
			{
				//bug in Mono for Android or whatever: after config change the extra fields are wrong
				// -> reload:
				Reload();
				return;
			}

			_appTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);

			SetContentView(Resource.Layout.entry_edit);
			_closeForReload = false;

			// Likely the app has been killed exit the activity
			if (!App.Kp2a.DatabaseIsUnlocked)
			{
				Finish();
				return;
			}


			if (Intent.GetBooleanExtra(IntentContinueWithEditing, false))
			{
				//property "State" will return the state


			} else
			{
				Database db = App.Kp2a.GetDb();

				App.Kp2a.EntryEditActivityState = new EntryEditActivityState();
				ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this);
				State.ShowPassword = ! prefs.GetBoolean(GetString(Resource.String.maskpass_key), Resources.GetBoolean(Resource.Boolean.maskpass_default));
			
				Intent i = Intent;
				String uuidBytes = i.GetStringExtra(KeyEntry);
				
				PwUuid entryId = PwUuid.Zero;
				if (uuidBytes != null)
					entryId = new PwUuid(MemUtil.HexStringToByteArray(uuidBytes));
				
				State.ParentGroup = null;
				if (entryId.EqualsValue(PwUuid.Zero))
				{
					String groupId = i.GetStringExtra(KeyParent);
					State.ParentGroup = db.KpDatabase.RootGroup.FindGroup(new PwUuid(MemUtil.HexStringToByteArray(groupId)), true);
					
					State.EntryInDatabase = new PwEntry(true, true);
					State.EntryInDatabase.Strings.Set(PwDefs.UserNameField, new ProtectedString(
						db.KpDatabase.MemoryProtection.ProtectUserName, db.KpDatabase.DefaultUserName));
					
					/*KPDesktop
				 * ProtectedString psAutoGen;
			PwGenerator.Generate(out psAutoGen, Program.Config.PasswordGenerator.AutoGeneratedPasswordsProfile,
				null, Program.PwGeneratorPool);
			psAutoGen = psAutoGen.WithProtection(pwDb.MemoryProtection.ProtectPassword);
			pwe.Strings.Set(PwDefs.PasswordField, psAutoGen);

			int nExpireDays = Program.Config.Defaults.NewEntryExpiresInDays;
			if(nExpireDays >= 0)
			{
				pwe.Expires = true;
				pwe.ExpiryTime = DateTime.Now.AddDays(nExpireDays);
			}*/
					
					if ((State.ParentGroup.IconId != PwIcon.Folder) && (State.ParentGroup.IconId != PwIcon.FolderOpen) &&
					    (State.ParentGroup.IconId != PwIcon.FolderPackage))
					{
						State.EntryInDatabase.IconId = State.ParentGroup.IconId; // Inherit icon from group
					}
					State.EntryInDatabase.CustomIconUuid = State.ParentGroup.CustomIconUuid;
					
					/*
				 * KPDesktop
			if(strDefaultSeq.Length == 0)
			{
				PwGroup pg = m_pwEntry.ParentGroup;
				if(pg != null)
				{
					strDefaultSeq = pg.GetAutoTypeSequenceInherited();

					if(strDefaultSeq.Length == 0)
					{
						if(PwDefs.IsTanEntry(m_pwEntry))
							strDefaultSeq = PwDefs.DefaultAutoTypeSequenceTan;
						else
							strDefaultSeq = PwDefs.DefaultAutoTypeSequence;
					}
				}
			}*/
					_appTask.PrepareNewEntry(State.EntryInDatabase);
					State.IsNew = true;
					State.EntryModified = true;
					
				} else
				{
					
					System.Diagnostics.Debug.Assert(entryId != null);
					
					State.EntryInDatabase = db.Entries [entryId];
					State.IsNew = false;
					
					
				} 
				
				State.Entry = State.EntryInDatabase.CloneDeep();

			}
		
			if (!State.EntryModified)
			    SetResult(KeePass.ExitNormal);
			else
				SetResult(KeePass.ExitRefreshTitle);


			FillData();
			View scrollView = FindViewById(Resource.Id.entry_scroll);
			scrollView.ScrollBarStyle = ScrollbarStyles.InsideInset;
			
			ImageButton iconButton = (ImageButton)FindViewById(Resource.Id.icon_button);
			
			if (State.SelectedIcon)
			{
				//TODO: custom image
				iconButton.SetImageResource(Icons.IconToResId(State.SelectedIconId));
			}
			iconButton.Click += (sender, evt) => {
				UpdateEntryFromUi(State.Entry);
				IconPickerActivity.Launch(this);
			};
		

			// Generate password button
			Button generatePassword = (Button)FindViewById(Resource.Id.generate_button);
			generatePassword.Click += (sender, e) => {
				UpdateEntryFromUi(State.Entry);
				GeneratePasswordActivity.Launch(this);
			};




			// Save button
			View save = FindViewById(Resource.Id.entry_save);
			if (save == null)
			{
				//save is not part of layout for API >= 14 -> use action bar
				ActionBar.SetCustomView(Resource.Layout.SaveButton);
				ActionBar.SetDisplayShowCustomEnabled(true);
				ActionBar.SetDisplayShowTitleEnabled(false);  
				ActionBar.SetDisplayUseLogoEnabled(false);
				ActionBar.SetDisplayShowHomeEnabled(false);
				ActionBar.SetDisplayOptions(ActionBarDisplayOptions.ShowCustom,
				                            ActionBarDisplayOptions.ShowCustom);
				save = FindViewById(Resource.Id.entry_save);

			}
			save.Click += (sender, e) => 
			{
				SaveEntry();

			};
		
			// Respect mask password setting
			if (State.ShowPassword) {
				EditText pass = (EditText) FindViewById(Resource.Id.entry_password);
				EditText conf = (EditText) FindViewById(Resource.Id.entry_confpassword);
				
				pass.InputType = InputTypes.ClassText | InputTypes.TextVariationVisiblePassword;
				conf.InputType = InputTypes.ClassText | InputTypes.TextVariationVisiblePassword;
			}

			Button addButton = (Button) FindViewById(Resource.Id.add_advanced);
			addButton.Visibility = ViewStates.Visible;
			addButton.Click += (sender, e) =>
			{
				LinearLayout container = (LinearLayout) FindViewById(Resource.Id.advanced_container);

				KeyValuePair<string, ProtectedString> pair = new KeyValuePair<string, ProtectedString>("" , new ProtectedString(true, ""));
				LinearLayout ees = CreateExtraStringView(pair);
				container.AddView(ees);

				State.EntryModified = true;

				TextView keyView = (TextView) ees.FindViewById(Resource.Id.title);
				keyView.RequestFocus();

					
			};
		
			((CheckBox)FindViewById(Resource.Id.entry_expires_checkbox)).CheckedChange += (sender, e) => 
			{
				State.Entry.Expires = e.IsChecked;
				if (e.IsChecked)
				{
					if (State.Entry.ExpiryTime < DateTime.Now)
						State.Entry.ExpiryTime = DateTime.Now;
				}
				UpdateExpires();
				State.EntryModified = true;
			};


		}

		void SaveEntry()
		{
			Database db = App.Kp2a.GetDb();
			EntryEditActivity act = this;
			
			if (!ValidateBeforeSaving())
				return;
			
			PwEntry initialEntry = State.EntryInDatabase.CloneDeep();
			
			PwEntry newEntry = State.EntryInDatabase;
			
			//Clone history and re-assign:
			newEntry.History = newEntry.History.CloneDeep();
			
			//Based on KeePass Desktop
			bool bCreateBackup = (!State.IsNew);
			if(bCreateBackup) newEntry.CreateBackup(null);
			
			if (State.SelectedIcon == false) {
				if (State.IsNew) {
					newEntry.IconId = PwIcon.Key;
				} else {
					// Keep previous icon, if no new one was selected
				}
			}
			else {
				newEntry.IconId = State.SelectedIconId;
				newEntry.CustomIconUuid = State.SelectedCustomIconId;
			}
			/* KPDesktop
				if(m_cbCustomForegroundColor.Checked)
					newEntry.ForegroundColor = m_clrForeground;
				else newEntry.ForegroundColor = Color.Empty;
				if(m_cbCustomBackgroundColor.Checked)
					newEntry.BackgroundColor = m_clrBackground;
				else newEntry.BackgroundColor = Color.Empty;
				
				*/
			
			UpdateEntryFromUi(newEntry);
			newEntry.Binaries = State.Entry.Binaries;
			newEntry.Expires = State.Entry.Expires;
			if (newEntry.Expires)
			{
				newEntry.ExpiryTime = State.Entry.ExpiryTime;
			}

			
			newEntry.Touch(true, false); // Touch *after* backup
			
			StrUtil.NormalizeNewLines(newEntry.Strings, true);
			
			bool bUndoBackup = false;
			PwCompareOptions cmpOpt =  (PwCompareOptions.NullEmptyEquivStd |
			                            PwCompareOptions.IgnoreTimes);
			if(bCreateBackup) cmpOpt |= PwCompareOptions.IgnoreLastBackup;
			if(newEntry.EqualsEntry(initialEntry, cmpOpt, MemProtCmpMode.CustomOnly))
			{
				// No modifications at all => restore last mod time and undo backup
				newEntry.LastModificationTime = initialEntry.LastModificationTime;
				bUndoBackup = bCreateBackup;
			}
			else if(bCreateBackup)
			{
				// If only history items have been modified (deleted) => undo
				// backup, but without restoring the last mod time
				PwCompareOptions cmpOptNh = (cmpOpt | PwCompareOptions.IgnoreHistory);
				if(newEntry.EqualsEntry(initialEntry, cmpOptNh, MemProtCmpMode.CustomOnly))
					bUndoBackup = true;
			}
			if(bUndoBackup) newEntry.History.RemoveAt(newEntry.History.UCount - 1);
			
			newEntry.MaintainBackups(db.KpDatabase);

			//if ( newEntry.Strings.ReadSafe (PwDefs.TitleField).Equals(State.Entry.Strings.ReadSafe (PwDefs.TitleField)) ) {
			//	SetResult(KeePass.EXIT_REFRESH);
			//} else {
			//it's safer to always update the title as we might add further information in the title like expiry etc.
			SetResult(KeePass.ExitRefreshTitle);
			//}
			
			RunnableOnFinish runnable;

			ActionOnFinish closeOrShowError = new ActionOnFinish((success, message) => {
				if (success)
				{
					Finish();
				} else
				{
					OnFinish.DisplayMessage(this, message);
				}
			});

			ActionOnFinish afterAddEntry = new ActionOnFinish((success, message) => 
			{
				if (success)
					_appTask.AfterAddNewEntry(this, newEntry);
			},closeOrShowError);

			if ( State.IsNew ) {
				runnable = AddEntry.GetInstance(this, App.Kp2a, newEntry, State.ParentGroup, afterAddEntry);
			} else {
				runnable = new UpdateEntry(this, App.Kp2a, initialEntry, newEntry, closeOrShowError);
			}
            ProgressTask pt = new ProgressTask(App.Kp2a, act, runnable);
			pt.Run();
			

		}

		void UpdateEntryFromUi(PwEntry entry)
		{
			Database db = App.Kp2a.GetDb();
			EntryEditActivity act = this;

			entry.Strings.Set(PwDefs.TitleField, new ProtectedString(db.KpDatabase.MemoryProtection.ProtectTitle,
			                                                            Util.GetEditText(act, Resource.Id.entry_title)));
			entry.Strings.Set(PwDefs.UserNameField, new ProtectedString(db.KpDatabase.MemoryProtection.ProtectUserName,
			                                                               Util.GetEditText(act, Resource.Id.entry_user_name)));
			
			String pass = Util.GetEditText(act, Resource.Id.entry_password);
			byte[] password = StrUtil.Utf8.GetBytes(pass);
			entry.Strings.Set(PwDefs.PasswordField, new ProtectedString(db.KpDatabase.MemoryProtection.ProtectPassword,
			                                                               password));
			MemUtil.ZeroByteArray(password);
			
			entry.Strings.Set(PwDefs.UrlField, new ProtectedString(db.KpDatabase.MemoryProtection.ProtectUrl,
			                                                          Util.GetEditText(act, Resource.Id.entry_url)));
			entry.Strings.Set(PwDefs.NotesField, new ProtectedString(db.KpDatabase.MemoryProtection.ProtectNotes,
			                                                            Util.GetEditText(act, Resource.Id.entry_comment)));
		
			// Validate expiry date
			DateTime newExpiry = new DateTime();
			if ((State.Entry.Expires) && (!DateTime.TryParse( Util.GetEditText(this,Resource.Id.entry_expires), out newExpiry)))
			{
				//ignore here
			}
			else
			{
				State.Entry.ExpiryTime = newExpiry;
			}

			// Delete all non standard strings
			var keys = entry.Strings.GetKeys();
			foreach (String key in keys)
				if (PwDefs.IsStandardField(key) == false)
					entry.Strings.Remove(key);
			
			LinearLayout container = (LinearLayout) FindViewById(Resource.Id.advanced_container);
			
			for (int index = 0; index < container.ChildCount; index++) {
				View view = container.GetChildAt(index);
				
				TextView keyView = (TextView)view.FindViewById(Resource.Id.title);
				String key = keyView.Text;

				if (String.IsNullOrEmpty(key))
					continue;
				
				TextView valueView = (TextView)view.FindViewById(Resource.Id.value);
				String value = valueView.Text;


				bool protect = ((CheckBox) view.FindViewById(Resource.Id.protection)).Checked;
				entry.Strings.Set(key, new ProtectedString(protect, value));
			}
			

			entry.OverrideUrl = Util.GetEditText(this,Resource.Id.entry_override_url);
			
			List<string> vNewTags = StrUtil.StringToTags(Util.GetEditText(this,Resource.Id.entry_tags));
			entry.Tags.Clear();
			foreach(string strTag in vNewTags) entry.AddTag(strTag);
			
			/*KPDesktop


				m_atConfig.Enabled = m_cbAutoTypeEnabled.Checked;
				m_atConfig.ObfuscationOptions = (m_cbAutoTypeObfuscation.Checked ?
				                                 AutoTypeObfuscationOptions.UseClipboard :
				                                 AutoTypeObfuscationOptions.None);

				SaveDefaultSeq();
				
				newEntry.AutoType = m_atConfig;
				*/

		}

		void AddBinaryOrAsk(string filename)
		{
			string strItem = UrlUtil.GetFileName(filename);

			if(State.Entry.Binaries.Get(strItem) != null)
			{
				AlertDialog.Builder builder = new AlertDialog.Builder(this);
				builder.SetTitle(GetString(Resource.String.AskOverwriteBinary_title));

				builder.SetMessage(GetString(Resource.String.AskOverwriteBinary));

				builder.SetPositiveButton(GetString(Resource.String.AskOverwriteBinary_yes), (dlgSender, dlgEvt) => 
				                                                                                                         {
						AddBinary(filename, true);
					});

				builder.SetNegativeButton(GetString(Resource.String.AskOverwriteBinary_no), (dlgSender, dlgEvt) => 
				                                                                                                         {
						AddBinary(filename, false);
					});

				builder.SetNeutralButton(GetString(Android.Resource.String.Cancel), 
				                         (dlgSender, dlgEvt) => {});

				Dialog dialog = builder.Create();
				dialog.Show();


			} else
				AddBinary(filename, true);
		}

		void AddBinary(string filename, bool overwrite)
		{
			string strItem = UrlUtil.GetFileName(filename);

			if (!overwrite)
			{
				string strFileName = UrlUtil.StripExtension(strItem);
				string strExtension = "." + UrlUtil.GetExtension(strItem);
				
				int nTry = 0;
				while(true)
				{
					string strNewName = strFileName + nTry.ToString(CultureInfo.InvariantCulture) + strExtension;
					if(State.Entry.Binaries.Get(strNewName) == null)
					{
						strItem = strNewName;
						break;
					}
					
					++nTry;
				}
			}
			try
			{
				byte[] vBytes = File.ReadAllBytes(filename);
					ProtectedBinary pb = new ProtectedBinary(false, vBytes);
				State.Entry.Binaries.Set(strItem, pb);
				}
			catch(Exception exAttach)
			{
				Toast.MakeText(this, GetString(Resource.String.AttachFailed)+" "+exAttach.Message, ToastLength.Long).Show();
			}
			State.EntryModified = true;
			PopulateBinaries();
		}

		protected override void OnSaveInstanceState(Bundle outState)
		{
			base.OnSaveInstanceState(outState);
			_appTask.ToBundle(outState);
		}

		public override void OnBackPressed()
		{
			if (State.EntryModified == false)
			{
				base.OnBackPressed();
			} else
			{
				AlertDialog.Builder builder = new AlertDialog.Builder(this);
				builder.SetTitle(GetString(Resource.String.AskDiscardChanges_title));
				
				builder.SetMessage(GetString(Resource.String.AskDiscardChanges));
				
				builder.SetPositiveButton(GetString(Android.Resource.String.Yes), (dlgSender, dlgEvt) => 
				                                                                                                                  {
					Finish();
					
					});
				
				builder.SetNegativeButton(GetString(Android.Resource.String.No), (dlgSender, dlgEvt) => 
				                                                                                                                 {
					
					});
				
				
				Dialog dialog = builder.Create();
				dialog.Show();
			}

		}

		public void Reload() {
			//this reload ìs necessary to overcome a strange problem with the extra string fields which get lost
			//somehow after re-creating the activity. Maybe a Mono for Android bug?
			Intent intent = Intent;
			intent.PutExtra(IntentContinueWithEditing, true);
			OverridePendingTransition(0, 0);
			intent.AddFlags(ActivityFlags.NoAnimation);
			_closeForReload = true;
			SetResult(KeePass.ExitRefreshTitle); //probably the entry will be modified -> let the EditActivity refresh to be safe
			Finish();
			
			OverridePendingTransition(0, 0);
			StartActivity(intent);
		}
		
		protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
		{
			switch ((int)resultCode)
			{
			case ResultOkIconPicker:
				State.SelectedIconId = (PwIcon) data.Extras.GetInt(IconPickerActivity.KeyIconId);
				State.SelectedCustomIconId = PwUuid.Zero;
				String customIconIdString = data.Extras.GetString(IconPickerActivity.KeyCustomIconId);
				if (!String.IsNullOrEmpty(customIconIdString))
					State.SelectedCustomIconId = new PwUuid(MemUtil.HexStringToByteArray(customIconIdString));
				State.SelectedIcon = true;
				State.EntryModified = true;
				Reload();
				break;
				
			case ResultOkPasswordGenerator:
				String generatedPassword = data.GetStringExtra("keepass2android.password.generated_password");
				
				byte[] password = StrUtil.Utf8.GetBytes(generatedPassword);
				State.Entry.Strings.Set(PwDefs.PasswordField, new ProtectedString(App.Kp2a.GetDb().KpDatabase.MemoryProtection.ProtectPassword,
			                                                            password));
				MemUtil.ZeroByteArray(password);

				State.EntryModified = true;
				Reload();
				break;
			case (int)Result.Ok:
					if (requestCode == Intents.RequestCodeFileBrowseForBinary)
					{
						string filename = Util.IntentToFilename(data);
						if (filename != null) {
							if (filename.StartsWith("file://")) {
								filename = filename.Substring(7);
							}
							
							filename = Java.Net.URLDecoder.Decode(filename);
							AddBinaryOrAsk(filename);
						}
					}
					Reload();


				break;
			case (int)Result.Canceled:
				Reload();
				break;
			}
		}

		void PopulateBinaries()
		{
			ViewGroup binariesGroup = (ViewGroup)FindViewById(Resource.Id.binaries);
			binariesGroup.RemoveAllViews();
			RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
			foreach (KeyValuePair<string, ProtectedBinary> pair in State.Entry.Binaries.OrderBy(p => p.Key) )
			{
				String key = pair.Key;
				Button binaryButton = new Button(this) {Text = key};

				binaryButton.SetCompoundDrawablesWithIntrinsicBounds( Resources.GetDrawable(Android.Resource.Drawable.IcMenuDelete),null, null, null);
				binaryButton.Click += (sender, e) => 
				{
					State.EntryModified = true;
					State.Entry.Binaries.Remove(key);
					PopulateBinaries();

				};
				binariesGroup.AddView(binaryButton,layoutParams);
				
				
			}

			Button addBinaryButton = new Button(this) {Text = GetString(Resource.String.add_binary)};
			addBinaryButton.SetCompoundDrawablesWithIntrinsicBounds( Resources.GetDrawable(Android.Resource.Drawable.IcMenuAdd) , null, null, null);
			addBinaryButton.Click += (sender, e) => 
			{
				Util.showBrowseDialog("/mnt/sdcard", this, Intents.RequestCodeFileBrowseForBinary, false);

			};
			binariesGroup.AddView(addBinaryButton,layoutParams);

			var binariesLabel = FindViewById(Resource.Id.entry_binaries_label);
			if (binariesLabel != null)
				binariesLabel.Visibility = State.Entry.Binaries.UCount > 0 ? ViewStates.Visible : ViewStates.Gone;
		}
		public override bool OnCreateOptionsMenu(IMenu menu) {
			base.OnCreateOptionsMenu(menu);
			
			MenuInflater inflater = MenuInflater;
			inflater.Inflate(Resource.Menu.entry_edit, menu);
			
			
			IMenuItem togglePassword = menu.FindItem(Resource.Id.menu_toggle_pass);
			if ( State.ShowPassword ) {
				togglePassword.SetTitle(Resource.String.menu_hide_password);
			} else {
				togglePassword.SetTitle(Resource.String.show_password);
			}
			
			return true;
		}
		
		public override bool OnOptionsItemSelected(IMenuItem item) {
			switch ( item.ItemId ) {
			case Resource.Id.menu_donate:
				try {
						Util.gotoDonateUrl(this);
				} catch (ActivityNotFoundException) {
					Toast.MakeText(this, Resource.String.error_failed_to_launch_link, ToastLength.Long).Show();
					return false;
				}
				
				return true;
			case Resource.Id.menu_toggle_pass:
					if ( State.ShowPassword ) {
					item.SetTitle(Resource.String.show_password);
						State.ShowPassword = false;
				} else {
					item.SetTitle(Resource.String.menu_hide_password);
						State.ShowPassword = true;
				}
				SetPasswordStyle();
				return true;
			case Resource.Id.menu_cancel_edit:
				Finish();
				break;
			case Resource.Id.menu_rate:
				try {
					Util.gotoMarket(this);
				} catch (ActivityNotFoundException) {
					Toast.MakeText(this, Resource.String.no_url_handler, ToastLength.Long).Show();
				}
				return true;
			case Resource.Id.menu_suggest_improvements:
				try {
					Util.gotoUrl(this, Resource.String.SuggestionsURL);
				} catch (ActivityNotFoundException) {
					Toast.MakeText(this, Resource.String.no_url_handler, ToastLength.Long).Show();
				}
				return true;
			case Resource.Id.menu_translate:
				try {
					Util.gotoUrl(this, Resource.String.TranslationURL);
				} catch (ActivityNotFoundException) {
					Toast.MakeText(this, Resource.String.no_url_handler, ToastLength.Long).Show();
				}
				return true;

			}


			
			return base.OnOptionsItemSelected(item);
		}
		
		private void SetPasswordStyle() {
			TextView password = (TextView) FindViewById(Resource.Id.entry_password);
			TextView confpassword = (TextView) FindViewById(Resource.Id.entry_confpassword);
			
			if ( State.ShowPassword ) {
				password.InputType = InputTypes.ClassText | InputTypes.TextVariationVisiblePassword;
				confpassword.InputType = InputTypes.ClassText | InputTypes.TextVariationVisiblePassword;
				
			} else {
				password.InputType = InputTypes.ClassText | InputTypes.TextVariationPassword;
				confpassword.InputType = InputTypes.ClassText | InputTypes.TextVariationPassword;
			}
		}

		void UpdateExpires()
		{
			if (State.Entry.Expires)
			{
				PopulateText(Resource.Id.entry_expires, getDateTime(State.Entry.ExpiryTime));
			}
			else
			{
				PopulateText(Resource.Id.entry_expires, GetString(Resource.String.never));
			}
			((CheckBox)FindViewById(Resource.Id.entry_expires_checkbox)).Checked = State.Entry.Expires;
			FindViewById(Resource.Id.entry_expires).Enabled = State.Entry.Expires;
		}

		public override Java.Lang.Object OnRetainNonConfigurationInstance()
		{
			UpdateEntryFromUi(State.Entry);
			return this;
		}

		LinearLayout CreateExtraStringView(KeyValuePair<string, ProtectedString> pair)
		{
			LinearLayout ees = (LinearLayout)LayoutInflater.Inflate(Resource.Layout.entry_edit_section, null);
			((TextView)ees.FindViewById(Resource.Id.title)).Text = pair.Key;
			((TextView)ees.FindViewById(Resource.Id.title)).TextChanged += (sender, e) => State.EntryModified = true;
			((TextView)ees.FindViewById(Resource.Id.value)).Text = pair.Value.ReadString();
			((TextView)ees.FindViewById(Resource.Id.value)).TextChanged += (sender, e) => State.EntryModified = true;

			((CheckBox)ees.FindViewById(Resource.Id.protection)).Checked = pair.Value.IsProtected;
			
			//ees.FindViewById(Resource.Id.edit_extra).Click += (sender, e) => DeleteAdvancedString((View)sender);
			ees.FindViewById(Resource.Id.edit_extra).Click += (sender, e) => EditAdvancedString((View)sender);
			return ees;
		}

		private void EditAdvancedString(View sender)
		{
			AlertDialog.Builder builder = new AlertDialog.Builder(this);
			View dlgView = LayoutInflater.Inflate(Resource.Layout.edit_extra_string_dialog, null);
			builder.SetView(dlgView);
			builder.SetNegativeButton(Android.Resource.String.Cancel, (o, args) => { });
			builder.SetPositiveButton(Android.Resource.String.Ok, (o, args) =>
				{
					CopyFieldFromExtraDialog(sender, o, Resource.Id.title);
					CopyFieldFromExtraDialog(sender, o, Resource.Id.value);
					CopyCheckboxFromExtraDialog(sender, o, Resource.Id.protection);
				});
			Dialog dialog = builder.Create();

			//setup delete button:
			var deleteButton = dlgView.FindViewById<Button>(Resource.Id.delete_extra);
			deleteButton.SetCompoundDrawablesWithIntrinsicBounds(Resources.GetDrawable(Android.Resource.Drawable.IcMenuDelete), null, null, null);
			deleteButton.Click += (o, args) =>
				{
					DeleteAdvancedString(sender);
					dialog.Dismiss();
				};
			//copy values:
			View ees = (View) sender.Parent;
			dlgView.FindViewById<EditText>(Resource.Id.title).Text = ees.FindViewById<EditText>(Resource.Id.title).Text;
			dlgView.FindViewById<EditText>(Resource.Id.value).Text = ees.FindViewById<EditText>(Resource.Id.value).Text;
			dlgView.FindViewById<CheckBox>(Resource.Id.protection).Checked = ees.FindViewById<CheckBox>(Resource.Id.protection).Checked;
			
			dialog.Show();

		}

		private void CopyFieldFromExtraDialog(View eesButton, object dialog, int fieldId)
		{
			var sourceField = (EditText)((Dialog)dialog).FindViewById(fieldId);
			var targetField = ((TextView)((View)eesButton.Parent).FindViewById(fieldId));
			if (sourceField.Text != targetField.Text)
			{
				targetField.Text = sourceField.Text;
				State.EntryModified = true;
			}	
		}

		private void CopyCheckboxFromExtraDialog(View eesButton, object dialog, int fieldId)
		{
			var sourceField = (CheckBox)((Dialog)dialog).FindViewById(fieldId);
			var targetField = ((CheckBox)((View)eesButton.Parent).FindViewById(fieldId));
			if (sourceField.Checked != targetField.Checked)
			{
				targetField.Checked = sourceField.Checked;
				State.EntryModified = true;
			}
		}

		private void FillData() {
			ImageButton currIconButton = (ImageButton) FindViewById(Resource.Id.icon_button);
			App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(currIconButton, Resources, App.Kp2a.GetDb().KpDatabase, State.Entry.IconId, State.Entry.CustomIconUuid);
			
			PopulateText(Resource.Id.entry_title, State.Entry.Strings.ReadSafe (PwDefs.TitleField));
			PopulateText(Resource.Id.entry_user_name, State.Entry.Strings.ReadSafe (PwDefs.UserNameField));
			PopulateText(Resource.Id.entry_url, State.Entry.Strings.ReadSafe (PwDefs.UrlField));
			
			String password = State.Entry.Strings.ReadSafe(PwDefs.PasswordField);
			PopulateText(Resource.Id.entry_password, password);
			PopulateText(Resource.Id.entry_confpassword, password);
			SetPasswordStyle();
			
			PopulateText(Resource.Id.entry_comment, State.Entry.Strings.ReadSafe (PwDefs.NotesField));

			LinearLayout container = (LinearLayout) FindViewById(Resource.Id.advanced_container);
			
			foreach (var pair in State.Entry.Strings)
			{
				String key = pair.Key;
				
				if (!PwDefs.IsStandardField(key)) {
					var ees = CreateExtraStringView(pair);
					container.AddView(ees);
				}
			}

			PopulateBinaries();

			PopulateText(Resource.Id.entry_override_url, State.Entry.OverrideUrl);
			PopulateText(Resource.Id.entry_tags, StrUtil.TagsToString(State.Entry.Tags, true));

			UpdateExpires();
		}
		private String getDateTime(DateTime dt) {
			return dt.ToString ("g", CultureInfo.CurrentUICulture);
		}


		public void DeleteAdvancedString(View view) {
			var section = view.Parent;
			LinearLayout container = (LinearLayout) FindViewById(Resource.Id.advanced_container);
			State.EntryModified = true;
			for (int i = 0; i < container.ChildCount; i++) {
				var ees = container.GetChildAt(i);			
				if (ees == section) {
					container.RemoveViewAt(i);
					container.Invalidate();
					break;
				}
			}
		}
		

		protected bool ValidateBeforeSaving() {
			// Require title
			String title = Util.GetEditText(this, Resource.Id.entry_title);
			if ( title.Length == 0 ) {
				Toast.MakeText(this, Resource.String.error_title_required, ToastLength.Long).Show();
				return false;
			}
			
			// Validate password
			String pass = Util.GetEditText(this, Resource.Id.entry_password);
			String conf = Util.GetEditText(this, Resource.Id.entry_confpassword);
			if ( ! pass.Equals(conf) ) {
				Toast.MakeText(this, Resource.String.error_pass_match, ToastLength.Long).Show();
				return false;
			}

			// Validate expiry date
			DateTime newExpiry = new DateTime();
			if ((State.Entry.Expires) && (!DateTime.TryParse( Util.GetEditText(this,Resource.Id.entry_expires), out newExpiry)))
		    {
				Toast.MakeText(this, Resource.String.error_invalid_expiry_date, ToastLength.Long).Show();
				return false;
			}
			State.Entry.ExpiryTime = newExpiry;


			LinearLayout container = (LinearLayout) FindViewById(Resource.Id.advanced_container);
			for (int i = 0; i < container.ChildCount; i++) {
				View ees = container.GetChildAt(i);
				
				TextView keyView = (TextView) ees.FindViewById(Resource.Id.title);
				string key = keyView.Text;
				
				if (String.IsNullOrEmpty(key)) {
					Toast.MakeText(this, Resource.String.error_string_key, ToastLength.Long).Show();
					return false;
				}
				
			}
			
			return true;
		}

	
		private void PopulateText(int viewId, String text) {
			TextView tv = (TextView) FindViewById(viewId);
			tv.Text = text;
			tv.TextChanged += (sender, e) => {State.EntryModified = true;};
		}

		protected override void OnPause()
		{
			if (!_closeForReload)
				UpdateEntryFromUi(State.Entry);

			base.OnPause();

		}

		
	}

}

