// Created with MonoDevelop
//
//    Copyright (C) 2022 Hiperscan GmbH Dresden, Germany
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program 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 General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Text;
using System.Xml;

using Hiperscan.Unix;

namespace Hiperscan.Common.IO
{
    public partial class XmlObject
    {
        public void Write(object obj, string file_name)
        {
            this.Init();
            this.SetFileName(file_name);
            this.CreateRootElement(obj);
            this.SerializeProperties(obj, this.Document.DocumentElement);

            FileIO.Save(this.Document, this.FileName);
        }

        private void CreateRootElement(object obj)
        {
            this.Document = new XmlDocument();

            XmlNode root = this.Document.CreateElement(obj.GetType().Name);
            XmlAttribute serialization_culture_attribute = this.Document.CreateAttribute(XmlObject.CULTURE_ATTRIBUTE);
            serialization_culture_attribute.Value = this.Culture.ToString();
            root.Attributes.Append(serialization_culture_attribute);
            this.Document.AppendChild(root);
        }

        private void SerializeProperties(object obj, XmlNode parent_node)
        {
            SortedDictionary<string, PropertyInfo> properties = new SortedDictionary<string, PropertyInfo>();
            
            foreach (PropertyInfo property_info in obj.GetType().GetProperties(this.BindingFlages))
            {
                var attr = property_info.GetCustomAttribute(typeof(XmlSerializationAttribute));
                if (attr == null)
                    continue;

                properties.Add(property_info.Name, property_info);
            }

            foreach (PropertyInfo property_info in properties.Values)
            {
                XmlNode child_node = this.AddToXml(parent_node, obj, property_info);
                if (child_node != null)
                    this.SerializeProperties(property_info.GetValue(obj), child_node);
            }
        }

        private XmlNode AddToXml(XmlNode parent, object obj, PropertyInfo property_info)
        {
            XmlNode node = this.Document.CreateElement(property_info.Name);
            parent.AppendChild(node);

            object value = property_info.GetValue(obj);

            if (value == null)
            {
                node.InnerText = XmlObject.NULL;
                return null;
            }

            if (property_info.PropertyType == typeof(DateTime))
            {
                node.InnerText = ((DateTime) value).ToString("o", this.Culture);
                return null;
            }

            TypeConverter type_converter = TypeDescriptor.GetConverter(property_info.PropertyType);
            string xml_value = type_converter.ConvertToString(null, this.Culture, value);

            if (xml_value == property_info.PropertyType.FullName)
                return node;

            node.InnerText = xml_value;
            return null;
        }

        private void CheckDefaultConstructor(Type type)
        {

        }
    }
}
