/***********************************************************************
 * 
 *  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 System.Collections.Specialized;
using Novell.CASA.DataEngines.Common;
using Novell.CASA.CASAPolicy;
#if LINUX
using Novell.CASA.GUI;
#endif

namespace Novell.CASA.DataEngines 
{

    public class AD 
    {

       private miCASAEngine micasaengine;
#if LINUX
       private GKEngine gkEngine = null;
       private KWalletEngine  kwEngine = null; 
#endif
       private AggregationPol aggPol;
   

       public AD()
       {
         // Always Aggregate miCASA. 
          micasaengine =  new miCASAEngine();
#if LINUX
          kwEngine = new KWalletEngine();
          gkEngine = new GKEngine();
#endif
/*
   
         // Reading Policy to see what else needs to be Aggregated.
         aggPol = (AggregationPol) ICASAPol.GetPolicy(CASAPolType.AGGREGATION_POL);
         if (aggPol != null ) 
         { 
        	ArrayList stores = aggPol.StoreList;
        	IEnumerator enumerator = stores.GetEnumerator();
  
        	while(enumerator.MoveNext())
         	{
                	string storeID = (((Store)(enumerator.Current)).StoreName);

                	if(storeID.Equals(ConstStrings.KW))
                	{ 
                        	Logger.DbgLog("A-D Lib: KWallet Set up for Aggregation");
                     		kwEngine = new KWalletEngine(); 
                	} 
               		else if(storeID.Equals(ConstStrings.GK))
                	{
                     		Logger.DbgLog("A-D Lib:Gnome Keyring Set up for Aggregation");
                    		 gkEngine = new GKEngine(); 
                	} 
         	// Console.WriteLine("StoreName = " + ((Store)(enumerator.Current)).StoreName + "StoreId = " + ((Store)(enumerator.Current)).StoreId);
         	}
        }  
 */
 
      }
     
       public XmlDocument Aggregate()
       {
#if LINUX
            gkEngine = null;
            kwEngine = null;
#endif
           //Read the Policy Just before you aggregate
           
           // Reading Policy to see what else needs to be Aggregated.
           aggPol = (AggregationPol) ICASAPol.GetPolicy(CASAPolType.AGGREGATION_POL);
           if (aggPol != null )
           {
                ArrayList stores = aggPol.StoreList;
                IEnumerator enumerator = stores.GetEnumerator();

                while(enumerator.MoveNext())
                {
                        string storeID = (((Store)(enumerator.Current)).StoreName);

#if LINUX
                        if(storeID.Equals(ConstStrings.KW))
                        {
                                Logger.DbgLog("A-D Lib: KWallet Set up for Aggregation");
                                kwEngine = new KWalletEngine();
                        }
                        else if(storeID.Equals(ConstStrings.GK))
                        {
                                Logger.DbgLog("A-D Lib:Gnome Keyring Set up for Aggregation");
                                 gkEngine = new GKEngine();
                        }
#endif
                // Console.WriteLine("StoreName = " + ((Store)(enumerator.Current)).StoreName + "StoreId = " + ((Store)(enumerator.Current)).StoreId);
                }
          }
  
        

           XmlDocument ccf = new XmlDocument();    
           XmlElement elem = ccf.CreateElement("CCF");
           ccf.AppendChild(elem);

           // TBD: Lookup Policy here and maybe send it via constructors
           XmlNode micasaEnum  =  micasaengine.Aggregate();  
           if (micasaEnum != null) //Atleast <miCASA> should come incase of no secrets
           {
           	XmlNode gotit = ccf.ImportNode(micasaEnum,true);
           	ccf.DocumentElement.AppendChild(gotit);
           }
           else
           {
                // Null comes only when it failed to talk to miCASA.   
#if LINUX
				Logger.DbgLog("A-D Lib:Failed to Connect to miCASA");
#endif
           }

#if LINUX
           if (gkEngine != null)
           {
          	 XmlNode gkSecrets = gkEngine.Aggregate();
	         if( null != gkSecrets )
	         {
        	     XmlNode gkImportedNode = ccf.ImportNode(gkSecrets,true);
	             ccf.DocumentElement.AppendChild(gkImportedNode);
	         }
	         else
        	 {
		      Logger.DbgLog("A-D Lib:Failed to Connect to Gnome Keyring");

	         }
           }


           if(kwEngine != null )
           {
           	XmlNode KwEnum  =  kwEngine.Aggregate();
	        if (KwEnum != null) //Atleast <KWallet> should come incase of no secrets
	        {
	             XmlNode kwImported = ccf.ImportNode(KwEnum,true);
	             ccf.DocumentElement.AppendChild(kwImported);
        	}
	        else
        	{
	             // Null comes only when it failed to talk to Kwallet.
		      Logger.DbgLog("A-D Lib:Failed to Connect to KWallet");
	        }
           }

#endif


           return ccf;
                    
       }



       /********************************************************************************
        Modifying a Secret

	SetSecret will modify the Value(s) of a Key(s) for an  existing secret
	SetSecret will also add new secrets

	public int SetSecret(XmlNode secret, int StoreID)

	Parameters

	secret : Secrets XMLNode
         1. If a  Key node of a secret is missing then that key will be deleted
         2. For Gnome keyring, Key having Id "GkPassword" cannot be deleted as
            Gnome Api's do not allow it.
         3. All Time nodes for a Secret need not be passed as they cannot be set.
         4. Keyring attributes have a fixed datatype of Int and String. 
            Currently we support only String types. To support int types CCF needs to be modified accordingly.
         5. SetSecret overloaded method, without the opnType parameter, is not supported for GnomeKeyring

	opnType : Operation Type
          ConstStrings.OPERATION_ADD_SECRET
          ConstStrings.OPERATION_MODIFY_SECRET

	StoreID : int value
          Novell.CASA.DataEngines.Common.ConstStrings.CASA_STORE_KWALLET  = 3;
          Novell.CASA.DataEngines.Common.ConstStrings.CASA_STORE_GK  = 4

	Returns
	  An Error code or 0 if operation is successfull.
        *********************************************************************************/

       public int SetSecret(XmlNode secret, int opnType, int StoreID)
       {
            if (StoreID == ConstStrings.CASA_STORE_MICASA)
                   return micasaengine.SetSecret(secret, opnType);
#if LINUX
            if (StoreID == ConstStrings.CASA_STORE_KWALLET)
                   return kwEngine.SetSecret(secret, opnType);
            if (StoreID == ConstStrings.CASA_STORE_GK)
                   return gkEngine.SetSecret(secret, opnType);
#endif
            else
            {
#if LINUX
                Logger.DbgLog("A-D Lib:Failed to Set Secret in to  miCASA");
#endif
                return -1;

            }

       }



       /********************************************************************************
        Modifying a Secret

        SetSecret will modify the Value(s) of a Key(s) for an  existing secret
        SetSecret will also add new secrets

        public int SetSecret(XmlNode secret, int StoreID)

        Parameters

        secret : Secrets XMLNode
         1. If a  Key node of a secret is missing then that key will be deleted
         2. For Gnome keyring, Key having Id "GkPassword" cannot be deleted as
            Gnome Api's do not allow it.
         3. All Time nodes for a Secret need not be passed as they cannot be set.
         4. Keyring attributes have a fixed datatype of Int and String.
            Currently we support only String types. To support int types CCF needs to be modified accordingly.

        StoreID : int value
          Novell.CASA.DataEngines.Common.ConstStrings.CASA_STORE_KWALLET  = 3;
          Novell.CASA.DataEngines.Common.ConstStrings.CASA_STORE_GK  = 4

        Returns
          An Error code or 0 if operation is successfull.
        *********************************************************************************/

       public int SetSecret(XmlNode secret, int StoreID)
       {
            if (StoreID == ConstStrings.CASA_STORE_MICASA)
                   return micasaengine.SetSecret(secret);
#if LINUX
            if (StoreID == ConstStrings.CASA_STORE_KWALLET)
                   return kwEngine.SetSecret(secret);
            if (StoreID == ConstStrings.CASA_STORE_GK)
                   return gkEngine.SetSecret(secret);
#endif
            else
            {
#if LINUX
                Logger.DbgLog("A-D Lib:Failed to Set Secret in to  miCASA");
#endif
                return -1;

            }

       }


       public  int GetSecret(XmlNode secret, int StoreID)
       {
           
           //TBD: Check for Store ID and call the right DataEngine.
           if (StoreID == ConstStrings.CASA_STORE_MICASA)
	           return micasaengine.GetSecret(secret);
           else
           { 
#if LINUX
              Logger.DbgLog("A-D Lib: Failed to Get Secret in to  miCASA");
#endif
               return -1;
           }
       }


	/*******************************************************************************
	Remove will delete a Secret.

	public int Remove(XmlNode secret, int StoreID)


	Parameters

	secret : Secrets XmlNode
        	 1. This node will be deleted from its parent.


	StoreID : int value
        	  Novell.CASA.DataEngines.Common.ConstStrings.CASA_STORE_KWALLET  = 3;
	          Novell.CASA.DataEngines.Common.ConstStrings.CASA_STORE_GK  = 4


	Returns
		An Error code or 0 if operation is successfull. 

	*********************************************************************************/
      
       public int Remove(XmlNode secret, int StoreID)
       {
           
	    if (StoreID == ConstStrings.CASA_STORE_MICASA)
                   return micasaengine.Remove(secret);
#if LINUX
            if (StoreID == ConstStrings.CASA_STORE_KWALLET)
                   return kwEngine.Remove(secret);
            if (StoreID == ConstStrings.CASA_STORE_GK)
                   return gkEngine.Remove(secret);
#endif
            return -1;
       }  
         
       public int AggregateStore(XmlDocument outDoc, int StoreID)
       {
           // This need not be policy aware. GUI knows what its doing.

           XmlNode secEnum;
           DataEngine engine;         

           XmlNode toproot =  outDoc.DocumentElement;
           if (toproot == null)
           {
                XmlElement elem = outDoc.CreateElement("CCF");
                outDoc.AppendChild(elem);
           }

           if ( StoreID  == ConstStrings.CASA_STORE_MICASA )    // If its miCASA
           { 
               engine =  micasaengine;
               secEnum = engine.Aggregate();
               if (secEnum != null )
               {
                   XmlNode root = outDoc.DocumentElement;
                   XmlNodeList miCASANodes = root.SelectNodes("descendant::miCASA");
                  // Console.WriteLine("ADLIB: Count is " + miCASANodes.Count);
                   if (miCASANodes.Count !=  0) // If there is something remove it
                   {
                        root.RemoveChild(miCASANodes[0]);
                   }
                   XmlNode gotit = outDoc.ImportNode(secEnum,true);
                   root.AppendChild(gotit);
                   return  ConstStrings.CASA_SUCCESS;
               }
               else
                   return  ConstStrings.CASA_STORE_NOT_AVAILABLE;
           } 
#if LINUX
           else if( StoreID == ConstStrings.CASA_STORE_GK )
           {
                  gkEngine = new GKEngine();
               	  secEnum = gkEngine.Aggregate();
              	  if (secEnum != null )
               	  {
                     	  XmlNode root = outDoc.DocumentElement;
	                  XmlNodeList gkNode = root.SelectNodes("descendant::GK");
        	          if (gkNode.Count !=  0) // If there is something remove it
                	  {
	                  	root.RemoveChild(gkNode[0]); 
        	          }
	                  XmlNode gkImportNode = outDoc.ImportNode(secEnum,true);
        	          root.AppendChild(gkImportNode);
                	  return  ConstStrings.CASA_SUCCESS;
                 }
                 else
                   return  ConstStrings.CASA_STORE_NOT_AVAILABLE;
              
           }
           else if(StoreID == ConstStrings.CASA_STORE_KWALLET)
           {
                      kwEngine = new KWalletEngine();
	       	       secEnum = kwEngine.Aggregate();
	               if (secEnum != null )
        	       {
                   		XmlNode root = outDoc.DocumentElement;
	                	XmlNodeList gkNode = root.SelectNodes("descendant::KWallet");
                                if (gkNode.Count !=  0) // If there is something remove it
  	                        {
        		        	root.RemoveChild(gkNode[0]);
                                } 
 		                XmlNode kwImportNode = outDoc.ImportNode(secEnum,true);
 		                root.AppendChild(kwImportNode);
 		                return  ConstStrings.CASA_SUCCESS;
               	       }
                       else
                       {
                          //Console.WriteLine("KWallet some issue");
 	                  return  ConstStrings.CASA_STORE_NOT_AVAILABLE;
                       }

           } 

           Logger.DbgLog("A-D Lib: Unknown Operation Requested");
#endif           
           return ConstStrings.CASA_OPERATION_FAILED;
       }

       public int InitAD()
       {

           return ConstStrings.CASA_SUCCESS;
       }


       public int CleanUP_AD()
       {

           return ConstStrings.CASA_SUCCESS;
       }		
    }
}