using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
using Aitex.Common.Util;

namespace MECF.Framework.Common.Utilities
{
    public class BinarySerializer<T> where T : new()
    {
        private static string pathName = PathManager.GetDirectory("Objects");

        private static Object thisLock = new Object();

        /// <summary>
        /// Serializes an object to the file which name is the full name of the object type.
        /// </summary>
        /// <param name="stuff"></param>
        public static void ToStream(T stuff)
        {
            lock (thisLock)
            {
                if (!Directory.Exists(pathName))
                {
                    Directory.CreateDirectory(pathName);
                }
                var fileName = typeof(T).FullName;

                IFormatter formatter = new BinaryFormatter();
                Stream stream = new FileStream(pathName + @"\" + fileName + @".obj", FileMode.Create);
                try
                {
                    using (stream)
                    {
                        formatter.Serialize(stream, stuff);
                        stream.Close();
                    }
                }
                catch (SerializationException e)
                {
                    Console.WriteLine(e.Message);
                    throw;
                }

                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    throw;
                }
            }
        }

        /// <summary>
        /// Serializes an object to a file with specified name.
        /// </summary>
        /// <param name="stuff"></param>
        /// <param name="fileName"></param>
        public static void ToStream(T stuff, string fileName)
        {
            lock (thisLock)
            {
                if (!Directory.Exists(pathName))
                {
                    Directory.CreateDirectory(pathName);
                }

                IFormatter formatter = new BinaryFormatter();
                Stream stream = new FileStream(pathName + @"\" + fileName + @".obj", FileMode.Create);
                try
                {
                    using (stream)
                    {
                        formatter.Serialize(stream, stuff);
                        stream.Close();
                    }
                }
                catch (SerializationException e)
                {
                    Console.WriteLine(e.Message);
                    throw;
                }

                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    throw;
                }
            }
        }

        /// <summary>
        /// Deserializes to an object the file whose name is same as the full name of the object type.
        /// </summary>
        /// <returns></returns>
        public static T FromStream()
        {
            lock (thisLock)
            {
                if (!Directory.Exists(pathName))
                {
                    Directory.CreateDirectory(pathName);
                }

                T obj = default(T);

                var fileName = typeof(T).FullName;

                var fullName = pathName + @"\" + fileName + @".obj";

                if (!File.Exists(fullName))
                {
                    return new T();
                }

                IFormatter formatter = new BinaryFormatter();

                Stream stream = new FileStream(fullName, FileMode.Open, FileAccess.Read);

                try
                {
                    using (stream)
                    {
                        obj = (T)formatter.Deserialize(stream);
                        stream.Close();
                    }

                    //ISubscriber subscriber = obj as ISubscriber;
                    //if (subscriber != null)
                    //{
                    //    subscriber.Subscribe();
                    //}
                }
                catch (SerializationException e)
                {
                    Console.WriteLine(e.Message);
                    //throw;
                }

                return obj;
            }
        }

        /// <summary>
        /// Deserializes a specified file to an object.
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static T FromStream(string fileName)
        {
            lock (thisLock)
            {
                if (!Directory.Exists(pathName))
                {
                    Directory.CreateDirectory(pathName);
                }

                T obj = default(T);

                var fullName = pathName + @"\" + fileName + @".obj";

                if (!File.Exists(fullName))
                {
                    return new T();
                }

                IFormatter formatter = new BinaryFormatter();

                Stream stream = new FileStream(fullName, FileMode.Open, FileAccess.Read);


                try
                {
                    using (stream)
                    {
                        obj = (T)formatter.Deserialize(stream);
                        stream.Close();
                    }
                }
                catch (SerializationException e)
                {
                    Console.WriteLine(e.Message);
                    //throw;
                }

                return obj;
            }
        }
    }
}