using System;
using System.Data;
using System.Collections;
using System.Configuration;
using System.Collections.Generic;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml;
using System.IO;
using System.Xml.Serialization;
using digioz;

namespace digioz
{
    public class XML : IDataNonRelational
    {
        public PortalSettings coPortalSettings;

        public XML(PortalSettings poPortalSettings)
        {
            coPortalSettings = poPortalSettings;
        }

        public void openEntity()
        {

        }
        public void closeEntity()
        {

        }
        public object GetEntity(int piID)
        {
            object loObject = null;
            string[] lsFiles = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory + "App_Data\\", piID.ToString() + "_*.xml");
            if (lsFiles.Length > 1)
            {
                throw new ApplicationException("Duplicated Entity ID. ID = " + piID.ToString());
            }
            else if (lsFiles.Length == 0)
            {
                throw new ApplicationException("Invalid Entity ID. ID = " + piID.ToString());
            }
            else
            {
                FileStream loStream = new FileStream(lsFiles[0], FileMode.Open);
                StreamReader loReader = new StreamReader(loStream);
                string lsType = Path.GetFileNameWithoutExtension(lsFiles[0]);
                lsType = lsType.Substring(lsType.IndexOf("_") + 1);
                loObject = this.DeserializeObject(loReader.ReadToEnd(), Type.GetType(lsType));
            }

            return loObject;
        }

        public object GetEntity(string psEntityName, int piID)
        {
            object loObject = null;
            string[] lsFiles = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory + "App_Data\\", piID.ToString() + "_" + psEntityName + ".xml");

            if (lsFiles.Length > 1)
            {
                throw new ApplicationException("Duplicated Entity ID. ID = " + piID.ToString());
            }
            else if (lsFiles.Length == 0)
            {
                throw new ApplicationException("Invalid Entity ID. ID = " + piID.ToString());
            }
            else
            {
                FileStream loStream = new FileStream(lsFiles[0], FileMode.Open);
                StreamReader loReader = new StreamReader(loStream);
                string lsType = Path.GetFileNameWithoutExtension(lsFiles[0]);
                lsType = lsType.Substring(lsType.IndexOf("_") + 1);
                loObject = this.DeserializeObject(loReader.ReadToEnd(), Type.GetType(lsType));
            }

            return loObject;
        }

        public IEnumerable GetEntity(string psEntityName)
        {
            object loObject = null;
            List<object> loObjects = new List<object>();            
            string[] lsFiles = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory + "App_Data\\", "*._" + psEntityName + ".xml");

            for (int i = 0; i < lsFiles.Length; i++)
            {
                FileStream loStream = new FileStream(lsFiles[0], FileMode.Open);
                StreamReader loReader = new StreamReader(loStream);
                string lsType = Path.GetFileNameWithoutExtension(lsFiles[0]);
                lsType = lsType.Substring(lsType.IndexOf("_") + 1);
                loObject = this.DeserializeObject(loReader.ReadToEnd(), Type.GetType(lsType));
                loObjects.Add(loObject);
            }

            return loObjects;
        }

        public bool SaveEntity(object poObject)
        {
            bool retval = false;
            if (poObject != null)
            {
                // Get ID either from the poObject, or next ID.
                int liID = this.GetIDFromObject(poObject);
                if (liID == -1)
                {
                    liID = this.GetNextID();
                    poObject.GetType().InvokeMember("ID", System.Reflection.BindingFlags.SetProperty, null, poObject, new object[] {liID});
                }

                // Get xml.
                string lsXML = this.SerializeObject(poObject, poObject.GetType());

                // Get a file name.            
                string lsFileName = this.CreateXmlFileName(liID, poObject.GetType());

                // Save xml into the file
                FileStream loStream = new FileStream(lsFileName, FileMode.Create);
                StreamWriter loWriter = new StreamWriter(loStream);
                loWriter.Write(lsXML);
                loWriter.Close();
                loStream.Close();

                retval = true;
            }
            return retval;
        }

        public bool DeleteEntity(object poObject)
        {
            bool retval = false;
            if (poObject != null)
            {
                int liID = this.GetIDFromObject(poObject);
                if (liID == -1)
                {
                    throw new ApplicationException("Cannot delete entity " + poObject.GetType() + " which has an invalid ID.");
                }
                string lsFile = this.CreateXmlFileName(liID, poObject.GetType());                               
                File.Delete(lsFile);                                
                retval = true;
            }
            return retval;
        }

        public bool DeleteEntity(string psEntityName, int piID)
        {
            return false;
        }

        public bool CreateEntity(object poObject)
        {
            bool retval = false;
            this.SaveEntity(poObject);
            retval = true;
            return retval;
        }

        public int GetNextID()
        {
            // Open a file to get the next ID.
            string lsFileName = System.AppDomain.CurrentDomain.BaseDirectory + "App_Data\\count.txt";            
            FileStream loStream = new FileStream(lsFileName,FileMode.Open);
            StreamReader loReader = new StreamReader(loStream);
            int liCount = 1 + int.Parse(loReader.ReadLine());
            loReader.Close();
            loStream.Close();

            // Overwrite the file with the new ID.
            loStream = new FileStream(lsFileName, FileMode.Create);
            StreamWriter loWriter = new StreamWriter(loStream);
            loWriter.WriteLine(liCount.ToString());
            loWriter.Flush();
            loWriter.Close();
            
            return liCount;
        }

        public string SerializeObject(object poObject, Type poType)
        {
            XmlSerializer loXmlSerializer = new XmlSerializer(poType);
            StringWriter loSW = new StringWriter();
            loXmlSerializer.Serialize(loSW, poObject);
            string lsSerializedXml = loSW.ToString();

            return lsSerializedXml;
        }

        public object DeserializeObject(string psString, Type poType)
        {
            XmlSerializer loXmlSerializer = new XmlSerializer(poType);
            object loDeserializedXml;
            loDeserializedXml = (object)loXmlSerializer.Deserialize(new StringReader(psString));

            return loDeserializedXml;
        }

        private string CreateXmlFileName(int piID, Type poType)
        {
            return System.AppDomain.CurrentDomain.BaseDirectory + "App_Data\\" + piID.ToString() + "_" + poType.ToString() + ".xml";
        }

        // If poObject.ID is not null and bigger than zero, returns ID; otherwise -1.
        private int GetIDFromObject(object poObject)
        {
            int liID = -1;
            object loID = poObject.GetType().InvokeMember("ID", System.Reflection.BindingFlags.GetProperty, null, poObject, null);
            if (loID != null)
            {           
                liID = (int)loID;
                if (liID < 1)
                {
                    liID = -1;
                }
            }
            return liID;
        }

        //void test()
        //{
        //    Class1 loClass1Object1 = new Class1();
        //    loClass1Object1.csProperty1 = "Value1";

        //    string lsSerializedXml = SerializeObject(loClass1Object1, typeof(class1));
        //    class1 loClass1Object2 = (class1)DeserializeObject(lsSerializedXml, typeof(class1));
        //}
    }
}
