/***********************************************************************
 * 
 *  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.Text;
using System.Collections;

using Novell.CASA.MiCasa.Common;

namespace sscs.cache
{
    public class KeyValue
    {
		public static int VALUE_TYPE_STRING = 0;
		public static int VALUE_TYPE_BINARY = 1;

		private int m_iValueType = VALUE_TYPE_STRING;

        private string m_key;
        public string Key
        {
            get
            {
                return m_key;
            }
            set
            {
                m_key = value;
            }
        }
        private byte[] m_value;

        public string GetValue()
        {
            return (DecryptValue());
        }

		public byte[] GetValueAsBytes()
		{
			return (DecyptValueAsBytes());
		}

		// this sets string values
        public void SetValue(string sValue)
        {
            
			string oldValue = DecryptValue();
			
            if (oldValue.Equals(sValue))
                return;
            else
            {                    
				byte[] newEncryptedValue = EncryptValue(sValue);
                m_value = newEncryptedValue;
                m_modified = DateTime.Now;
            }
        }

		// this sets binary values
		public void SetValue(byte[] baValue)
		{
			m_iValueType = VALUE_TYPE_BINARY;
			m_value = EncryptValue(baValue);
			m_modified = DateTime.Now;
		}

        /*
        public string Value
        {
            get
            {
                // decrypt
                return (DecryptValue());
            }
            set
            {
                byte[] newEncrypteValue = EncryptValue(value);

                if ((newEncrypteValue != null) && (newEncrypteValue.Equals(m_value)))
                    return;
                else
                {                    
                    m_value = newEncrypteValue;
                    m_modified = DateTime.Now;
                }
            }
        }
        */


	private Hashtable mLinkedKeys = null; // = new Hashtable();

		public void AddLink(LinkedKeyInfo linkedInfo)
		{
			if (mLinkedKeys == null)
				mLinkedKeys = new Hashtable();

                        if(!mLinkedKeys.ContainsKey(linkedInfo.GetLinkID()))
  			    mLinkedKeys.Add(linkedInfo.GetLinkID(), linkedInfo);
		}

		public void RemoveLink(string sLinkID)
		{
			// remove link
			if (mLinkedKeys != null)
			{
				mLinkedKeys.Remove(sLinkID);
			}
		}

		public Hashtable GetLinkedKeys()
		{
			return mLinkedKeys;
		}

	private DateTime m_dtEncryptTime = DateTime.Now;
    private DateTime m_created;
    public DateTime CreatedTime
    {
        get
        {
            return m_created;
        }
    }

    private DateTime m_modified;
    public DateTime ModifiedTime
    {
        get
        {
            return m_modified;
        }
    }
        

        public KeyValue(string sKey, string sValue)
        {
            // NOTE: Order is important, do not change
            m_created = m_modified = DateTime.Now;
            m_key =  sKey;
            m_value = EncryptValue(sValue);                        
        }

		public KeyValue(string sKey, byte[] baValue)
		{
			// NOTE: Order is important, do not change
			m_created = m_modified = DateTime.Now;
			m_key =  sKey;
			m_value = EncryptValue(baValue);                       
			m_iValueType = VALUE_TYPE_BINARY;
		}

        private byte[] EncryptValue(string sValue)
        {
            byte[] baValueClear = Encoding.Default.GetBytes(sValue);                        
            return EncryptValue(baValueClear);
        }

		private byte[] EncryptValue(byte[] baValueClear)
		{
			// set encrypttime
			m_dtEncryptTime = DateTime.Now;
			return (XORValue(baValueClear));
		}

        private string DecryptValue()
        {            
            byte[] baValueClear = DecyptValueAsBytes();
            return Encoding.Default.GetString(baValueClear);                                    
        }
				
		private byte[] DecyptValueAsBytes()
		{
			return XORValue(m_value);
		}

		private byte[] XORValue(byte[] baInput)
		{            			
			byte[] baOutput = new byte[baInput.Length];			            
			Random ranNum = new Random(this.Key.GetHashCode());
			for (int i=0; i<baInput.Length; i++)
			{								
				baOutput[i] = (byte)((int)baInput[i] ^ ranNum.Next() ^ (~i) ^ m_dtEncryptTime.Ticks);
			}        					
			return baOutput;
		}

		public int GetValueType()
		{
			return m_iValueType;
		}

        public string ToXML()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<ENTRY>");
            
            sb.Append("<KEY>");
            sb.Append(m_key);
            sb.Append("</KEY>");

            sb.Append("<VALUE>");
            sb.Append(m_value);
            sb.Append("</VALUE>");

            sb.Append("<MODIFIED>");
            sb.Append(m_modified.Ticks);
            sb.Append("</MODIFIED>");

            sb.Append("</ENTRY>");
            
            return sb.ToString();
        }
    }
}