/***********************************************************************
 * 
 *  Copyright (C) 2005-2006 Novell, Inc. All Rights Reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; version 2.1
 *  of the License.
 *
 *  This library 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
 *  Library Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, Novell, Inc.
 * 
 *  To contact Novell about this file by physical or electronic mail, 
 *  you may find current contact information at www.novell.com.
 * 
 ***********************************************************************/

namespace Novell.CASA.GUI {


using System;
using System.Collections;
using System.Collections.Specialized;
using System.Threading;

using Gtk;
using Glade;
using Novell.CASA.MiCasa.Common;
using Novell.CASA.MiCasa.Communication;


public class MiCasa : Store
{
  	Gtk.TreeStore 		tsSecretIDMiCasa, 
  						tsNativeInfoMiCasa, 
  						tsKeyValue,
  						tsAvailableSecrets, 
  						tsAvailableKeys, 
  						tsLinkedKeys; 
  						
  	CellRendererText    cellEditable;

	ArrayList 			arrDeletedKeys = null;
  	
  	private SecretStore m_store = null;
    private String m_sRememberFor = "5";
    private DateTime m_dtRememberMPUntil = DateTime.Now;
    private Thread m_tRememberTimer = null;
    private int m_iRememberSeconds = 5;
  	
  	#region Glade Widgets
	
	[Glade.Widget]
	public Gtk.Window 	windowMain;

  	[Glade.Widget] 
  	public Gtk.TreeView tvSecretIDMiCasa; 
  	  	 	
  	[Glade.Widget] 
  	Gtk.TreeView 		tvNativeInfoMiCasa, 
  						tvKeyValue,
  						tvAvailableSecrets, 
  						tvAvailableKeys, 
  						tvLinkedKeys;
  	
  	[Glade.Widget] 
  	Gtk.Dialog 			dialogNewSecret,
  						dialogManageSecret,
  						dialogConfirmDelete,
						dialogLogin,
  						dialogLinkKeyValue,
  						dialogSpecialCharacter;
  	
  	[Glade.Widget] 
  	Gtk.Menu 			menuRightClick;
  	
  	[Glade.Widget] 
  	Gtk.Entry 			entrySecretID,
  						entryKey,
  						entryValue, 
  						entryDeleteSecretID,
  						entryLinkValue,						
						entryMasterPassword3, 
						entryMasterPassword4;
  	
  	[Glade.Widget] 
  	Gtk.CheckButton		cbuttonShowPassword;
  	  	  	
  	[Glade.Widget] 
  	Gtk.MenuItem 		cmiNewKey,
  						cmiDelete,
  						cmiView,
  						cmiLink,
  						cmiCopy;
  	
  	[Glade.Widget] 
  	Gtk.Notebook		notebook2;
  	
  	[Glade.Widget] 
  	Gtk.Label			labelLinkSecretID, 
  						labelLinkKeyID,
						label86,
						label88,
                        labelRememberFor,
                        labelSeconds;

    [Glade.Widget]
    Gtk.SpinButton      spinbuttonRememberFor;
  	#endregion
  	
  	
  	  	  	  	  	  	  	
  	///#######################################################################
    /// CONSTRUCTOR
    
    /// <summary>
	///  
	/// </summary>
	public MiCasa()
  	{
  		Logger.DbgLog("GUI:MiCasa.MiCasa() - BEGIN");
  		
  		/// SecretID TreeStore
  		tvSecretIDMiCasa = (Gtk.TreeView)CasaMain.gxmlMain.GetWidget("tvSecretIDMiCasa");
		tsSecretIDMiCasa = new TreeStore(typeof(string), typeof(string[]), typeof(string[]), typeof(string), typeof(string[]), typeof(string[]));		
		tvSecretIDMiCasa.AppendColumn("Secret ID",new CellRendererText(),"text",0);
		tvSecretIDMiCasa.Model = tsSecretIDMiCasa;
		tsSecretIDMiCasa.SetSortColumnId(0, Gtk.SortType.Ascending);
		tvSecretIDMiCasa.RowActivated 		+= new RowActivatedHandler(OntvSecretIDMiCasaRowActivated);		
		tvSecretIDMiCasa.ButtonReleaseEvent += new ButtonReleaseEventHandler(OnRightClicked);		
		tvSecretIDMiCasa.CursorChanged 		+= new EventHandler(OnCursorChanged);
		/// NativeInfo TreeStore
		tvNativeInfoMiCasa = (Gtk.TreeView)CasaMain.gxmlMain.GetWidget("tvNativeInfoMiCasa");
		tsNativeInfoMiCasa = new TreeStore(typeof(string), typeof(string));		
		tvNativeInfoMiCasa.AppendColumn("NativeKey",new CellRendererText(),"text",0);
		tvNativeInfoMiCasa.AppendColumn("NativeValue",new CellRendererText(),"text",1);
		tvNativeInfoMiCasa.Model = tsNativeInfoMiCasa;
		tvNativeInfoMiCasa.ModifyBase(StateType.Normal,new Gdk.Color(0xff,0xff,0xe6));
		/// Aggregate the store
		AggregateStore();
				
		Logger.DbgLog("GUI:MiCasa.MiCasa() - END");
  	} 
  	
  	
  	
	///#######################################################################
	/// AGGREGATE STORE
	
    /// <summary>
	/// 
	/// </summary>
	public override void AggregateStore()
  	{
		Logger.DbgLog("GUI:MiCasa.AggregateStore() - BEGIN");
		
		try
		{
			tsSecretIDMiCasa.Clear();  	
			tsNativeInfoMiCasa.Clear();
  			StoreDataInterface.AggregateStore(Common.STORE_MICASA);
  			StoreDataInterface.ReadStore(Common.STORE_MICASA,ref tsSecretIDMiCasa);
  		}
  		catch(Exception exp)
  		{
  			Logger.DbgLog("GUI:MiCasa.AggregateStore() - EXCEPTION:" + exp.ToString());
  		}
  		
  		Logger.DbgLog("GUI:MiCasa.AggregateStore() - END");  		
  	}

	public override void ClearViewOnStore()
	{
		tsSecretIDMiCasa.Clear();  	
		tsNativeInfoMiCasa.Clear();
	}
  	
  	
  	
  	///#######################################################################
  	/// DISPLAY NATIVE INFO
  	
    /// <summary>
	/// For Native Information display.
	/// </summary>
  	private void OnCursorChanged(object obj, EventArgs args)
  	{
  		Logger.DbgLog("GUI:MiCasa.OnCursorChanged() - BEGIN");
  		
  		TreeModel 	model;
		TreeIter 	iter;
		string 		selected     = null;
		string[] 	NativeKeys   = null, 
					NativeValues = null;  		
		
		if( tvSecretIDMiCasa.Selection.GetSelected (out model, out iter) )
			selected = (string) model.GetValue (iter, 0);

		if( (null != selected) && (selected.Length > 0) )
		{			
			tsNativeInfoMiCasa.Clear();
			/// Populate NativeInfo
			tsNativeInfoMiCasa.AppendValues("Keychain Name", "= "+model.GetValue(iter,3));			
			NativeKeys   = (string[]) model.GetValue (iter, 4);
			NativeValues = (string[]) model.GetValue (iter, 5);			
			for( int i=0; i< NativeKeys.Length; i++ )
				if( (null != NativeValues[i]) && ("" != NativeValues[i]) )
					tsNativeInfoMiCasa.AppendValues(NativeKeys[i], "= "+NativeValues[i]);			
			tvNativeInfoMiCasa.ShowAll();
		} 
  		
  		Logger.DbgLog("GUI:MiCasa.OnCursorChanged() - END");
  	}
  	
  	///#######################################################################
	/// RIGHT-CLICK CONTEXT MENU
	
    /// <summary>
	/// 
	/// </summary>
	public void OnRightClicked(object obj, ButtonReleaseEventArgs args)
	{			
		Logger.DbgLog("GUI:MiCasa.OnRightClicked() - BEGIN");
		
		if( 3 == args.Event.Button )
		{
			try
			{
				Logger.DbgLog("GUI:MiCasa.OnRightClicked() - Context menu opened.");
				Glade.XML gxmlTemp = new Glade.XML (Common.GladeFile, "menuRightClick", null);
    	    			gxmlTemp.Autoconnect (this);
				menuRightClick.Popup(null, null, null, IntPtr.Zero, 3, Gtk.Global.CurrentEventTime);
				
				if( 0 != tvSecretIDMiCasa.Selection.CountSelectedRows() )
					cmiCopy.Sensitive = false;					
				else
					cmiNewKey.Sensitive = cmiView.Sensitive = cmiLink.Sensitive = cmiCopy.Sensitive = cmiDelete.Sensitive = false;				
			}
			catch(Exception exp)
			{
				Logger.DbgLog("GUI:MiCasa.OnRightClicked() - EXCEPTION:" + exp.ToString());
			}
		}
		Logger.DbgLog("GUI:MiCasa.OnRightClicked() - BEGIN");	
	}
	
	
  	
    ///#######################################################################
	/// VIEW KEY-VALUES 
	
	/// <summary>
	/// 
	/// </summary>
  	public override void ViewKeyValues()
	{						
		Logger.DbgLog("GUI:MiCasa.dialogManageSecret() - BEGIN");
		
		TreeModel model;
		TreeIter  iter;
		string    selected	= null;				  
		string[]  keys		= null,
			  values	= null;
		
		try
		{
		if( null == arrDeletedKeys )
			arrDeletedKeys = new ArrayList();
		else
			arrDeletedKeys.Clear();
				
		if( tvSecretIDMiCasa.Selection.GetSelected (out model, out iter) )
		{
			selected = (string)   model.GetValue(iter, 0);
			keys	 = (string[]) model.GetValue(iter, 1);
			values 	 = (string[]) model.GetValue(iter, 2);
					
			Glade.XML gxmlTemp = new Glade.XML (Common.GladeFile, "dialogManageSecret", null);
	    	gxmlTemp.Autoconnect (this);
			dialogManageSecret.TransientFor = (Gtk.Window)CasaMain.gxmlMain.GetWidget("windowMain");
			dialogManageSecret.Title = "miCASA - Manage Secret";
						
			cellEditable = new CellRendererText();
			cellEditable.Editable = true;
			cellEditable.Edited += new EditedHandler(OnKeyValueEdited);		
			///			   				KEY:0          VALUE:1         VALUE-DUP:2  	  DIRTY-BIT:3   LINK:4 			
			tsKeyValue = new TreeStore(typeof(string),typeof(string), typeof(string), typeof(bool), typeof(string));
			tvKeyValue.AppendColumn("Key",new CellRendererText(),"text",0);
			tvKeyValue.AppendColumn("Value",cellEditable,"text",2);
			tvKeyValue.AppendColumn("Linked", new CellRendererText(), "text", 4);
			tvKeyValue.RowActivated += new RowActivatedHandler(tvKeyValue_RowActivated);
			
			entrySecretID.Text = selected;
			SecretStore ss = GetMiCasaStore();
			bool bHasLinks = false;

			for( int i=0; i< keys.Length; i++ )
			{				
				Secret secret = ss.getSecret(selected);
				Hashtable ht = secret.GetLinkedKeys(keys[i]);
				if (ht != null && ht.Count > 0)
					bHasLinks = true;
				else
					bHasLinks = false;				
				
				if( (null != keys[i]) && (null != values[i]) )
					if( bHasLinks )
					{
						tsKeyValue.AppendValues(keys[i], values[i], "********", false, "Yes");
					}
					else
					{
						tsKeyValue.AppendValues(keys[i], values[i], "********", false, "No");

					}				
			}
			
			
			
			tvKeyValue.Model = tsKeyValue;
			entryKey.HasFocus = true;
		}
		}
		catch(Exception exp)
		{
			Logger.DbgLog("GUI:MiCasa.dialogManageSecret() - EXCEPTION:" + exp.ToString());
		}
		
		Logger.DbgLog("GUI:MiCasa.dialogManageSecret() - END");
	}
	
	
	/// <summary>
	/// EDIT KEY-VALUE 
	/// </summary>
	public void OnKeyValueEdited(object obj, EditedArgs args)	
	{		
		Logger.DbgLog("GUI:MiCasa.OnKeyValueEdited() - BEGIN");
		
		TreeModel model;
		TreeIter  iter;	
		object    val;
		string    KeyName  = null,
				  KeyValue = null;
		string[]  Keys	   = null,
				  Values   = null;  
		
		try
		{		
			tvKeyValue.Selection.GetSelected (out model, out iter);		
			val = tsKeyValue.GetValue(iter,0); 
			KeyName = val.ToString();
			if( true == cbuttonShowPassword.Active )
				val = tsKeyValue.GetValue(iter,1);
			else
			 	val = tsKeyValue.GetValue(iter,2);
			KeyValue = val.ToString();
							
			tvSecretIDMiCasa.Selection.GetSelected (out model, out iter);		
			
			if( false == entrySecretID.Editable )
			{
				if( ("" != args.NewText) && (Common.MAX_LEN >= args.NewText.Length) && (KeyValue != args.NewText) )
				{
				if(  Common.STATUS_SUCCESS == StoreDataInterface.UpdateStore(Common.STORE_MICASA, Common.OPERATION_MODIFY_KEY, KeyName, args.NewText, ref model, ref iter) )
				{
					Logger.DbgLog("GUI:MiCasa.OnKeyValueEdited() - StoreDataInterface.UpdateStore() succeeded");
					tvKeyValue.Selection.GetSelected (out model, out iter);				
					tsKeyValue.SetValue(iter, 1, args.NewText);					
					tsKeyValue.SetValue(iter, 2, "********");
					
					tvSecretIDMiCasa.Selection.GetSelected (out model, out iter);
					Keys   = (string[]) model.GetValue(iter, 1);
					Values = (string[]) model.GetValue(iter, 2);		
					for( int i=0; i< Keys.Length; i++ )
					{
						if( Keys[i] == KeyName )
						{
							Values[i] = args.NewText;
							tsSecretIDMiCasa.SetValue(iter, 2, Values);				
							break;
						}
					}
					//AggregateStore();
				}
				else
					Logger.DbgLog("GUI:MiCasa.OnKeyValueEdited() - ERROR: STATUS_STORE_UPDATEFAILED");
				}
				
			}
			else if( (Common.MAX_LEN >= args.NewText.Length) )
			{
				tvKeyValue.Selection.GetSelected (out model, out iter);				
				tsKeyValue.SetValue(iter, 1, args.NewText);
				tsKeyValue.SetValue(iter, 2, "********");				
			}				
		}
		catch(Exception exp)
		{
			Logger.DbgLog("GUI:MiCasa.OnKeyValueEdited() - EXCEPTION:" + exp.ToString());
		}
		
		Logger.DbgLog("GUI:MiCasa.OnKeyValueEdited() - END");
	}

	public void on_buttonhelpEditSecret_clicked(object obj, EventArgs args)
	{
		Common.ShowHelpUrl("EditingSecrets.html");
	}
	
	/// <summary>
	/// ADD BUTTON CLICKED 
	/// </summary>
	public void on_buttonNewAdd_clicked(object obj, EventArgs args)
	{
		Logger.DbgLog("GUI:MiCasa.on_buttonNewAdd_clicked() - BEGIN");
				
		if( ("" != entryKey.Text) && ("" != entryValue.Text) )		
		{
			TreeIter  iterKey;			
			object    val = null;
			ArrayList arrKeys   = new ArrayList();
			ArrayList arrValues = new ArrayList();
			
			if(tsKeyValue.GetIterFirst(out iterKey))
			{
				do
				{									
					val = tsKeyValue.GetValue(iterKey,0);
					arrKeys.Add(val.ToString());
					val = tsKeyValue.GetValue(iterKey,1);
					arrValues.Add(val.ToString());
				}
				while( tsKeyValue.IterNext(ref iterKey) );
			}		
			if( -1 == arrKeys.IndexOf(entryKey.Text) )
			if( true == Common.ValidateString(entryKey.Text) )
			{
				iterKey = tsKeyValue.AppendValues(entryKey.Text, entryValue.Text, "********", true, "No");
				entryKey.Text = entryValue.Text = "";				
			}
			else
			{
				Glade.XML gxmlTemp = new Glade.XML (Common.GladeFile, "dialogSpecialCharacter", null);
				gxmlTemp.Autoconnect (this);
				//dialogSpecialCharacter.TransientFor = (Gtk.Window)CasaMain.gxmlMain.GetWidget("dialogNewSecret");			
			}	
			//tvKeyValue.Selection.SelectIter(iterKey);
			entryKey.HasFocus = true;
		}			
		
		Logger.DbgLog("GUI:MiCasa.on_buttonNewAdd_clicked() - END");		
	}
	
	public void on_buttonSCClose_clicked(object obj, EventArgs args)
	{
		dialogSpecialCharacter.Destroy();
	}
	
	/// <summary>
	/// REMOVE BUTTON CLICKED 
	/// </summary>
	public void on_buttonNewRemove_clicked(object obj, EventArgs args)
	{
		Logger.DbgLog("GUI:MiCasa.on_buttonNewRemove_clicked() - BEGIN");
		
		TreeModel modelKey;
		TreeIter  iterKey; 
		
		if(tvKeyValue.Selection.GetSelected (out modelKey, out iterKey))
			if( false == (bool)tsKeyValue.GetValue(iterKey,3) )
				arrDeletedKeys.Add(tsKeyValue.GetValue(iterKey,0));		
					
		if( 0 != tvKeyValue.Selection.CountSelectedRows() )
		{
			TreeModel model;
			TreeIter  iter;
			
			tvKeyValue.Selection.GetSelected (out model, out iter);
			tsKeyValue.Remove(ref iter);
			tvKeyValue.ColumnsAutosize();
		}
		
		Logger.DbgLog("GUI:MiCasa.on_buttonNewRemove_clicked() - END");
	}
	
	
	/// <summary>
	/// SHOW PASSWORD CHECK BUTTON CLICKED 
	/// </summary>
	public void on_cbuttonShowPassword_toggled(object obj, EventArgs args)
	{        
		TreeViewColumn tvCol;

        if (tvKeyValue.Model.IterNChildren() > 0)
        {

            if ((true == cbuttonShowPassword.Active) && (m_dtRememberMPUntil.CompareTo(DateTime.Now) > 0))
            {                
                tvKeyValue.RemoveColumn(tvKeyValue.GetColumn(1));
                tvCol = new TreeViewColumn("Value", cellEditable, "text", 1);
                tvKeyValue.InsertColumn(tvCol, 1);
            }
            else if (true == cbuttonShowPassword.Active)
            {
                // prompt user for MasterPassword

                Glade.XML gxmlTemp = new Glade.XML(Common.GladeFile, "dialogLogin", null);
                gxmlTemp.Autoconnect(this);
                dialogLogin.TransientFor = dialogManageSecret;

                label86.Text = "Enter your Master Password to view values";
                entryMasterPassword3.Text = "";
                entryMasterPassword3.HasFocus = true;
                label88.Hide();
                entryMasterPassword4.Hide();

                //labelRememberFor.Visible = true;
                //labelSeconds.Visible = true;
                //spinbuttonRememberFor.Visible = true;
                //spinbuttonRememberFor.Text = m_sRememberFor;

                dialogLogin.Show();
            }
            else
            {                
                tvKeyValue.RemoveColumn(tvKeyValue.GetColumn(1));
                tvCol = new TreeViewColumn("Value", cellEditable, "text", 2);
                tvKeyValue.InsertColumn(tvCol, 1);
            }
        }	
	}
	
	public void okbuttonLogin_clicked(object abj, EventArgs args)
	{    
		TreeViewColumn tvCol;
		
		if( tvKeyValue.Model.IterNChildren() > 0 )

		if( 0 == miCASA.SetMasterPassword(0, entryMasterPassword3.Text) )
		{			
			tvKeyValue.RemoveColumn(tvKeyValue.GetColumn(1));
			tvCol = new TreeViewColumn("Value", cellEditable, "text", 1);
			tvKeyValue.InsertColumn(tvCol, 1);			

            // get seconds to remember
			/*
            m_sRememberFor = spinbuttonRememberFor.Text;
            if (m_sRememberFor != null)
            {
                DateTime dtNow = DateTime.Now;
                m_iRememberSeconds = int.Parse(m_sRememberFor);
                m_dtRememberMPUntil = dtNow.AddSeconds(m_iRememberSeconds);                
            } 
			*/          
			dialogLogin.Destroy();

            //if (m_iRememberSeconds > 0)
               // StartRememberTimer();
		}
		else
		{
			// prompt user 						
			MessageDialog md=new MessageDialog(dialogLogin,Gtk.DialogFlags.Modal,
												Gtk.MessageType.Warning,
												Gtk.ButtonsType.Ok,
												"Master Password incorrect");

			md.Response +=new ResponseHandler(md_Response2);
			md.SetPosition(Gtk.WindowPosition.CenterOnParent);		
			md.Modal = true;
			md.Show();
		}				
	}
	
	public void closebuttonLogin_clicked(object abj, EventArgs args)
	{
		cbuttonShowPassword.Active = false;
		dialogLogin.Destroy();  
	}
    
    
	public void OnDialogLoginDeleted(object obj, DeleteEventArgs args) 
	{		    			
		cbuttonShowPassword.Active = false;
		dialogLogin.Destroy();
		args.RetVal = true;        		
	}

    public void StartRememberTimer()
    {
        //if (m_tRememberTimer == null)
        {
            m_tRememberTimer = new Thread(new ThreadStart(ResetTimerThreadFn));
            m_tRememberTimer.Start();
        }
        
    }
    internal void ResetTimerThreadFn()
    {
        TreeViewColumn tvCol;
        Thread.Sleep(m_iRememberSeconds * 1000);
        if (tvKeyValue != null)
        {
            try
            {
                tvKeyValue.RemoveColumn(tvKeyValue.GetColumn(1));
                tvCol = new TreeViewColumn("Value", cellEditable, "text", 2);
                tvKeyValue.InsertColumn(tvCol, 1);    
                cbuttonShowPassword.Active = false;
            }
            catch
            {
                
            }
        }
    }
    
	public void on_entryMasterPassword3_activate(object obj, EventArgs args)
	{
		if( "" != entryMasterPassword3.Text )
			okbuttonLogin_clicked(obj, args);
	}
    
	public void on_entryMasterPassword4_activate(object obj, EventArgs args)
	{
		okbuttonLogin_clicked(obj, args);
	}
    
	
	private void md_Response2(object o, ResponseArgs args)
	{
		MessageDialog md = (MessageDialog)o;
		if (md != null)
		{
			md.Destroy();
			entryMasterPassword3.Text="";
			entryMasterPassword3.HasFocus = true;			
		}
	}

	public void on_helpbuttonAuthentication_clicked(object obj, EventArgs args)
	{
		Common.ShowHelpUrl("CASAMasterPasswordAuthentication.htm");		
	}
	
	/// <summary>
	/// MANAGE SECRET-ID DIALOG OK-BUTTON CLICKED 
	/// </summary>
	public void on_buttonManageOk_clicked(object obj, EventArgs args)
	{
		TreeModel modelSecret;
		TreeIter  iterSecret, 
			  iterKey;
		string    NewKey    	 = null,
			  NewValue  	 = null;				  
		string[]  strDeletedKeys = null;			  
		bool   	  dirtyBit  	 = false;		
		//ArrayList arrKeys   	 = null,
		//	  arrValues 	 = null;
		
		try
		{
			if( (0 == tvKeyValue.Model.IterNChildren()) && tvSecretIDMiCasa.Selection.GetSelected (out modelSecret, out iterSecret) )
			{
				if( Common.STATUS_SUCCESS == StoreDataInterface.UpdateStore(Common.STORE_MICASA, Common.OPERATION_DELETE_SECRET, "", "", ref modelSecret, ref iterSecret) )
				{				
					tsSecretIDMiCasa.Remove(ref iterSecret);
					tvSecretIDMiCasa.ColumnsAutosize();
					tsNativeInfoMiCasa.Clear();					
					Logger.DbgLog("GUI:MiCasa.on_buttonManageOk_clicked() - DELETE_SECRET_SUCCEEDED");					
				}
				else
					Logger.DbgLog("GUI:MiCasa.on_buttonManageOk_clicked() - DELETE_SECRET_FAILED");					
				AggregateStore();
			}
			else 
			{
			if( (null != arrDeletedKeys) && (arrDeletedKeys.Count > 0) )
			{					
				tvSecretIDMiCasa.Selection.GetSelected (out modelSecret, out iterSecret);
				strDeletedKeys = (string[])arrDeletedKeys.ToArray(typeof(string));
				for( int i=0; i < strDeletedKeys.Length; i++)
				{
					if( Common.STATUS_SUCCESS == StoreDataInterface.UpdateStore(Common.STORE_MICASA, Common.OPERATION_DELETE_KEY, strDeletedKeys[i], null, ref modelSecret, ref iterSecret) )
						Logger.DbgLog("GUI:MiCasa.on_buttonManageOk_clicked() - DELETE_KEY_SUCCEEDED.");
					else
						Logger.DbgLog("GUI:MiCasa.on_buttonManageOk_clicked() - DELETE_KEY_FAILED.");	
				}
				arrDeletedKeys.Clear();
							
			}			
			
			if( tsKeyValue.GetIterFirst(out iterKey) && tvSecretIDMiCasa.Selection.GetSelected (out modelSecret, out iterSecret) )
			{					
				do
				{									
					NewKey   = (string) tsKeyValue.GetValue(iterKey,0);				
					NewValue = (string) tsKeyValue.GetValue(iterKey,1);
					dirtyBit = (bool)   tsKeyValue.GetValue(iterKey,3);
					
					if( true == dirtyBit )
					{	
						if( Common.STATUS_SUCCESS == StoreDataInterface.UpdateStore(Common.STORE_MICASA, Common.OPERATION_ADD_KEY, NewKey, NewValue, ref modelSecret, ref iterSecret) )
							Logger.DbgLog("GUI:MiCasa.on_buttonManageOk_clicked() - ADD_KEY_VALUE_SUCCEEDED.");
						else
							Logger.DbgLog("GUI:MiCasa.on_buttonManageOk_clicked() - ADD_KEY_VALUE_FAILED.");		
					}
				}
				while( tsKeyValue.IterNext(ref iterKey) );									
				
			}
				AggregateStore();
			}						
		}
		catch(Exception exp)
		{
			Logger.DbgLog("GUI:MiCasa.on_buttonManageOk_clicked() - EXCEPTION:" + exp.ToString());		
		}
		
		tsKeyValue.Dispose();
		dialogManageSecret.Destroy();			
	}
	
	/// <summary>
	/// MANAGE SECRET-ID DIALOG CANCEL-BUTTON CLICKED 
	/// </summary>
	public void on_buttonManageCancel_clicked(object obj, EventArgs args)
	{
		tsKeyValue.Dispose();
		arrDeletedKeys.Clear();
		dialogManageSecret.Destroy();		
	}
	
	/// <summary>
	/// SECRET-ID DOUBLE CLICKED 
	/// </summary>
	private void OntvSecretIDMiCasaRowActivated( object obj, RowActivatedArgs args ) 
	{ 
		Logger.DbgLog("GUI:MiCasa.OntvSecretIDMiCasaRowActivated() - SecretID doubled clicked.");		
		ViewKeyValues();
	}
	
	/// <summary>
	/// VIEW KEY-VALUES CALLED VIA MAIN-MENU/CONTEXT-MENU 
	/// </summary>
	public void OnViewActivated(object obj, EventArgs args)
	{
		Logger.DbgLog("GUI:MiCasa.OnViewActivated() - ViewKeyValues() called.");
		ViewKeyValues();		
	}
	
	///#######################################################################
	/// ADD NEW SECRET
	
    /// <summary>
	/// 
	/// </summary>
	public void OnNewSecretActivated(object obj, EventArgs args)
	{
		Logger.DbgLog("GUI:MiCasa.OnNewSecretActivated() - BEGIN");
		
		Glade.XML gxmlTemp = new Glade.XML (Common.GladeFile, "dialogNewSecret", null);
        	gxmlTemp.Autoconnect (this);
        	dialogNewSecret.TransientFor = (Gtk.Window)CasaMain.gxmlMain.GetWidget("windowMain");
        	dialogNewSecret.Title = "miCASA - New Secret";
		
        	cellEditable = new CellRendererText();
		cellEditable.Editable = true;
		cellEditable.Edited += new EditedHandler(OnKeyValueEdited);		
        ///				   KEY:0          VALUE:1         VALUE-DUP:2  	  DIRTY-BIT:3   LINK:4 			
		tsKeyValue = new TreeStore(typeof(string),typeof(string), typeof(string), typeof(bool), typeof(string));
		tvKeyValue.AppendColumn("Key",new CellRendererText(),"text",0);
		tvKeyValue.AppendColumn("Value",cellEditable,"text",2);
		tvKeyValue.AppendColumn("Linked",new CellRendererText(),"text",4);
		tvKeyValue.Model = tsKeyValue;		
		tsKeyValue.Clear();
		entrySecretID.HasFocus = true;
		entrySecretID.Text = "";
		
		Logger.DbgLog("GUI:MiCasa.OnNewSecretActivated() - END");
	}
	
	
	
	///#######################################################################
    /// ADD NEW KEY-VALUES TO EXISTING SECRET
    
    /// <summary>
	/// 
	/// </summary>
	public void OnNewKeyActivated(object obj, EventArgs args)
	{
		Logger.DbgLog("GUI:MiCasa.OnNewKeyActivated() - BEGIN");
		
		ViewKeyValues();
		
        	Logger.DbgLog("GUI:MiCasa.OnNewKeyActivated() - END");        
	}
	
	
	
	
	public void on_buttonNewOk_clicked(object obj, EventArgs args)
	{
		Logger.DbgLog("GUI:MiCasa.on_buttonNewOk_clicked() - BEGIN");
		
		TreeModel modelSecret;
		TreeIter  iterSecret,
				  iterKey;
		string 	  NewKey       = null,
				  NewValue     = null; 
		string[]  Keys	   	   = null,
				  Values   	   = null,
				  NativeKeys   = null,
				  NativeValues = null;
		object 	  val		   = null;		
		ArrayList arrKeys	   = null,
				  arrValues    = null;
					
		if ( true == entrySecretID.Editable && false == Common.ValidateString(entrySecretID.Text) )
		{
			/*// prompt user 						
			MessageDialog md=new MessageDialog(this.windowMain,Gtk.DialogFlags.Modal,
				Gtk.MessageType.Warning,
				Gtk.ButtonsType.Ok,
				"Secret ID may not contain \"*\"");

			md.Response += new ResponseHandler(md_Response);
			md.SetPosition(Gtk.WindowPosition.CenterOnParent);		
			md.Modal = true;
			md.Show();*/
			Glade.XML gxmlTemp = new Glade.XML (Common.GladeFile, "dialogSpecialCharacter", null);
			gxmlTemp.Autoconnect (this);
			entrySecretID.HasFocus = true;
			return;
		}

		if( (true == entrySecretID.Editable) && ("" != entrySecretID.Text) && (tvKeyValue.Model.IterNChildren() > 0) )
		{
			Logger.DbgLog("GUI:MiCasa.on_buttonNewOk_clicked() - Adding New Secrets and KeyValues.");
			
			arrKeys 	= new ArrayList();
			arrValues 	= new ArrayList();
			
			try
			{
				if(tsKeyValue.GetIterFirst(out iterKey))
				{
					do
					{
						val = tsKeyValue.GetValue(iterKey,0);
						NewKey = val.ToString();				
						val = tsKeyValue.GetValue(iterKey,1);
						NewValue = val.ToString();
						
						if( -1 == (arrKeys.IndexOf(NewKey)) )
						{	
							arrKeys.Add(NewKey);
							arrValues.Add(NewValue);
						}
					} 
					while( tsKeyValue.IterNext(ref iterKey) );
					
					Keys = (string[])arrKeys.ToArray(typeof(string));
					Values = (string[])arrValues.ToArray(typeof(string));
					NativeKeys = new string[Common.MAX_NATIVE_ELEMENTS];
					NativeValues = new string[Common.MAX_NATIVE_ELEMENTS];					
					NativeKeys[Common.INDEX_NATIVEINFO_FOLDERNAME] = Common.NATIVEINFO_FOLDERNAME; 
					NativeKeys[Common.INDEX_NATIVEINFO_TYPEID] = Common.NATIVEINFO_TYPEID;
					NativeKeys[Common.INDEX_NATIVEINFO_SYNC] = Common.NATIVEINFO_SYNC;
					NativeKeys[Common.INDEX_NATIVEINFO_SYNCTYPE] = Common.NATIVEINFO_SYNCTYPE;
					NativeKeys[Common.INDEX_NATIVEINFO_MODIFIEDTIME] = Common.NATIVEINFO_MODIFIEDTIME;				
					NativeValues[Common.INDEX_NATIVEINFO_FOLDERNAME] = null;
					NativeValues[Common.INDEX_NATIVEINFO_TYPEID] = null;
					NativeValues[Common.INDEX_NATIVEINFO_SYNC] = null;
					NativeValues[Common.INDEX_NATIVEINFO_SYNCTYPE] = null;
					NativeValues[Common.INDEX_NATIVEINFO_MODIFIEDTIME] = null;					
					
					iterSecret = tsSecretIDMiCasa.AppendValues(entrySecretID.Text, Keys, Values, "Default", NativeKeys, NativeValues);
					modelSecret = tvSecretIDMiCasa.Model;					
					
					if( Common.STATUS_SUCCESS == StoreDataInterface.UpdateStore(Common.STORE_MICASA, Common.OPERATION_ADD_SECRET, "", "", ref modelSecret, ref iterSecret) )
					{
						AggregateStore();
						Logger.DbgLog("GUI:MiCasa.on_buttonNewOk_clicked() - ADD_NEW_SECRET_SUCCEEDED.");
					}
	    			else
	    				Logger.DbgLog("GUI:MiCasa.on_buttonNewOk_clicked() - ERROR: ADD_NEW_SECRET_FAILED");	
	    		}
    		}
			catch(Exception exp)
			{
				Logger.DbgLog("GUI:MiCasa.on_buttonNewOk_clicked() - EXCEPTION:" + exp.ToString());	
			}
			tsKeyValue.Dispose();
			dialogNewSecret.Destroy();		
		}
	
		
		Logger.DbgLog("GUI:MiCasa.on_buttonNewOk_clicked() - END");
	}
		
		
	public void on_buttonNewCancel_clicked(object obj, EventArgs args)
	{		
		dialogNewSecret.Destroy();
	}

	public void on_helpbuttonNewSecret_clicked(object obj, EventArgs args)
	{
		Common.ShowHelpUrl("AddNewSecrets.htm");
	}
		
		
	///#######################################################################
    /// LINK 
    
    /// <summary>
	/// LINK Key-Values
	/// </summary>
	public void OnLinkActivated(object obj, EventArgs args)
	{
		Logger.DbgLog("GUI:MiCasa.OnLinkActivated() - ViewKeyValues() called.");
		ViewKeyValues();
	}
	
	
	
	///#######################################################################
    /// COPY
    
    /// <summary>
	/// COPY Key-Values
	/// </summary>		
	public void OnCopyActivated(object obj, EventArgs args)
	{
		
	}  
	
	public void on_helpbuttonLinkKeys_clicked(object obj, EventArgs args)
	{
		Common.ShowHelpUrl("LinkingSecrets.htm");
	}
	
	
	///#######################################################################
    // DELETE SECRET
    
    /// <summary>
	/// DELETE Secret
	/// </summary>						
	public void OnDeleteActivated(object obj, EventArgs args)	
	{
		Logger.DbgLog("GUI:MiCasa.OnDeleteActivated() - BEGIN");
		
		if( 0 != tvSecretIDMiCasa.Selection.CountSelectedRows() )
        {
			Glade.XML gxmlTemp = new Glade.XML (Common.GladeFile, "dialogConfirmDelete", null);
        	gxmlTemp.Autoconnect (this);
            dialogConfirmDelete.TransientFor = (Gtk.Window)CasaMain.gxmlMain.GetWidget("windowMain");                
	    dialogConfirmDelete.Title = "miCASA - Delete Secret";
	    
        	TreeModel model;
			TreeIter  iter;
			string    selected = null;			
			if( tvSecretIDMiCasa.Selection.GetSelected (out model, out iter) )
			{
				selected = (string) model.GetValue (iter, 0);
				if( (null != selected) && (selected.Length > 0) )
					entryDeleteSecretID.Text = selected;
			}
		}
        
        Logger.DbgLog("GUI:MiCasa.OnDeleteActivated() - END");
	}
	
	public void on_buttonYes_clicked(object obj, EventArgs args)
	{
		Logger.DbgLog("GUI:MiCasa.on_buttonYes_clicked() - BEGIN");
				
		TreeModel model;
		TreeIter  iter;
		
		try
		{
			if( tvSecretIDMiCasa.Selection.GetSelected (out model, out iter) )
			{
				if( Common.STATUS_SUCCESS == StoreDataInterface.UpdateStore(Common.STORE_MICASA, Common.OPERATION_DELETE_SECRET, "", "", ref model, ref iter) )
				{				
					tsSecretIDMiCasa.Remove(ref iter);
					tvSecretIDMiCasa.ColumnsAutosize();
					tsNativeInfoMiCasa.Clear();
					dialogConfirmDelete.Destroy();
					Logger.DbgLog("GUI:MiCasa.on_buttonYes_clicked() - DELETE_SECRET_SUCCEEDED");
					
				}
				else
					Logger.DbgLog("GUI:MiCasa.on_buttonYes_clicked() - DELETE_SECRET_FAILED");
			}
		}
		catch(Exception exp)
		{
			Logger.DbgLog("GUI:MiCasa.on_buttonYes_clicked() - EXCEPTION:" + exp.ToString());
		}
		
		Logger.DbgLog("GUI:MiCasa.on_buttonYes_clicked() - END");						
	}
	
	public void on_buttonNo_clicked(object obj, EventArgs args)
	{		
		dialogConfirmDelete.Destroy();
	}
	
	/// LINK
	
	private void tvKeyValue_RowActivated(object o, RowActivatedArgs args)
		{
			TreeModel model;
			TreeIter iter;
			string selected=null;
								
			if(tvKeyValue.Selection.GetSelected (out model, out iter))
			{				
				selected=(string) model.GetValue (iter, 0);
				if(selected != null && selected.Length > 0)
				{
					Glade.XML gxmlTemp = new Glade.XML (Common.GladeFile, "dialogLinkKeyValue", null);
					gxmlTemp.Autoconnect (this);
					dialogLinkKeyValue.TransientFor = (Gtk.Window)CasaMain.gxmlMain.GetWidget("dialogNewSecret");
					dialogLinkKeyValue.Title = "miCASA - Link Keys";
					dialogLinkKeyValue.Modal = true;
					
					
					// show MICASA tab only
					(notebook2.GetNthPage(Common.STORE_MICASA)).Visible = true;
					(notebook2.GetNthPage(Common.STORE_FIREFOX)).Visible = false;
        			(notebook2.GetNthPage(Common.STORE_MOZILLA)).Visible = false;
        			(notebook2.GetNthPage(Common.STORE_KDEWALLET)).Visible = false;
        			(notebook2.GetNthPage(Common.STORE_GNOMEKEYRING)).Visible = false;

					// show available secrets
					tsAvailableSecrets=new TreeStore(typeof(string),typeof(string));		
					tsAvailableSecrets.SetSortColumnId(0, Gtk.SortType.Ascending);

					tvAvailableSecrets.AppendColumn("Secret ID",new CellRendererText(),"text",0);									
					tvAvailableSecrets.Model=tsAvailableSecrets;				
					tvAvailableSecrets.ButtonReleaseEvent +=new ButtonReleaseEventHandler(tvAvailableSecrets_ButtonReleaseEvent);

					// show secretIDs
					SecretStore ss = GetMiCasaStore();
					StringCollection sc = ss.enumerateSecretIDs();
					StringEnumerator se = sc.GetEnumerator();
					se.Reset();
					while (se.MoveNext())
					{
						tsAvailableSecrets.AppendValues(se.Current);
					}

					// show available keys
					tsAvailableKeys=new TreeStore(typeof(string), typeof(string));
					tvAvailableKeys.AppendColumn("Key", new CellRendererText(), "text", 0);
					//tvAvailableKeys.AppendColumn("Value", new CellRendererText(), "text", 1);
					tvAvailableKeys.Model=tsAvailableKeys;	
					tvAvailableKeys.Show();


					// populate current linked keys
					tsLinkedKeys=new TreeStore(typeof(string), typeof(string));
					tsLinkedKeys.SetSortColumnId(0, Gtk.SortType.Descending);				

					tvLinkedKeys.AppendColumn("Secret ID", new CellRendererText(), "text", 0);
					tvLinkedKeys.AppendColumn("Key", new CellRendererText(), "text", 1);
					tvLinkedKeys.Model=tsLinkedKeys;
									
					Secret secret = ss.getSecret(entrySecretID.Text);
					ShowLinkedKeys(secret, selected);

					// display info on this secret
					labelLinkSecretID.Text = entrySecretID.Text;
					labelLinkKeyID.Text = selected;
					//entryLinkValue.Text = secret.getKeyValue(selected);
					entryLinkValue.Sensitive = false;
					entryLinkValue.Text = "********";
					entryLinkValue.Changed +=new EventHandler(entryLinkValue_Changed);
					entryLinkValue.LeaveNotifyEvent +=new LeaveNotifyEventHandler(entryLinkValue_LeaveNotifyEvent);

				}
			}
		}

		private void ShowLinkedKeys(Secret secret, string keyID)
		{

			Hashtable htLinkKeys = secret.GetLinkedKeys(keyID);
			if (htLinkKeys != null)
			{
				tsLinkedKeys.Clear();
				IDictionaryEnumerator ienum = (IDictionaryEnumerator)htLinkKeys.GetEnumerator();
				ienum.Reset();
				while (ienum.MoveNext())
				{
					LinkedKeyInfo lki = (LinkedKeyInfo) ienum.Value;
					tsLinkedKeys.AppendValues(lki.GetLinkedSecretID(true), lki.GetLinkedKeyID());
				}
			}
		}

		private void tvAvailableSecrets_ButtonReleaseEvent(object o, ButtonReleaseEventArgs args)
		{
			TreeModel model;
			TreeIter iter;
			string selected=null;
				
			if(tvAvailableSecrets.Selection.GetSelected (out model, out iter))
				selected=(string) model.GetValue (iter, 0);

			tsAvailableKeys.Clear();

			if(selected != null && selected.Length > 0)
			{
				SecretStore ss = GetMiCasaStore();
				Secret secret = ss.getSecret(selected);
				NameValueCollection nvc = secret.getKeyValueCollection();
				for (int i=0; i<nvc.Count; i++)
				{
					// don't allow linking this key to ourself.
					if (labelLinkSecretID.Text.Equals(selected) 
						&& labelLinkKeyID.Text.Equals(nvc.GetKey(i)))
						continue;

					tsAvailableKeys.AppendValues(nvc.GetKey(i), nvc.GetValues(i)[0]);
				}
			}
		}
	
		public void on_buttonLinkAdd_clicked(object obj, EventArgs args)
		{
			TreeModel model;
			TreeIter iter;
			string selectedSecret=null;
				
			if (tvAvailableSecrets.Selection.GetSelected (out model, out iter))
			{
				selectedSecret=(string) model.GetValue (iter, 0);

				TreeModel modelKey;
				TreeIter iterKey;
				string selectedKey=null;
				
				if (tvAvailableKeys.Selection.GetSelected (out modelKey, out iterKey))
				{
					selectedKey = (string) modelKey.GetValue (iterKey, 0);
					//tsLinkedKeys.AppendValues(selectedSecret, selectedKey);

					// add a null terminator to the secretid
					//selectedSecret = selectedSecret + '\0';

					LinkedKeyInfo lki = new LinkedKeyInfo(selectedSecret, selectedKey);
					MiCasaRequestReply.Send(MiCasaRequestReply.VERB_SET_LINKED_KEY, null, labelLinkSecretID.Text, labelLinkKeyID.Text, lki);

					Secret secret = GetMiCasaStore().getSecret(entrySecretID.Text);
					ShowLinkedKeys(secret, labelLinkKeyID.Text);
					AggregateStore();
				}
			}
		}

		public void on_buttonLinkRemove_clicked(object obj, EventArgs args)
		{
			TreeModel model;
			TreeIter iter;
			string selectedSecret=null;
			string selectedKey=null;
			if (tvLinkedKeys.Selection.GetSelected (out model, out iter))
			{
				selectedSecret = (string) model.GetValue(iter,0);
				// add NULL
				//selectedSecret = selectedSecret;
				selectedKey = (string) model.GetValue(iter,1);	
			
				LinkedKeyInfo lki = new LinkedKeyInfo(selectedSecret, selectedKey);
				MiCasaRequestReply.Send(MiCasaRequestReply.VERB_REMOVE_LINKED_KEY, null, labelLinkSecretID.Text, labelLinkKeyID.Text, lki);

				Secret secret = GetMiCasaStore().getSecret(entrySecretID.Text);
				ShowLinkedKeys(secret, labelLinkKeyID.Text);
				AggregateStore();
			}
		}

		private SecretStore GetMiCasaStore()
		{
			if (m_store == null)
				m_store = SecretStore.getInstance();
			
			return m_store;			
		}


		private string sNewKeyValue = null;
		private void entryLinkValue_Changed(object sender, EventArgs e)
		{
			//update the value for this key
			Gtk.Entry entry = (Gtk.Entry)sender;
			sNewKeyValue = entry.Text;

		}

		private void entryLinkValue_LeaveNotifyEvent(object o, LeaveNotifyEventArgs args)
		{
			if (sNewKeyValue != null)
			{
				SecretStore ss = GetMiCasaStore();
				Secret secret = ss.getSecret(labelLinkSecretID.Text);
				secret.setKeyValuePair(labelLinkKeyID.Text, sNewKeyValue);
				ss.setSecret(0, secret, Secret.SS_CREDSET);
				sNewKeyValue = null;
			}
		}
		
		public void on_button32_clicked(object obj, EventArgs args)
		{		
			//string[]  keys	= null,
			
			dialogLinkKeyValue.Destroy();
			/*
			SecretStore ss = GetMiCasaStore();
			bool bHasLinks = false;

			for( int i=0; i< keys.Length; i++ )
			{				
				Secret secret = ss.getSecret(entrySecretID.Text);
				Hashtable ht = secret.GetLinkedKeys(keys[i]);
				if (ht != null && ht.Count > 0)
					bHasLinks = true;
				else
					bHasLinks = false;				
				
				if( (null != keys[i]) && (null != values[i]) )
					if( bHasLinks )
					{
						tsKeyValue.AppendValues(keys[i], values[i], "********", false, "Yes");
					}
					else
					{
						tsKeyValue.AppendValues(keys[i], values[i], "********", false, "No");

					}				
			}*/
			
		}
	/// LINK

	private void md_Response(object o, ResponseArgs args)
	{
		MessageDialog md = (MessageDialog)o;
		if (md != null)
		{
			md.Destroy();			
		}
	}
}
}
///##################################################################
///							END OF FILE
///##################################################################