using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using DevExpress.XtraBars.Docking;
using Pixel.Modular.Engine.Data;
using PXP.Crawler.API.Data;
using NodePinDirPXP.Crawler.API.Utils;
using PXP.Crawler.API.Utils;

namespace NodePinDirPXP.Crawler.API.Utils
{
    [Serializable]
    public class Sett : IDisposable
    {       
        private string fileName = "settings.xml";

        private SettDataSet settDataSet = new SettDataSet();

        private bool autoSave = false;

        public Sett()
        {
            autoSave = false;
        }

        public void Dispose()
        {
            if (settDataSet != null)
            {
                settDataSet.Dispose();
                settDataSet = null;
            }
        }

        public Sett(bool auto)
        {
            autoSave = auto;
        }

        public void SetSett(string propName, string val)
        {
            SetSett("general", propName, val, new byte[0]);
        }

        public void SetSett(string propName, byte[] valData)
        {
            SetSett("general", propName, "", valData);
        }

        public void SetSett(string setName, string propName, string val, byte[] valData = null)
        {
            DataRow[] fsRows = settDataSet.SettingsSet.Select("Name = '" + setName + "'");
            SettDataSet.SettingsSetRow ssRow = null;

            if (valData == null)
                valData = new byte[0];
            
            if (fsRows.Length == 0)
            {
                fsRows = new DataRow[]
                             {
                                 settDataSet.SettingsSet.AddSettingsSetRow(setName)
                             };
            }

            if (fsRows.Length == 1)
            {
                ssRow = (SettDataSet.SettingsSetRow)fsRows[0];
                bool propFound = false;
                SettDataSet.SettingsRow psRow = null;
                foreach (SettDataSet.SettingsRow sRow in ssRow.GetSettRows())
                {
                    if (sRow.Name == propName)
                    {
                        //v = sRow.Value;
                        propFound = true;
                        psRow = sRow;
                        break;
                    }
                }

                if (propFound)
                {
                    psRow.Value = val;
                    psRow.DataValue = valData;
                } else
                {
                    psRow = settDataSet.Settings.AddSettingsRow(propName, val, ssRow, valData);
                }

                if (autoSave)
                {
                    settDataSet.AcceptChanges();
                    settDataSet.WriteXml(fileName, XmlWriteMode.IgnoreSchema);                    
                }
            }
        }

        public byte[] GetSettData(string settName)
        {
            return GetSettData("general", settName);
        }

        public byte[] GetSettData(string settName, string propName)
        {
            DataRow[] fsRows = settDataSet.SettingsSet.Select("Name = '" + settName + "'");
            SettDataSet.SettingsSetRow ssRow = null;
            if (fsRows.Length == 1)
            {
                ssRow = (SettDataSet.SettingsSetRow)fsRows[0];
                foreach (SettDataSet.SettingsRow sRow in ssRow.GetSettRows())
                {
                    if (sRow.Name == propName)
                    {
                        return sRow.DataValue;                        
                    }
                }
            }

            return new byte[0];
        }

        public string GetSett(string propName, string defaultValue)
        {
            return GetSett("general", propName, defaultValue);
        }

        public string GetSett(string settName, string propName, string defaultValue)
        {
            string v = defaultValue;

            DataRow[] fsRows = settDataSet.SettingsSet.Select("Name = '" + settName + "'");
            SettDataSet.SettingsSetRow ssRow = null;
            if (fsRows.Length == 1)
            {
                ssRow = (SettDataSet.SettingsSetRow) fsRows[0];
                foreach (SettDataSet.SettingsRow sRow in ssRow.GetSettRows())
                {
                    if (sRow.Name == propName)
                    {
                        v = sRow.Value;
                        break;
                    }
                }
            }

            return v;
        }

        public string SerializeXml()
        {
            StringBuilder sb = new StringBuilder();
            StringWriter sw = new StringWriter(sb, CultureInfo.InvariantCulture);
            settDataSet.WriteXml(sw);
            sw.Close();
            return sb.ToString();
        }

        public void Save(ref StringWriter writer)
        {
            try
            {
                settDataSet.WriteXml(writer, XmlWriteMode.IgnoreSchema);
                //settDataSet.WriteXml(filePath, XmlWriteMode.IgnoreSchema);
            }
            catch (Exception exc)
            {

            }
        }

        public void Save(string filePath)
        {
            if (File.Exists(filePath))
                File.Delete(filePath);

            try
            {
                settDataSet.WriteXml(filePath, XmlWriteMode.IgnoreSchema);                
            } catch(Exception exc)
            {
                
            }
        }

        public void Load(byte[] data)
        {
            settDataSet.Clear();
            MemoryStream ms = new MemoryStream(data);            
            TextReader tr = new StreamReader(ms);
            settDataSet.ReadXml(tr, XmlReadMode.IgnoreSchema);
            tr.Dispose();
            ms.Dispose();
        }

        public void Load(string filePath)
        {
            settDataSet.Clear();

            if (File.Exists(filePath))
                settDataSet.ReadXml(filePath, XmlReadMode.IgnoreSchema);
            
            fileName = filePath;
        }

        public void Load()
        {
            if (File.Exists(fileName))
                settDataSet.ReadXml(fileName, XmlReadMode.IgnoreSchema);
        }

        public void LoadObject(object obj, string objName)
        {
            DataRow[] fsRows = settDataSet.SettingsSet.Select("Name = '" + objName + "'");
            SettDataSet.SettingsSetRow ssRow = null;
            if (fsRows.Length == 1)
            {
                ssRow = (SettDataSet.SettingsSetRow)fsRows[0];

                Type cType = obj.GetType();

                foreach (SettDataSet.SettingsRow sRow in ssRow.GetSettRows())
                {
                    PropertyInfo pi = cType.GetProperty(sRow.Name);
                    if (pi != null)
                    {
                        object initObj = null;
                        object tval;
                        if (pi.PropertyType.Name == "ObjectTransform")
                        {
                            initObj = pi.GetValue(obj, new object[0]);
                        }
                        //    tval = Misc.GetObjectFromData(sRow.DataValue, pi.PropertyType, initObj);
                        //} else
                        //{
                            if (sRow.Value == "_od" && sRow.DataValue.Length > 0)
                            {
                                tval = Misc.GetObjectFromData(sRow.DataValue, pi.PropertyType, initObj);
                            } else
                            {
                                tval = Misc.GetObjectFromString(sRow.Value, pi.PropertyType, initObj);                                
                            }
                        //}
                        
                        if (tval != null)
                        {
                            if (pi.CanWrite)
                            {
                                pi.SetValue(obj, tval, new object[0]);                                
                            } else
                            {
                                Debug.WriteLine("Object Load: Could no assign property: " + pi.Name);
                            }
                        }
                    }
                }
            }
        }

        public void LoadControl(Control cont)
        {
            LoadObject(cont, cont.Name);           
        }

        public void SaveObject(object obj, string objName, string[] propNames)
        {
            DataRow[] fsRows = settDataSet.SettingsSet.Select("Name = '" + objName + "'");
            SettDataSet.SettingsSetRow ssRow = null;
            if (fsRows.Length == 1)
            {
                ssRow = (SettDataSet.SettingsSetRow)fsRows[0];
            } else
            {
                ssRow = settDataSet.SettingsSet.AddSettingsSetRow(objName);
            }

            foreach (SettDataSet.SettingsRow tsRow in ssRow.GetSettRows())
            {
                tsRow.Delete();
            }

            settDataSet.AcceptChanges();

            Type cType = obj.GetType();

            foreach (string propName in propNames)
            {
                PropertyInfo pi = cType.GetProperty(propName);
                if (pi != null)
                {
                    SettDataSet.SettingsRow sRow;
                    switch (pi.PropertyType.Name)
                    {
                        case "Point":
                            sRow = settDataSet.Settings.AddSettingsRow(pi.Name, Misc.GetStringFromValue(pi.GetValue(obj, new object[0])), ssRow, new byte[0]);
                            break;
                        case "Size":
                            sRow = settDataSet.Settings.AddSettingsRow(pi.Name, Misc.GetStringFromValue(pi.GetValue(obj, new object[0])), ssRow, new byte[0]);
                            break;
                        case "FormWindowState":
                            sRow = settDataSet.Settings.AddSettingsRow(pi.Name, pi.GetValue(obj, new object[0]).ToString(), ssRow, new byte[0]);
                            break;
                        case "Boolean":
                            sRow = settDataSet.Settings.AddSettingsRow(pi.Name, pi.GetValue(obj, new object[0]).ToString(), ssRow, new byte[0]);
                            break;
                        case "String":
                            sRow = settDataSet.Settings.AddSettingsRow(pi.Name, pi.GetValue(obj, new object[0]).ToString(), ssRow, new byte[0]);
                            break;
                        case "Int64":
                        case "Int32":
                            sRow = settDataSet.Settings.AddSettingsRow(pi.Name, pi.GetValue(obj, new object[0]).ToString(), ssRow, new byte[0]);
                            break;
                        case "Single":
                            float cv = (float)pi.GetValue(obj, new object[0]);
                            sRow = settDataSet.Settings.AddSettingsRow(pi.Name, "_od", ssRow, Conv.SingleData(cv));
                            break;
                        case "Color":
                            Color ccv = (Color)pi.GetValue(obj, new object[0]);
                            sRow = settDataSet.Settings.AddSettingsRow(pi.Name, ccv.ToArgb().ToString(), ssRow, new byte[0]);
                            break;
                        default:
                            break;
                    }                    
                }
            }

            if (autoSave)
                settDataSet.WriteXml(fileName, XmlWriteMode.IgnoreSchema);
        }        

        public void SaveControl(Control cont, string[] propNames)
        {
            SaveObject(cont, cont.Name, propNames);           
        }

        public static DockPanel FindDockPanel(Control cont)
        {
            if (cont is DockPanel)
                return (DockPanel)cont;

            if (cont.Parent != null)
                return FindDockPanel(cont.Parent);

            return null;
        }

        public static string GetDataSetXmlString(DataSet dataSet)
        {
            StringBuilder sb = new StringBuilder();
            TextWriter tw = new StringWriter(sb);
            dataSet.WriteXml(tw, XmlWriteMode.IgnoreSchema);
            tw.Dispose();
            return sb.ToString();
        }        
    }
}
