using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Xml;

namespace FileManager
{
    //#define RootClassName  "XMLData"
    //#define XMLClassEndTag  std::string("</")+RootClassName+">"
    //#define Empty_String  std::string("")

    public interface Convertinterface
    {
        void Serialize(bool isStoring, XmlDocument xml, XmlNode rootNode);
    }

    public class MemberBase
    {
        const string RootClassName = "XMLData";
        const string XMLClassEndTag = "</" + RootClassName + ">";
        const string Empty_String = "";

        protected string m_sValue;
        //public virtual ~MemberBase() { };
        public virtual void Dispose() { }
        public string toString() { return m_sValue; }
        //public const char* c_str() { return m_sValue.c_str(); }
        public string getStringPtr(string str) { return m_sValue = str; }     //c++原代码为：std::string *getStringPtr() { return &m_sValue; }; 
    }
    /**
		serializable string
	*/
    public class xString : MemberBase
    {
        public void AssignValue(string value) { m_sValue = value; }           //因为c#无=重载，所以修改为public
        public xString() { }
        public xString(string value) { AssignValue(value); }
        public string value() { return m_sValue; }
        //public xString operator=(const string value) { AssignValue(value); return *this; }  //c#不可以重载=
        //public xString operator=(const char* value) { AssignValue(value); return *this; }  //c#不可以重载=
    }

    public class xInt : MemberBase
    {
        public void AssignValue(int value) { m_sValue = value.ToString(); }        //因为c#无=重载，所以修改为public
        public xInt() { AssignValue(0); }
        public xInt(int value) { AssignValue(value); }
        public int value()
        {
            int value;
            value = int.Parse(m_sValue);
            return value;
        }
        //xInt operator=(const int value) { AssignValue(value); return *this; };  //c#不可以重载=
    }

    public class xDouble : MemberBase
    {
        public void AssignValue(double value) { m_sValue = value.ToString(); }       //因为c#无=重载，所以修改为public
        public xDouble() { AssignValue(0); }
        public xDouble(double value) { AssignValue(value); }
        public double value()
        {
            double value;
            value = double.Parse(m_sValue);
            return value;
        }
        //xDouble operator=(const double value) { AssignValue(value); return *this; }; //c#不可以重载=
    }

    public class xLong : MemberBase
    {
        public void AssignValue(long value) { m_sValue = value.ToString(); }   //因为c#无=重载，所以修改为public            public xLong() { AssignValue(0); }
        public xLong(long value) { AssignValue(value); }
        public long value()
        {
            long value;
            value = long.Parse(m_sValue);
            return value;
        }
        //xLong operator=(const long value) { AssignValue(value); return *this; };  //c#不可以重载=
    }

    public class xDWORD : MemberBase
    {
        public void AssignValue(uint value) { m_sValue = value.ToString(); }    //因为c#无=重载，所以修改为public
        public xDWORD() { AssignValue(0); }
        public xDWORD(uint value) { AssignValue(value); }
        public uint value()
        {
            uint value;
            value = uint.Parse(m_sValue);
            return value;
        }
        //xDWORD operator=(const DWORD value) { AssignValue(value); return *this; };
    }

    public class xBool : MemberBase
    {
        public void AssignValue(bool value) { m_sValue = value ? "true" : "false"; }       //因为c#无=重载，所以修改为public
        public xBool() { AssignValue(false); }
        public xBool(bool value) { AssignValue(value); }

        public bool value()
        {
            bool value = false;
            string sHelp = m_sValue;
            //transform(sHelp.GetEnumerator(), sHelp.end(), sHelp.GetEnumerator(), toupper);
            sHelp=sHelp.ToUpper();
            if (sHelp == "TRUE")
                return true;
            return value;
        }
        //xBool operator=(const bool value) { AssignValue(value); return *this; };
    }

    public class xTime_t : MemberBase   //time_t对应c#类型？long?
    {
        public void AssignValue(DateTime value)     //因为c#无=重载，所以修改为public
        {
            m_sValue = value.ToString();
        }

        public xTime_t()
        {
            DateTime t = Convert.ToDateTime(null);
            AssignValue(t);
        }

        public xTime_t(DateTime value) { AssignValue(value); }

        public DateTime value()
        {
            return Convert.ToDateTime(m_sValue);
        }
        //xTime_t operator=(const time_t value) { AssignValue(value); return *this; };
    }

    //   class __declspec(dllexport) xOleDateTime : public MemberBase  //COleDateTime对应c#类型？统一改为time_t
    //  {
    //   {
    //      private:
    //	       void AssignValue(const COleDateTime value);
    //      public:
    //	       xOleDateTime() { };
    //         xOleDateTime(COleDateTime value) { AssignValue(value); };
    //         COleDateTime value();
    //         xOleDateTime operator=(const COleDateTime value) { AssignValue(value); return *this; };
    //   };

    public class xOleDateTimeSpan : MemberBase   //COleDateTimeSpan对应c#类型？TimeSpan?
    {
        public void AssignValue(TimeSpan value)        //因为c#无=重载，所以修改为public
        {
            m_sValue = value.ToString();
        }
        public xOleDateTimeSpan()
        {
            TimeSpan timeSpan = DateTime.Now - DateTime.Now;
            AssignValue(timeSpan);
        }
        public xOleDateTimeSpan(TimeSpan value) { AssignValue(value); }

        public TimeSpan value()
        {
            return TimeSpan.Parse(m_sValue);
        }

        //xOleDateTimeSpan operator=(const COleDateTimeSpan value) { AssignValue(value); return *this; };
    };

    public class xRect : MemberBase
    {
        public void AssignValue(Rect value, int shape = 1)        //因为c#无=重载，所以修改为public
        {
            //Rect x = new Rect();

            // domain text body
            string strDomainTextBody = "";
            // value 1 -- shape
            string strValue = "";

            // value 2 -- center x
            // domain center
            int centerX = (int)(value.Left + value.Right) / 2;
            strValue = centerX.ToString();

            strDomainTextBody += strValue + ",";
            // value 3 -- center y
            int centerY = (int)(value.Top + value.Bottom) / 2;
            strValue = centerY.ToString();
            strDomainTextBody += strValue + ",";

            if (shape == 0)
            {
                // value 4 -- diameter
                int diameter = (int)value.Width;
                strValue = diameter.ToString();
                strDomainTextBody += strValue + ",";
                // value 5 -- 0
                strDomainTextBody += "0";
            }
            else
            {
                // value 4 -- width
                int width = (int)value.Width;
                strValue = width.ToString();
                strDomainTextBody += strValue + ",";
                // value 5 -- height
                int height = (int)value.Width;
                strValue = height.ToString();
                strDomainTextBody += strValue;
            }

            // return domain text body
            m_sValue = strDomainTextBody;
        }

        public xRect()  //xRect() { AssignValue(0); };???
        {
            Rect value = new Rect();
            value.X = 0;
            value.Y = 0;
            value.Width = 1;
            value.Height = 1;
            AssignValue(value, 1);
        }

        xRect(Rect value, int shape) { AssignValue(value, shape); }

        void SplitString(string s, ref List<string> v, string c)
        {
            string[] sArray = System.Text.RegularExpressions.Regex.Split(s, c, System.Text.RegularExpressions.RegexOptions.None);
            foreach (string i in sArray)
                v.Add(i);
        }
        public Rect value()
        {
            Rect rectangle = new Rect();
            List<string> point = new List<string>();

            SplitString(m_sValue, ref point, ",");

            rectangle.X = int.Parse(point[0]);
            rectangle.Y = int.Parse(point[1]);
            rectangle.Width = Math.Abs(int.Parse(point[0]) + int.Parse(point[2]));
            rectangle.Height = Math.Abs(int.Parse(point[1]) + int.Parse(point[3]));
            return rectangle;
        }
    }

    public class xPoint : MemberBase
    {
        public void AssignValue(System.Drawing.Point value)             //因为c#无=重载，所以修改为public
        {
            int X = value.Y;
            int Y = value.Y;
            string OutString;
            string sX = X.ToString();
            string sY = Y.ToString();
            OutString = sX + "," + sY;
            m_sValue = OutString;
        }
        xPoint()
        {
            System.Drawing.Point value = new System.Drawing.Point();
            value.X = 0;
            value.Y = 0;
            AssignValue(value);
        }
        xPoint(System.Drawing.Point value) { AssignValue(value); }
        void SplitString(string s, ref List<string> v, string c)
        {
            string[] sArray = System.Text.RegularExpressions.Regex.Split(s, c, System.Text.RegularExpressions.RegexOptions.None);
            foreach (string i in sArray)
                v.Add(i);
        }
        System.Drawing.Point value()
        {
            System.Drawing.Point p = new System.Drawing.Point();
            List<string> point = new List<string>();
            SplitString(m_sValue, ref point, ",");

            p.X = int.Parse(point[0]);
            p.Y = int.Parse(point[1]);

            return p;
        }

    };


    //typedef std::map<std::string, CollectionBase*>::iterator __declspec(dllexport) CollectionIterator;  ???
    public abstract class CollectionBase<ISlo>
    {
        private string m_sCollectionName;
        private string m_sCollectionClassType;
        public CollectionBase() { m_sCollectionName = ""; m_sCollectionClassType = ""; }
        public List<ISlo> m_vCollection = new List<ISlo>(); //vector<ISlo*> m_vCollection;  ISlo*转??

        public SortedDictionary<ISlo, bool> m_mOwner = new SortedDictionary<ISlo, bool>();   //map<ISlo*, bool> ？？
        public void setCollectionName(string value) { m_sCollectionName = value; }
        public void setCollectionClassType(string value) { m_sCollectionClassType = value; }
        public abstract ISlo newElement();
        public string getCollectionName() { return m_sCollectionName; }
        public int size() { return m_vCollection.Count(); }
        public ISlo getItem(int itemID) { return m_vCollection[itemID]; }
        public void Clear()
        {
            if (m_vCollection.Count() > 0)
            {
                m_vCollection.Clear();
            }
        }
    }

    public class Collection<T> : CollectionBase<ISlo>
    {
        /**
        create new element of type T
        @return empty object of type T
        */
        public override ISlo newElement()
        {
            T newItem = System.Activator.CreateInstance<T>();
            //T newItem = default(T);
            object temp = newItem;
            ISlo sIo = (ISlo)temp;

            //Slo sIo = new Slo();
            m_vCollection.Add(sIo);
            //I change this value to be false forever(gsp).No matter what case there's no need to set the object's owner to the collection
            //after we created the object we'll put them to in a smartpointer.then the smartpointer will manage it.
            //m_mOwner[sIo] = false;//m_mOwner[newItem]=true 
            //Type type = newItem.GetType();
            return sIo;
        }

        public void addItem(T item)
        {
            object temp = item;
            ISlo sIo = (ISlo)temp;
            m_vCollection.Add(sIo);/* m_mOwner[item] = false;*/
        }

        public T getItem(int itemID)
        {
            object temp = m_vCollection[itemID];
            T item = (T)temp;
            return item;
        }
    };

    public abstract class ISlo : Convertinterface
    {
        public abstract void Serialize(bool isStoring, XmlDocument xml, XmlNode rootNode);

        //virtual ~ISlo() = default;
    }

    //typedef std::vector<Slo*>::iterator  __declspec(dllexport) SerializableIterator;  //iterator？

    public class Slo : ISlo
    {
        //private (Slo const &s) { }
        //private Slo operator=(Slo const &s) { return *this; };

        public string strReplaceAll(string source, string searchFor, string replaceWith)
        {
            if ((searchFor == null) || (searchFor == ""))
            {
                return source;
            }
            source.Replace(searchFor, replaceWith);
            return source;
        }

        public string m_sXML;
        public string m_sClassName;
        public string m_sVersion;
        public SortedDictionary<string, MemberBase> m_AttributeMappings = new SortedDictionary<string, MemberBase>();
        public SortedDictionary<string, ISlo> m_MemberMappings = new SortedDictionary<string, ISlo>();
        public SortedDictionary<string, CollectionBase<ISlo>> m_MemberCollections = new SortedDictionary<string, CollectionBase<ISlo>>();

        public void setClassName(string ClassName) { m_sClassName = ClassName; }
        public Slo()
        {
            m_sClassName = null;
            m_sVersion = null;
            m_sXML = null;
            m_AttributeMappings.Clear();
            m_MemberMappings.Clear();
            m_MemberCollections.Clear();
        }

        /**
         Register a member
         @MemberName XML-Description/Name for the member
         @Member Member to register
         @return void
        */
        public void Register(string MemberName, MemberBase Member)  // public void Register(string MemberName, MemberBase Member, string DefaultValue)  DefaultValue无引用，c#无自动补充功能，故方法调整为双参数
        {
            m_AttributeMappings[MemberName] = Member;
        }

        /**
        Register a member-subclass
        @MemberName XML-Description/Name for the member-class
        @Member Member-class to register
        @return void
        */
        public void Register(string MemberName, ISlo Member)
        {
            m_MemberMappings[MemberName] = Member;
        }

        /**
         Register a class-collection
         @CollectionName XML-Description/Name for the collection
         @SubclassCollection Collection to register
         @return void
        */
        public void Register(string CollectionName, CollectionBase<ISlo> SubclassCollection)
        {
            SubclassCollection.setCollectionName(CollectionName);
            m_MemberCollections[CollectionName] = SubclassCollection;
        }

        public override void Serialize(bool isStoring, XmlDocument xml, XmlNode rootNode)
        {
            if (isStoring)
            {
                if (xml.DocumentElement != null)
                {
                    toXML(xml, rootNode);
                }
            }
            else
            {
                fromXML(xml, rootNode);
            }
        }
        public void toXML(XmlDocument xml, XmlNode rootNode)
        {
            //XmlNode rootNode = xml.SelectSingleNode("XMLData");

            //for (auto it_member = m_AttributeMappings.begin(); it_member != m_AttributeMappings.end(); ++it_member)
            //{
            //    rootNode->SetAttribute(it_member->first.c_str(), it_member->second->c_str());
            //}
            for (int it_member = 0; it_member < m_AttributeMappings.Count; it_member++)
            {
                var element = m_AttributeMappings.ElementAt(it_member);

                if (rootNode.Attributes[element.Key] == null)
                {
                    XmlElement XmlEle = (XmlElement)rootNode;
                    XmlEle.SetAttribute(element.Key, element.Value.toString());
                }
                else
                {
                    rootNode.Attributes[element.Key].InnerText = element.Value.toString();
                }
            }
            //XmlElement element = (XmlElement)xmlDoc.SelectSingleNode("BookStore/NewBook");

            //for (auto it_subclass = m_MemberMappings.begin(); it_subclass != m_MemberMappings.end(); ++it_subclass)
            //{
            //    ISlo* subMember = it_subclass->second;
            //    tinyxml2::XMLElement* subClassNode = classDoc->NewElement("Member");
            //    subClassNode->SetAttribute("RegName", it_subclass->first.c_str());
            //    rootNode->InsertEndChild(subClassNode);
            //    subMember->Serialize(true, classDoc, subClassNode);
            //}

            for (int it_subclass = 0; it_subclass < m_MemberMappings.Count; it_subclass++)
            {
                var element = m_MemberMappings.ElementAt(it_subclass);
                ISlo subMember = element.Value;
                XmlNode subClassNode = xml.CreateElement("Member");
                rootNode.AppendChild(subClassNode);

                //if (rootNode.Attributes["RegName"] == null)
                //{
                //    XmlElement XmlEle_subclass = (XmlElement)rootNode;
                //    XmlEle_subclass.SetAttribute("RegName", element.Key);
                //}
                //else
                //{
                //    subClassNode.Attributes["RegName"].InnerText = element.Key;
                //}

                XmlElement XmlEle = (XmlElement)subClassNode;
                XmlEle.SetAttribute("RegName", element.Key);
                subMember.Serialize(true, xml, subClassNode);
            }


            //for (CollectionIterator it_collection = m_MemberCollections.begin(); it_collection != m_MemberCollections.end(); ++it_collection)
            //{
            //    tinyxml2::XMLElement* listNode = classDoc->NewElement("Collection");
            //    listNode->SetAttribute("RegName", (*it_collection).second->getCollectionName().c_str());
            //    for (size_t c = 0; c < (*it_collection).second->size(); c++)
            //    {
            //        ISlo* item = (*it_collection).second->getItem(c);
            //        tinyxml2::XMLElement* elementNode = classDoc->NewElement("Member");
            //        item->Serialize(true, classDoc, elementNode);
            //        listNode->InsertEndChild(elementNode);
            //    }
            //    rootNode->InsertEndChild(listNode);
            //}

            for (int it_collection = 0; it_collection < m_MemberCollections.Count; it_collection++)
            {
                var element = m_MemberCollections.ElementAt(it_collection);
                XmlNode listNode = xml.CreateElement("Collection");
                XmlElement XmlEle = (XmlElement)listNode;
                XmlEle.SetAttribute("RegName", element.Value.getCollectionName());
                for (int c = 0; c < element.Value.size(); c++)
                {
                    ISlo item = element.Value.getItem(c);
                    XmlNode elementNode = xml.CreateElement("Member");
                    item.Serialize(true, xml, elementNode);
                    listNode.AppendChild(elementNode);
                }

                rootNode.AppendChild(listNode);
            }
        }

        public void fromXML(XmlDocument xml, XmlNode rootNode)
        {

            //for (var it = this.m_AttributeMappings.First(); it != this.m_AttributeMappings.Last(); ++it)
            //{
            //    if (rootNode->Attribute(it->first.c_str()))
            //    {
            //        *(it->second->getStringPtr()) = rootNode->Attribute(it->first.c_str());// *(*it)->getField() = memberNode->GetText();
            //    }
            //}
            for (int count = 0; count < m_AttributeMappings.Count; count++)
            {
                var element = m_AttributeMappings.ElementAt(count);
                if (rootNode.Attributes[element.Key] != null)
                {
                    string aa = rootNode.Attributes[element.Key].Value;
                    element.Value.getStringPtr(rootNode.Attributes[element.Key].Value);
                }
            }

            //tinyxml2::XMLElement* classNode = rootNode->FirstChildElement("Member");
            //while (classNode != NULL)
            //{
            //    std::string className = classNode->Attribute("RegName");
            //    for (auto it_subclass = this->m_MemberMappings.begin(); it_subclass != this->m_MemberMappings.end(); ++it_subclass)
            //    {
            //        if (it_subclass->first == className)
            //        {
            //            it_subclass->second->Serialize(false, classDoc, classNode);
            //            break;
            //        }
            //    }
            //    classNode = classNode->NextSiblingElement("Member");
            //}

            XmlNodeList classNodeList = rootNode.SelectNodes("Member");
            if (classNodeList.Count != 0)
            {
                for (int i = 0; i < classNodeList.Count; i++)
                {
                    string className = classNodeList[i].Attributes["RegName"].Value;
                    for (int count = 0; count < m_MemberMappings.Count; count++)
                    {
                        var element = m_MemberMappings.ElementAt(count);
                        if (element.Key == className)
                        {
                            element.Value.Serialize(false, xml, classNodeList[i]);
                            break;
                        }
                    }
                }
            }

            //tinyxml2::XMLElement* collectionNode = rootNode->FirstChildElement("Collection");
            //while (collectionNode != NULL)
            //{
            //    std::string collectionName = collectionNode->Attribute("RegName");
            //    for (CollectionIterator it_collection = this->m_MemberCollections.begin(); it_collection != this->m_MemberCollections.end(); ++it_collection)
            //    {
            //        if ((*it_collection).second->getCollectionName() == collectionName)
            //        {
            //            (*it_collection).second->Clear();
            //            tinyxml2::XMLElement* classNode = collectionNode->FirstChildElement("Member");
            //            while (classNode != NULL)
            //            {
            //                ISlo* newItem = (*it_collection).second->newElement();
            //                newItem->Serialize(false, classDoc, classNode);
            //                classNode = classNode->NextSiblingElement("Member");
            //            }
            //        }
            //    }
            //    collectionNode = collectionNode->NextSiblingElement("Collection");
            //}
            //}

            XmlNodeList collectionNodeList = rootNode.SelectNodes("Collection");
            if (collectionNodeList.Count != 0)
            {
                for (int i = 0; i < collectionNodeList.Count; i++)
                {
                    string collectionName = collectionNodeList[i].Attributes["RegName"].Value;

                    for (int count = 0; count < m_MemberCollections.Count; count++)
                    {
                        var element = m_MemberCollections.ElementAt(count);
                        if (element.Value.getCollectionName() == collectionName)
                        {
                            element.Value.Clear();
                            XmlNodeList classNode2List = collectionNodeList[i].SelectNodes("Member");
                            if (classNode2List.Count != 0)
                            {
                                for (int j = 0; j < classNode2List.Count; j++)
                                {
                                    Convertinterface newItem = (Convertinterface)element.Value.newElement();
                                    //ISlo newItem = element.Value.newElement();
                                    //Object objectItem = element.Value.newElement();
                                    //ISlo newItem = (ISlo)objectItem;

                                    //newItem.m_AttributeMappings = m_AttributeMappings;
                                    //newItem.m_MemberMappings = m_MemberMappings;
                                    //newItem.m_MemberCollections = m_MemberCollections;

                                    newItem.Serialize(false, xml, classNode2List[j]);
                                }
                            }
                        }
                    }
                }
            }
        }

        string IdentifyClass(XmlNode rootNode, string XMLSource)
        {
            return rootNode.Attributes["RegName"].Value;
        }

        string IdentifyClassVersions(XmlNode rootNode, string XMLSource)  //同 IdentifyClass ???
        {
            return rootNode.Attributes["RegName"].Value;
        }


        public string getClassName() { return m_sClassName; }
        public void setVersion(string value) { m_sVersion = value; }
        public string getVersion() { return m_sVersion; }

        public void Clear()
        {
            m_AttributeMappings.Clear();
            m_MemberMappings.Clear();
            m_MemberCollections.Clear();
        }
    }
}
