/***********************************************************************
 * 
 *  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.
 * 
 ***********************************************************************/

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



namespace Novell.CASA.DataEngines
{

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

    //TBD: Generally we need to find out if fault is in parameter or miCASA or not available

    class miCASAEngine : DataEngine
    {

     public SecretStore store = null;

       public miCASAEngine()
       {

             //TBD: What happens here at miCASA end ?
             store = SecretStore.getInstance();
       }

       public XmlNode Aggregate()
       {

              XmlDocument doc = new XmlDocument();
              XmlElement key1;
              XmlAttribute Atr;
              XmlElement value1;
              XmlElement mi_secret;
              XmlAttribute synchAttr;
              XmlAttribute secidAttr;
              String sKey, sValue;


              //Adding miCASA Top Node
              XmlElement elem = doc.CreateElement(ConstStrings.miCASA);
              doc.AppendChild(elem);


              StringCollection sc = store.enumerateSecretIDs();
              if (sc != null)
              {
                     // Adding Keychain
                     XmlElement keychain = doc.CreateElement(ConstStrings.CCF_KEYCHAIN);
                     XmlAttribute id_attr = doc.CreateAttribute(ConstStrings.CCF_ID);
                     id_attr.Value = ConstStrings.CCF_KEYCHAINNAME;
                     keychain.SetAttributeNode(id_attr);
                     elem.AppendChild(keychain);


                     StringEnumerator se = sc.GetEnumerator();
                     se.Reset();

                     while (se.MoveNext())
                     {

                        Secret secret = store.getSecret(se.Current);
                        NameValueCollection nvc = secret.getKeyValueCollection();

                        mi_secret = doc.CreateElement(ConstStrings.CCF_SECRET);
                        synchAttr = doc.CreateAttribute(ConstStrings.CCF_SYNCH);
                        //TBD:
                        synchAttr.Value = "Persistent Secret" ;
                        secidAttr = doc.CreateAttribute(ConstStrings.CCF_ID);
                        secidAttr.Value = se.Current;
                        mi_secret.SetAttributeNode(secidAttr);
                        mi_secret.SetAttributeNode(synchAttr);


                        for (int i = 0; i < nvc.Count; i++)
                        {

                               sKey = nvc.GetKey(i);
                               sValue = nvc.Get(sKey);

                                //Key
                                key1 = doc.CreateElement(ConstStrings.CCF_KEY);
                                Atr = doc.CreateAttribute(ConstStrings.CCF_ID);

                                Atr.Value = sKey;
                                key1.SetAttributeNode(Atr);

                                //Value
                                value1 = doc.CreateElement(ConstStrings.CCF_VALUE);
                                value1.InnerText = sValue;

                                key1.AppendChild(value1);

                                mi_secret.AppendChild(key1);

                        }

/*
                       //Time
                       XmlElement Time1 = doc.CreateElement(ConstStrings.CCF_TIME);

                       XmlElement zone1 = doc.CreateElement(ConstStrings.CCF_ZONE);
                       zone1.InnerText = "IST";

                       XmlElement cr1 = doc.CreateElement(ConstStrings.CCF_CRTIME);
                       cr1.InnerText = null;

                       XmlElement mod1 = doc.CreateElement(ConstStrings.CCF_MDTIME);
 	               mod1.InnerText = null;

                       XmlElement acc1 = doc.CreateElement(ConstStrings.CCF_ACTIME);
                       acc1.InnerText = null;

                       Time1.AppendChild(zone1);
                       Time1.AppendChild(cr1);
                       Time1.AppendChild(mod1);
                       Time1.AppendChild(acc1);

                       mi_secret.AppendChild(Time1);
*/

                      //Finally Add Secret to Elem
                       keychain.AppendChild(mi_secret);

                     }
              }



              return doc.ChildNodes[0];


       }

       internal bool KeyInNewList(NameValueCollection nvc, string key)
       {
           if (nvc != null)
           {
               for (int i = 0; i < nvc.Count; i++)
               {
                   string sKey = nvc.GetKey(i);
                   if( key == sKey )
                       return true;
                }
            }
            return false;
       }

    public  int SetSecret(XmlNode secret, int opnType)
    {
	return SetSecret(secret);

    }

    public  int SetSecret(XmlNode secret)
       {

            XmlAttributeCollection atcol =  secret.Attributes;
            String secretid = atcol["ID"].InnerXml;
            Secret secretVal = store.getSecret(secretid);

            NameValueCollection nvc = secretVal.getKeyValueCollection();
            ArrayList existingKeyList;
         
            if (nvc.Count == 0)
            {
                existingKeyList = null;
            }
            else
            {
                existingKeyList = new ArrayList();
            }

            for(int i = 0; i < nvc.Count; i++ )
            {
                existingKeyList.Add(nvc.GetKey(i));
            }

            XmlNodeList keylist = secret.SelectNodes("descendant::Key");

            NameValueCollection newNVC = new System.Collections.Specialized.NameValueCollection();

            foreach (XmlNode tuple in keylist)
            {
                   //Get the Key
                   XmlAttributeCollection at = tuple.Attributes;
                   String keyname = (at["ID"]).InnerText;
                   newNVC.Add(keyname, tuple.ChildNodes[0].InnerText);                              
            }

            if(null != existingKeyList)
            {
                IEnumerator etor = existingKeyList.GetEnumerator();
                while( etor.MoveNext() )
                {
                    string key = (string)etor.Current;
                    if(KeyInNewList(newNVC,key) == false)
                    {
                        secretVal.removeKey(key,0);                    
                    }
                }
            }
            for(int i = 0 ; i < newNVC.Count ; i++)
            {
                string key = newNVC.GetKey(i);
                secretVal.setKeyValuePair(key,newNVC.Get(key));
            }

			// TBD: Return Value ??
 	    store.setSecret(0, secretVal, Secret.SS_CREDSET);

            return ConstStrings.CASA_SUCCESS;

       }





       public  int GetSecret(XmlNode secret)
       {
              XmlDocument doc;
              XmlElement key1;
              XmlAttribute Atr;
              XmlElement value1;
              XmlElement mi_secret;
              XmlAttribute synchAttr;
              XmlAttribute secidAttr;
              String sKey, sValue;



               XmlAttributeCollection atcol =  secret.Attributes;
               String secretid = atcol["ID"].InnerXml;

               Secret secretVal = store.getSecret(secretid);
               NameValueCollection nvc = secretVal.getKeyValueCollection();

               if (nvc.Count == 0)
               {
               	     //Console.WriteLine("Secret got deleted, ID is " + secretid) ;
               	     return ConstStrings.CASA_DATA_UNAVAILABLE;
               }
               else
               {
                     //Console.WriteLine("Got the secret from miCASA.");
                     doc = secret.OwnerDocument;
                     XmlNode root = secret.ParentNode;
                     XmlNode keychain = secret.ParentNode;

                     // Delete the Secret Node.
                     root.RemoveChild(secret);

                     mi_secret = doc.CreateElement(ConstStrings.CCF_SECRET);
               	     synchAttr = doc.CreateAttribute("Synch");
                     synchAttr.Value = "Persistent Secret";
                     secidAttr = doc.CreateAttribute(ConstStrings.CCF_ID);
                     secidAttr.Value = secretid;
                     mi_secret.SetAttributeNode(secidAttr);
                     mi_secret.SetAttributeNode(synchAttr);

                     for (int i = 0; i < nvc.Count; i++)
                     {

                                sKey = nvc.GetKey(i);
                                sValue = nvc.Get(sKey);

                                 //Key
                                 key1 = doc.CreateElement(ConstStrings.CCF_KEY);
                                 Atr = doc.CreateAttribute(ConstStrings.CCF_ID);
                                 Atr.Value = sKey;
                                 key1.SetAttributeNode(Atr);

                                 //Value
                                 value1 = doc.CreateElement(ConstStrings.CCF_VALUE);
                                 value1.InnerText = sValue;

                                 key1.AppendChild(value1);

                                 mi_secret.AppendChild(key1);

                                 //Console.WriteLine(sKey + " = " + sValue);
                         }


                        //Time
                        XmlElement Time1 = doc.CreateElement(ConstStrings.CCF_TIME);

                        XmlElement zone1 = doc.CreateElement(ConstStrings.CCF_ZONE);
                        zone1.InnerText = "IST";

                        XmlElement cr1 = doc.CreateElement(ConstStrings.CCF_CRTIME);
                        cr1.InnerText = null;

                        XmlElement mod1 = doc.CreateElement(ConstStrings.CCF_MDTIME);
                       mod1.InnerText = null;

                        XmlElement acc1 = doc.CreateElement(ConstStrings.CCF_ACTIME);
                        acc1.InnerText = null;

                        Time1.AppendChild(zone1);
                        Time1.AppendChild(cr1);
                        Time1.AppendChild(mod1);
                        Time1.AppendChild(acc1);

                        mi_secret.AppendChild(Time1);

                        //Finally Add Secret to Elem
                        keychain.AppendChild(mi_secret);


                      return ConstStrings.CASA_SUCCESS;
               }



       }


         
        public  int Remove(XmlNode secret)
        {

               XmlAttributeCollection atcol =  secret.Attributes;
               String secretid = atcol["ID"].InnerXml;

               //TBD: Why no other overloaded API
               store.removeSecret(secretid.Substring(secretid.IndexOf(":")+1), Secret.SS_CREDSET);


               XmlNode root = secret.ParentNode;
               root.RemoveChild(secret);
        
               return ConstStrings.CASA_SUCCESS;

            
        }




    }
}