using System;
using System.Collections;
using System.Xml;
using System.IO;
using Novell.CASA;
using Novell.CASA.DataEngines.Common;
using System.Collections.Specialized;
using System.Runtime.InteropServices;
using Novell.CASA.DataEngines.KWallet;




namespace Novell.CASA.DataEngines
{

   /*
    * This class is implementation of Data engine for KWallet.
    */


    class KWalletEngine : DataEngine
    {

      string[] EntryTypes = {"Binary","Passwords","Unknown", "Maps"};   


       public KWalletEngine()
       {
           // TBD: Read Policy information and have a list of wallet names;

       }

       public XmlNode Aggregate()
       {
              XmlDocument doc = new XmlDocument();
              Hashtable lookup  = new Hashtable();
              XmlElement key1;
              XmlAttribute Atr;
              XmlElement value1;
              XmlAttribute idAttr;
              String secid, val;
              XmlElement currentWallet;
              XmlElement Folder;
              XmlElement Type;
              XmlElement Secret;
              String walletName, foldername, entryType, secretval;

              

             //Adding Kwallet Top Node
 	     XmlElement elem = doc.CreateElement(ConstStrings.CCF_KW);
             doc.AppendChild(elem);
                  
             EnumSecretList enumList = new EnumSecretList();
	     //kwallet.Try(enumList);
	     kwallet.AggregateKW(enumList);
             EnumSecretList tempEnumSecretList1 = enumList;

             //This can be Null only when nothing is aggregated.
             if (((String)Marshal.PtrToStringAnsi(tempEnumSecretList1.walletName)) == null ) 
             {
                  //TBD: Log that there are no secrets to aggregate
             }
             else // Something to Aggregate
             { 
                          
                         
             while (tempEnumSecretList1 != null)
	     {
			walletName = (String)Marshal.PtrToStringAnsi(tempEnumSecretList1.walletName);
		       // Console.WriteLine("\n\nWallet name is***#  : "+walletName);

		        foldername = (String)Marshal.PtrToStringAnsi(tempEnumSecretList1.folderName);
		        //Console.WriteLine("\tFolder***# : "+foldername);
                        int entrytype = tempEnumSecretList1.entryType;
		        //Console.WriteLine("\t\tEntryType ***#: "+entrytype);
                        entryType = EntryTypes[entrytype]; 
		        //Console.WriteLine("\t\tEntryType in string ***#: "+entryType);
                   
		        secretval = (String)Marshal.PtrToStringAnsi(tempEnumSecretList1.secretVal);
		        //Console.WriteLine("\t\tSecret***# : "+secretval);

                        //Adding Wallet
                        if (lookup.ContainsKey(walletName))
                        {
				//Console.WriteLine("Wallet Node found");
                                currentWallet = (XmlElement)lookup[walletName];
                        }
                        else
                        {       
                                currentWallet = doc.CreateElement(ConstStrings.CCF_WALLET);
                                idAttr = doc.CreateAttribute(ConstStrings.CCF_ID);
                                idAttr.Value = walletName;
                                currentWallet.SetAttributeNode(idAttr);
                                elem.AppendChild(currentWallet);
				lookup.Add(walletName,currentWallet);
                        }

                        //Adding Folder
                        String xpath = "descendant::Folder[@Name='"+foldername+"']";
                        XmlNodeList folList = currentWallet.SelectNodes(xpath);
                        if (folList.Count == 0)
                        {
                                 Folder = doc.CreateElement(ConstStrings.CCF_FOLDER);
                                 XmlAttribute name_attr = doc.CreateAttribute(ConstStrings.CCF_NAME);
                                 name_attr.Value = foldername;
                                 Folder.SetAttributeNode(name_attr);
                                 currentWallet.AppendChild(Folder);
                                         
                         } 

                                
                        //Adding Type   
                        xpath = "descendant::Folder";
                        XmlNodeList folderlist = currentWallet.SelectNodes(xpath);

                        foreach(XmlNode folder in folderlist)
                        {
                        	XmlAttributeCollection atcol =  folder.Attributes;
                                XmlAttribute attr = atcol[ConstStrings.CCF_NAME];
                                if (attr.InnerXml.Equals(foldername))
                                {
                                	xpath = "descendant::Type[@ID='"+entryType+"']"; 
                                        XmlNodeList keylist = folder.SelectNodes(xpath);
                                        if (keylist.Count == 0)
                                	{
                                             	 Type = doc.CreateElement(ConstStrings.CCF_TYPE);
	                                         XmlAttribute name_attr = doc.CreateAttribute(ConstStrings.CCF_ID);
                	                         name_attr.Value = entryType;
		                                 Type.SetAttributeNode(name_attr);
	                                         folder.AppendChild(Type);

                                        }
                                        else
                                        {
                                         //Console.WriteLine("Type Already Added");
                                        }    

                                 }
                                      
                        }



                       //Adding the Secret
                       xpath = "descendant::Folder";
                       folderlist = currentWallet.SelectNodes(xpath); 
                              
                       foreach(XmlNode folder in folderlist)
                       {
                       		XmlAttributeCollection atcol =  folder.Attributes;
                                XmlAttribute attr = atcol[ConstStrings.CCF_NAME];
                                if (attr.InnerXml.Equals(foldername))
                                {
                                	xpath = "descendant::Type[@ID='"+entryType+"']";
                                        XmlNodeList keylist = folder.SelectNodes(xpath);
                                        if (keylist.Count == 0)
                                        {
                                                 //Console.WriteLine("Construction of CCF Failed");
                                        }
                                        else
                                        {
                                        	XmlNode TargetType = folder;
                                                string[] split = null; 
                                               
                                                int index = secretval.IndexOf('=');
                                                secid = secretval.Substring(0,index);


                                                Secret = doc.CreateElement(ConstStrings.CCF_SECRET);
                                                XmlAttribute  idattr = doc.CreateAttribute(ConstStrings.CCF_ID);
                                                idattr.Value = secid;
                                                Secret.SetAttributeNode(idattr);


	                                        if (entryType.Equals("Maps"))
        	                                {
                                                    string delim = ";";
                                                    char[] delimiter = delim.ToCharArray();
                                                    string realval = secretval.Substring(index+1);
                                                    
                                                    for(int x = 1; x < 10 ; x++)
                                                    {
							split = realval.Split(delimiter, x);	
                                                    }
                                                    foreach(string s in split)	
                                                    { 
                                                        int ix; 
							string key;
							string value;  
                                                          
							//Console.WriteLine("The val is :" + s);
                                                        if (s.Equals(""))
                                                        { 
                                                                //Console.WriteLine("No Secret Content for a Secret ID");  
								key = " ";
								value = " ";
                                                        }
                                                        else
                                                        {
								ix = s.IndexOf(':');
                                                       		key = s.Substring(0,ix);
								value = s.Substring(ix+1);

                                                        }  

                                                        key1 = doc.CreateElement(ConstStrings.CCF_KEY);
                                                        Atr = doc.CreateAttribute(ConstStrings.CCF_ID);
                                                        Atr.Value = key;
                                                        key1.SetAttributeNode(Atr);
                                                        
                                                         //Value
                                                        value1 = doc.CreateElement(ConstStrings.CCF_VALUE);
                                                        value1.InnerText = value;
                                                        key1.AppendChild(value1);
                                                        Secret.AppendChild(key1);


                                 
                                                       TargetType.AppendChild(Secret);

                                                        
                                                     
                                                    }

                	                        }
                        	                else if (entryType.Equals("Passwords"))
                                	        {

                                                	//Console.WriteLine("Passwords");
	                                                val = secretval.Substring(index+1);
                                              
	
        	                                        //Key
                	                                key1 = doc.CreateElement(ConstStrings.CCF_KEY);
                        	                        Atr = doc.CreateAttribute(ConstStrings.CCF_ID);
                                	                Atr.Value = "Credential";
                                        	        key1.SetAttributeNode(Atr);
	
        	                                       //Value
                	                               value1 = doc.CreateElement(ConstStrings.CCF_VALUE);
                        	                       value1.InnerText = val;
                                	               key1.AppendChild(value1);
                                        	       Secret.AppendChild(key1);

     		                                       TargetType.AppendChild(Secret);


                                               }
                                    }
                                 }
                          }

                              

        	       if (tempEnumSecretList1.next == IntPtr.Zero)
		       {
		         // Console.WriteLine("Reached End ##");
	        	  break;
		       }

        	       tempEnumSecretList1 = (EnumSecretList)Marshal.PtrToStructure(tempEnumSecretList1.next, typeof(EnumSecretList));

	      }
              }
       kwallet.FreeResources();   
       return doc.ChildNodes[0];


       }




	public  int SetSecret(XmlNode secret)
	{
		return ConstStrings.CASA_SUCCESS;
        }





        public  int GetSecret(XmlNode secret)
        {
        	return ConstStrings.CASA_SUCCESS;
        }


         
        public  int Remove(XmlNode secret)
        {
               return ConstStrings.CASA_SUCCESS;
        }




    }
}