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


namespace Tools
{
    public class SerializeService
    {
        List<object> used = new List<object>();
        public SerializeService()
        {
            used = new List<object>();
        }       

        public void RecursiveSerialize(object obj, Type _base, System.IO.Stream stream, string prefix = "")
        {
            if (used.Contains(obj))
                return;
            used.Add(obj);
            string str;
            System.IO.StreamWriter file = new System.IO.StreamWriter(stream);
            var allPropertiesOfObj = obj.GetType().GetProperties().OrderBy(e => (e.GetCustomAttributes(typeof(IndexAttrib), true).FirstOrDefault() as IndexAttrib).Index);

            foreach (var singleProperty in allPropertiesOfObj)
            {                
                var type = singleProperty.PropertyType;

                if (type.IsSubclassOf(_base) && singleProperty.GetValue(obj) != null)
                {
                    RecursiveSerialize(singleProperty.GetValue(obj), _base, stream, prefix + "\t\t");
                    continue;
                }

                //  https://stackoverflow.com/questions/16981070/c-sharp-reflection-to-match-type-listt-where-t-issubclassfoo
                if (
                   type.IsGenericType
                   && type.GetGenericTypeDefinition() == typeof(List<>)
                   )
                {
                    if (singleProperty.GetValue(obj) is IEnumerable<object> t)
                        foreach (var u in t)
                        {
                            RecursiveSerialize(u, _base, stream, prefix + "\t\t");
                        }

                    continue;
                }

                if (
                   type.IsGenericType
                   && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)
                   && typeof(string).Equals(type.GetGenericArguments()[0])
                   && typeof(string).Equals(type.GetGenericArguments()[1])
                   )
                {                  
                    if (
                        typeof(string).Equals(type.GetGenericArguments()[0])
                        && typeof(string).Equals(type.GetGenericArguments()[1])
                        )
                    {
                        var t = singleProperty.GetValue(obj) as Dictionary<string, string>;
                        foreach (var u in t)
                        {
                            file.WriteLine(u.Key + " : " + u.Value);
                        }
                        continue;
                    }
                }
                str = singleProperty.GetValue(obj)?.ToString();
                if (str != null && str != "")
                    file.WriteLine(prefix + "{0} : {1}", singleProperty.Name, str);

                /*
                var obj = properties_sort[0].GetValue(a);
                var t = obj.GetType();

                dynamic d2 = Convert.ChangeType(obj, t);


                foreach (var elem in d2)
                {
                    Console.WriteLine(elem.Key);
                    Console.WriteLine(elem.Value);
                }    
                */

            }
           
        }

        public static void Serialize(I_MySerializable obj, System.IO.Stream stream)
        {
            System.IO.StreamWriter file = new System.IO.StreamWriter(stream);
            var serialize = obj.Serialize();
            foreach (var elem in serialize)
                if (elem.Value != null && elem.Value != "")
                    file.WriteLine(elem.Key + " : " + elem.Value);
        }

        public static void Serialize(List<I_MySerializable> info, System.IO.Stream stream)
        {
            foreach (var elem in info)
                Serialize(elem, stream);
        }       
    }
}
