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


namespace Tools
{
    public class SerializeService
    {
        private class Pairs<TKey, TValue>
        {
            public TKey Key { set; get; }
            public TValue Value { set; get; }
        }

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

        public void RecursiveSerialize(object obj, Type _base, System.IO.MemoryStream memoryStream, string prefix = "")
        {
            if (used.Contains(obj))
                return;
            used.Add(obj);
            string str;
            System.IO.StreamWriter file = new System.IO.StreamWriter(memoryStream);
            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, memoryStream, 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, memoryStream, prefix + "\t\t");
                        }

                    continue;
                }

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

                /*
                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.MemoryStream memoryStream)
        {
            System.IO.StreamWriter file = new System.IO.StreamWriter(memoryStream);
            var serialize = obj.Serialize();
            foreach (var elem in serialize)
                if (elem.Value != null && elem.Value != "")
                    file.WriteLine(elem.Key + " : " + elem.Value);
            file.Flush();
        }

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