using System;
using System.Text;
using System.Collections.Specialized;
using Gtk;
using Glade;

using Novell.CASA;
using Novell.SecretStore.NSSSWrapper;

namespace GladeSharp2
{
	/// <summary>
	/// Summary description for Driver.
	/// </summary>
	class Driver
	{
		#region Glade Widgets
	
		[Widget] Gtk.Window window1;
		[Widget] Gtk.TreeView treeview1;	
			
		[Widget] Gtk.Window addSecretWindow;
		[Widget] Gtk.Window displaySecretWindow;
		
		[Widget] Gtk.Entry entrySecretID;
		[Widget] Gtk.Entry entryUsername;
		[Widget] Gtk.Entry entryPassword;
		[Widget] Gtk.Entry entryNDAP;
		[Widget] Gtk.Entry entryLDAP;
		[Widget] Gtk.Entry entryEMAIL;

		[Widget] Gtk.Entry entryLoginUser;
		[Widget] Gtk.Entry entryLoginPassword;
		[Widget] Gtk.Entry entryLoginServer;

		[Widget] Gtk.Label label11;
		[Widget] Gtk.Label label22;

		[Widget] Gtk.Label labelCreated;
		[Widget] Gtk.Label labelAccessed;
		[Widget] Gtk.Label labelModified;

		[Widget] Gtk.TreeView listActivity;
		[Widget] Gtk.TreeView tvKeyValue;
		[Widget] Gtk.Statusbar statusbar1;
		[Widget] Gtk.Image image1;

		[Widget] Gtk.Entry entryHost;
		[Widget] Gtk.Entry entryHostPort;

		[Widget] Gtk.Entry entryServerPort;
		[Widget] Gtk.Label labelServerStatus;

		#endregion
		
		
		Novell.CASA.SecretStore ss = Novell.CASA.SecretStore.getInstance();

		private RemoteStore m_rs = null;
		private bool b_isAuthenticated = false;

		//private RemoteServer m_remoteServer = null;

		TreeStore tsActivityStore;
		TreeIter tIter = new TreeIter();

		// used for secret list
		TreeStore store;
		TreeIter secretIter = new TreeIter();

		private static string SHS_PASSWORD	= "Password";
		private static string SHS_USERNAME	= "Username";
		private static string SHS_OTHER		= "Other";
		private static string SHS_BINARY	= "Binary";
		private static string SHS_CN		= "CN";
		private static string SHS_DN_LDAP	= "DN_LDAP";
		private static string SHS_DN_NDAP	= "DN_NDAP";
		private static string SHS_EMAIL		= "EMAIL";
	
		private DateTime date1970 = new DateTime(1970, 1, 1);
		

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main(string[] args) 
		{
			new Driver(args);
		}


		public Driver(string[] args) 
		{
		    Application.Init();

		    Glade.XML gxml = new Glade.XML (null, "gladesharp1.glade", "window1", null);			
		    gxml.Autoconnect (this);

			treeview1.AppendColumn ("Secrets", new CellRendererText (), "text", 0);
			store = new TreeStore (typeof (string));
			store.SetSortColumnId(0, Gtk.SortType.Ascending);
			treeview1.Model = store;
			
			

			listActivity.AppendColumn("Demo", new CellRendererText (), "text", 0);
			tsActivityStore = new TreeStore (typeof (string));
			listActivity.Model = tsActivityStore;

			logActivity("SecretStore Started");
			//image1.Pixbuf = new Gdk.Pixbuf (null, "./Bitmap.bmp");
			//image1.Pixbuf = "c:/Bitmap.bmp";
			showSecrets();

			// set Network login id
			entryLoginUser.Text = "cn="+getNetworkUserID()+",o=novell";

			// get config
			//System.Configuration.ConfigurationSettings.AppSettings.Set("Jim", "Jim Value");


		    Application.Run();
		}


		private void logActivity(string message)
		{
			tsActivityStore.Append (out tIter);
			tsActivityStore.SetValue (tIter, 0, "[" + DateTime.Now.ToShortTimeString() + "] "+ message);
		}
		// Connect the Signals defined in Glade
		public void on_window1_delete_event (object o, DeleteEventArgs args) 
		{
		    Application.Quit();
		    args.RetVal = true;
		}        
		
		
		#region Button Click Event handlers

		protected void on_toolbutton1_clicked(object o, EventArgs args)
		{
			return;
		}
	
		protected void on_toolbutton2_clicked(object o, EventArgs args)
		{
			FileSelection fDlg = new FileSelection("Choose a File");
			fDlg.Modal = true;
    		
			int nRc = fDlg.Run();
			fDlg.Hide();
    
			if(nRc == (int)ResponseType.Ok) 
			{
			}     
			return;
		}
	
		protected void on_toolbutton3_clicked(object o, EventArgs args)
		{
			Application.Quit();
			return;
		}
	
		#endregion
	
		#region Menu item handlers



		protected void on_quit1_activate(object o, EventArgs args)
		{
			Application.Quit();
			return;
		}

		protected void on_create_sample_credential1_activate(object o, EventArgs args)
		{
			Secret secret = ss.getSecret(0, "SampleCredential", Secret.SS_CREDSET, "");
			secret.setKeyValuePair(SHS_CN,"userCN");
			secret.setKeyValuePair(SHS_DN_LDAP, "cn=admin,o=novell");
			secret.setKeyValuePair(SHS_DN_NDAP, "admin.novell");
			secret.setKeyValuePair(SHS_EMAIL, "admin@novell.com");
			secret.setKeyValuePair(SHS_PASSWORD, "userPassword");

			ss.setSecret(0, secret, Secret.SS_CREDSET);
			showSecrets();
		}


		protected void on_cut1_activate(object o, EventArgs args)
		{
			return;
		}

		protected void on_copy1_activate(object o, EventArgs args)
		{
			return;
		}

		protected void on_delete1_activate(object o, EventArgs args)
		{
			return;
		}

		protected void on_paste1_activate(object o, EventArgs args)
		{
			return;
		}

		protected void on_about1_activate(object o, EventArgs args)
		{
			System.Text.StringBuilder AuthorStringBuild = new System.Text.StringBuilder ();
            
			AuthorStringBuild.Append ("SecretStore Client Version 4.0\n\n");
			AuthorStringBuild.Append ("Sample GUI Application.\n");
			AuthorStringBuild.Append ("Copyright (c) 2004\n\n");
            
			Gtk.MessageDialog md = new Gtk.MessageDialog (
				this.window1,
				DialogFlags.DestroyWithParent,
				MessageType.Info,
				ButtonsType.Ok, 
				AuthorStringBuild.ToString ()
				);
            
			int result = md.Run ();
			md.Hide();
            
			return;
		}

		#endregion

		// Common functions use by buttons and menu items




		public void on_button8_clicked(object o, EventArgs args)
		{
			Console.WriteLine("Sync Called");									
		}

		private void showSecrets()
		{
			store.Clear();
			StringCollection sc = ss.enumerateSecretIDs();
			if (sc != null)
			{
				StringEnumerator se = sc.GetEnumerator();
				se.Reset();
				while (se.MoveNext())
				{
					//listBox2.Items.Add(se.Current);
					store.Append(out secretIter);
					store.SetValue(secretIter, 0, se.Current);
				}
			}
		}

		public void on_button10_clicked (object o, EventArgs args)		
		{

			showSecrets();

			/*
			for (int i=0; i<10; i++)
			{
				store.AppendValues("[ " + System.DateTime.Now.ToString() + " ]");
				treeview1.ShowAll();
				treeview1.Show();
				
				System.Threading.Thread.Sleep(100);
				
			}
			*/
		}

		public void on_btnDeleteSecret_clicked(object o, EventArgs args)
		{
			Console.WriteLine("on_btnDeleteSecret_clicked");
			
			TreeModel model;
			TreeIter iter;
			string selected = "no selection";

			// you get the iter and the model if something is selected
			if (treeview1.Selection.GetSelected (out model, out iter))
				selected = (string) model.GetValue (iter, 0);

			Console.WriteLine (selected);
			ss.removeSecret(selected.Substring(11), 2);
			showSecrets();		
		
		}		

		public void on_btnAddSecret_clicked(object o, EventArgs args)
		{
			Glade.XML gxml = new Glade.XML (null, "gladesharp1.glade", "addSecretWindow", null);				
			gxml.Autoconnect (this);	
			
			addSecretWindow.Show();
		}

		public void on_btnOKAddSecret_clicked(object o, EventArgs args)
		{
			// add this secret
			string sSecretID = entrySecretID.Text;
			if (sSecretID != null && sSecretID.Length > 0)
			{
				string sUsername = entryUsername.Text;
				string sPassword = entryPassword.Text;
				if ((sUsername != null) && (sPassword != null))
				{
					Secret secret = ss.getSecret(0, sSecretID, Secret.SS_CREDSET, "");
					secret.setKeyValuePair(SHS_CN, sUsername);
					secret.setKeyValuePair(SHS_PASSWORD, sPassword);

					// get the rest
					if (entryNDAP.Text != null && entryNDAP.Text.Length > 0)
						secret.setKeyValuePair(SHS_DN_NDAP, entryNDAP.Text);

					if (entryLDAP.Text != null && entryLDAP.Text.Length > 0)
						secret.setKeyValuePair(SHS_DN_LDAP, entryLDAP.Text);

					if (entryEMAIL.Text != null && entryEMAIL.Text.Length > 0)
						secret.setKeyValuePair(SHS_EMAIL, entryEMAIL.Text);



					ss.setSecret(0, secret, Secret.SS_CREDSET);					
					showSecrets();
					addSecretWindow.HideAll();
				}		
			}
			else
			{
				System.Text.StringBuilder AuthorStringBuild = new System.Text.StringBuilder ();
            
				AuthorStringBuild.Append ("You must enter a SecretID\n\n");												
            
				Gtk.MessageDialog md = new Gtk.MessageDialog (
					this.window1,
					DialogFlags.DestroyWithParent,
					MessageType.Warning,
					ButtonsType.Ok, 
					AuthorStringBuild.ToString ()
					);
            
				int result = md.Run ();
				md.Hide();
			}
		}
		public void on_btnCancelAddSecret_clicked(object o, EventArgs args)
		{
			addSecretWindow.HideAll();			
		}

		public void on_btnEditSecret_clicked(object o, EventArgs args)
		{
			// edit the selected secret
			TreeModel model;
			TreeIter iter;
			string selected = null; //"no selection";

			// you get the iter and the model if something is selected
			if (treeview1.Selection.GetSelected (out model, out iter))
				selected = (string) model.GetValue (iter, 0);

			if (selected != null && selected.Length > 0)
			{
				selected = selected.Substring(11);
				Secret secret = ss.getSecret(0, selected, Secret.SS_CREDSET, "");
				Glade.XML gxml = new Glade.XML (null, "gladesharp1.glade", "displaySecretWindow", null);				
				gxml.Autoconnect (this);
				
				TreeStore storeKeyValue = new TreeStore(typeof (string), typeof (string));
				storeKeyValue.SetSortColumnId(0, Gtk.SortType.Ascending);
						
				TreeIter iterKV = new TreeIter();
                        
				NameValueCollection nvc = secret.getKeyValueCollection();
								
				for (int i=0; i<nvc.Count; i++)
				{
					string key = nvc.GetKey(i);
					string[] sValues = nvc.GetValues(key);

					//GLib.Value Key = new GLib.Value (key);
					//GLib.Value Value = new GLib.Value (sValues[0]);
					storeKeyValue.Append (out iterKV);
					storeKeyValue.SetValue (iterKV, 0, key);
					storeKeyValue.SetValue (iterKV, 1, secret.getKeyValue(key));					
				}


				tvKeyValue.AppendColumn("Key", new CellRendererText(), "text", 0);
				tvKeyValue.AppendColumn("Value", new CellRendererText(), "text", 1);			

				tvKeyValue.Model = storeKeyValue;
	
				label22.Text = selected;
				
				DateTime created = date1970.AddSeconds(secret.getCreateTime());
				DateTime mod = date1970.AddSeconds(secret.getModifiedTime());
				DateTime accessTime = date1970.AddSeconds(secret.getAccessTime());
			
				string test = created.ToLongDateString() + " @ " + created.ToLocalTime().ToShortTimeString();
				labelCreated.Text = test;

				labelAccessed.Text = accessTime.ToLocalTime().ToLongDateString()+ " @ " + accessTime.ToLocalTime().ToShortTimeString();
				labelModified.Text = mod.ToLocalTime().ToLongDateString()+ " @ " + mod.ToLocalTime().ToShortTimeString();

				displaySecretWindow.Show();				
			}
		}

		public void on_btnEditSecret1_clicked(object o, EventArgs args)
		{
			// edit the selected secret
			TreeModel model;
			TreeIter iter;
			string selected = "no selection";

			// you get the iter and the model if something is selected
			if (treeview1.Selection.GetSelected (out model, out iter))
				selected = (string) model.GetValue (iter, 0);


			if (selected != null && selected.Length > 0)
			{
				selected = selected.Substring(11);
				Secret secret = ss.getSecret(0, selected, Secret.SS_CREDSET, "");

				Glade.XML gxml = new Glade.XML (null, "gladesharp1.glade", "addSecretWindow", null);				
				gxml.Autoconnect (this);
				
				entrySecretID.Text = selected;
				entrySecretID.Editable = false;
				
				if (secret.getKeyValue("CN") !=null)
					entryUsername.Text = secret.getKeyValue("CN");

				if (secret.getKeyValue("password") !=null)
					entryPassword.Text = secret.getKeyValue("password");

				addSecretWindow.Title = "Edit Secret";
				addSecretWindow.Show();
				
			}
		}

		public void on_btnRemoveAll_clicked(object o, EventArgs args)
		{

			System.Text.StringBuilder AuthorStringBuild = new System.Text.StringBuilder ();
            
			AuthorStringBuild.Append ("Remove All\n\n Are you sure?");												
            
			Gtk.MessageDialog md = new Gtk.MessageDialog (
				this.window1,
				DialogFlags.DestroyWithParent,
				MessageType.Question,
				ButtonsType.YesNo, 
				AuthorStringBuild.ToString ()
				);
            
			int result = md.Run ();
			md.Hide();


			if (result == -8)
			{
				//enum the secrets and remove
				StringCollection sc = ss.enumerateSecretIDs();
				if (sc != null)
				{
					StringEnumerator se = sc.GetEnumerator();
					se.Reset();
					while (se.MoveNext())
					{
						ss.removeSecret(se.Current.Substring(11),2);										
					}
				}
				showSecrets();
			}
		}

		private void getRemoteSecrets()
		{
			if (b_isAuthenticated)
			{
				logActivity("Getting remote secrets");
				string[] saSecrets = m_rs.enumerateSecrets();
				// add these secrets to our local cache
				if (saSecrets != null)
				{
					if (ss == null)
						ss = new SecretStore();

					for (int i=0; i<saSecrets.Length; i++)
					{
						string sSecretID = saSecrets[i].Trim();
						//logActivity("Getting remote secret: "+sSecretID);
						RemoteSecret remoteSecret = m_rs.getSecret(sSecretID);					
						if (remoteSecret != null)
						{		
							// SS_Credset:
							logActivity("Adding remote secret: "+sSecretID);					
							if (sSecretID.StartsWith("SS_Cred") || sSecretID.StartsWith("SS_App"))
							{
								Secret localSecret;
								int iSecretType = Secret.SS_BINARY;
								if (sSecretID.StartsWith("SS_Cred"))
								{
									localSecret = ss.getSecret(0, saSecrets[i].Trim().Substring(11), Secret.SS_CREDSET, null);
									iSecretType = Secret.SS_CREDSET;
								}
								else
								{
									localSecret = ss.getSecret(0, saSecrets[i].Trim().Substring(10), Secret.SS_APP, null);
									iSecretType = Secret.SS_APP;
								}

								localSecret.mergeKeyValueCollection(remoteSecret.getKeyValueCollection());
								ss.setSecret(0, localSecret, iSecretType);
							}
							else
							{
								logActivity("Retrieved unhandled secret: "+sSecretID);
							}
						}										
						else
							logActivity("Secret not found: "+sSecretID);
					}			
					showSecrets();
				}
			}
			else
			{
				logActivity("User not authenticated to remote store");
				displayError("You are not authenticated to remote store");
			}

		}


		public void on_btnLogin_clicked(object o, EventArgs args)
		{
			if (!b_isAuthenticated)
			{
				
				statusbar1.Push(1, "Authenticating to server please wait");
				System.Threading.Thread.Sleep(100);


				m_rs = RemoteStore.getInstance();
				string host = entryLoginServer.Text.Trim();
				string userId = entryLoginUser.Text.Trim();
				string password = entryLoginPassword.Text.Trim();
				logActivity("Authenticating to "+host);
				
				try
				{
					m_rs.connect(host, userId, password, "");
				}
				catch (Exception e)
				{
					displayError(e.ToString());
					return;
				}

				//logActivity("Authenticated!");

				b_isAuthenticated = true;
				statusbar1.Push(1, "Authenticated to "+ host);
				logActivity("Authenticated");
				Gtk.Button login = (Gtk.Button)o;
				login.Label = "Logout";


				label11.LabelProp = "<b>Server Information -- Authenticated </b>";
				//label11.Text = "<b>Server Information</b> -- Authenticated to Server";
				getRemoteSecrets();
			}
			else
			{
				// logout
				b_isAuthenticated = false;
				Gtk.Button login = (Gtk.Button)o;
				label11.LabelProp = "<b>Server Information</b>";
				login.Label = "Login";
				statusbar1.Push(1, "Logged out");
				
			}
		}

		public void on_btnRefreshRemote_clicked(object o, EventArgs args)
		{
			getRemoteSecrets();
			showSecrets();
		}


		private void displayMessage(string message, MessageType messageType)
		{
			System.Text.StringBuilder AuthorStringBuild = new System.Text.StringBuilder ();
            
			AuthorStringBuild.Append (message);												
            
			Gtk.MessageDialog md = new Gtk.MessageDialog (
				this.window1,
				DialogFlags.DestroyWithParent,
				MessageType.Warning,
				ButtonsType.Ok, 
				AuthorStringBuild.ToString ()
				);
            
			int result = md.Run ();
			md.Hide();
		}

		private void displayMessageInfo(string message)
		{
			displayMessage(message, MessageType.Info);
		}
		private void displayError(string message)
		{
			displayMessage(message, MessageType.Warning);
		}

		private void on_btnSyncFromServer_clicked(object o, EventArgs args)
		{
			getRemoteSecrets();
		}
		private void on_btnClearActivity_clicked(object o, EventArgs args)
		{
			tsActivityStore.Clear();
		}

		private void on_btnSync2Server_clicked(object sender, EventArgs args)
		{
			if (b_isAuthenticated)
			{
				// get local secrets
				StringCollection sc = ss.enumerateSecretIDs();
				if (sc != null)
				{
					StringEnumerator se = sc.GetEnumerator();
					se.Reset();
					while (se.MoveNext())
					{

						string sID = se.Current;

						if (sID.StartsWith("SS_CredSet:"))
						{				
							sID = sID.Substring(sID.IndexOf(":") + 1);
							//type = Secret.SS_CREDSET;
						}

						Secret localSecret = ss.getSecret(0, sID, 2, null);
										
						RemoteSecret rs = new RemoteSecret(sID, 0, 0 ,0);
						rs.setKeyValueCollection(localSecret.getKeyValueCollection());
						if (m_rs != null)
						{
							m_rs.setSecret(rs);
							logActivity("Sending " + se.Current + " to server");
						}
					}
				}
			}

		}

		protected void on_btnServerStartStop_clicked(object o, EventArgs args)
		{

			Gtk.Button btn = (Gtk.Button)o;
			/*
			if (m_remoteServer == null)
			{
				m_remoteServer = new RemoteServer();


				try 
				{
					int iPort = Int32.Parse(entryServerPort.Text);
					m_remoteServer.startServer(iPort);
					labelServerStatus.Text = "Running";
				}
				catch (Exception e)
				{
					displayError("Port in use\r\n"+ e.ToString());
					return;
				}

				logActivity("Server started on port: "+entryServerPort.Text);
				btn.Label = "Stop Server";
			}
			else
			{
				m_remoteServer.stopServer();
				btn.Label = "Start Server";
				logActivity("Server stopped");
				labelServerStatus.Text = "Stopped";
				m_remoteServer = null;
			}
			*/
		}

		protected void on_btnGetRemoteSecrets_clicked(object o, EventArgs args)
		{

			RemoteClient rc = new RemoteClient();

			if ((entryHost.Text == null) || (entryHost.Text.Length < 1))
			{
				displayError("Please enter a Remote computer ");
				return;
			}
			
			
			try 
			{
				rc.openSocket(entryHost.Text, entryHostPort.Text);
			}
			catch (Exception e)
			{
				displayError(e.ToString());
				return;
			}

			try 
			{
				StringCollection sc = rc.getRemoteSecretIDS();

				if (sc != null)
				{
					StringBuilder sb = new StringBuilder();
					sb.Append("The following secrets were added:\r\n");
					StringEnumerator se = sc.GetEnumerator();
					se.Reset();
					while (se.MoveNext())
					{
						logActivity("Retrieved "+se.Current+" from " + entryHost.Text);
						Secret remoteSecret = rc.getRemoteSecret(se.Current);
						sb.Append(se.Current+"\r\n");

						// add it to our local cache
						Secret localSecret = ss.getSecret(se.Current);
						localSecret.mergeKeyValueCollection(remoteSecret.getKeyValueCollection());
						ss.setSecret(0, localSecret, localSecret.getSecretType());
					}

					displayMessageInfo(sb.ToString());
				}
			}
			catch (Exception e)
			{
				displayError(e.ToString());
			}

			rc.closeSocket();
			showSecrets();
		}

		private string getNetworkUserID()
		{

			Secret sec = ss.getSecret("SS_Cred:Default_Credential");
			string sUsername = sec.getKeyValue("CN");

			if (sUsername == null || sUsername.Length < 1)
			{
				sUsername = System.Environment.UserName.ToString();
	
			}
			return sUsername;
		}
	}
}