using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.ServiceModel;
using System.Threading;

using NHibernate;
using NHibernate.Cfg;

using log4net;
using log4net.Appender;
using log4net.Layout;
using log4net.Repository.Hierarchy;

namespace BeWo.Data
{
    public class WCFHibernateSessionManager
    {
        private static Dictionary<string, ISessionFactory> _SessionFactories = new Dictionary<string, ISessionFactory>();
        private static object _Lock = string.Empty;

        //private static readonly ILog log = LogManager.GetLogger("WCFHibernateSessionManager");

        public static ISession CurrentSession
        {
            get
            {
                return SessionOperationContextExt.Current.Session;
            }

            private set
            {
                SessionOperationContextExt.Current.Session = value;
            }
        }

        private static ISessionFactory SessionFactory
        {
            get
            {
                try
                {
                    Monitor.Enter(_Lock);
                    if (!_SessionFactories.ContainsKey(MultitenancyOperationContextExt.Current.Tenant))
                    {
#if DEBUG
                        var hierarchy = (Hierarchy)LogManager.GetRepository();
                        var logger = (Logger)hierarchy.GetLogger("NHibernate.SQL");
                        logger.AddAppender(new TraceAppender { Layout = new SimpleLayout() });
                        hierarchy.Configured = true;
#endif
                        _SessionFactories[MultitenancyOperationContextExt.Current.Tenant] = new Configuration().Configure(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Multitenancy\" + MultitenancyOperationContextExt.Current.Tenant + ".config")).BuildSessionFactory();
                    }

                    
                    return _SessionFactories[MultitenancyOperationContextExt.Current.Tenant];
                }
                catch (Exception e)
                {
                    //String path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SessionFactoryError.txt");
                    //System.IO.File.AppendAllText(path, String.Format("{0:dd.MM.yyyy HH:mm:ss}", DateTime.Now) + "\n" + e.Message + "\n" + e.StackTrace);
                    Debug.WriteLine("<<<<< " + e.StackTrace + (e.InnerException != null ? e.InnerException.Message : string.Empty));
                    throw new FaultException(e.StackTrace + e.InnerException != null ? e.InnerException.Message : string.Empty);
                }
                finally
                {
                    Monitor.Exit(_Lock);
                }
            }
        }

        public static void ResetAllSessionFactories()
        {
            try
            {
                String[] tenants = new String[_SessionFactories.Keys.Count];

                _SessionFactories.Keys.CopyTo(tenants, 0);

                foreach (var item in tenants)
                {
                    ResetSessionFactory(item);
                }
                _SessionFactories = new Dictionary<string, ISessionFactory>();
            }
            catch (Exception)
            {
                //ignore?
            }

        }

        public static void ResetSessionFactory(string tenant)
        {
            String t = tenant;
            if (String.IsNullOrEmpty(t))
                t = MultitenancyOperationContextExt.Current.Tenant;
            if (_SessionFactories.ContainsKey(t))
            {
                try
                {
                    ISessionFactory fact = _SessionFactories[t];
                    if (!fact.IsClosed)
                    {
                        fact.Close();
                    }
                    fact.Dispose();

                }
                catch (Exception)
                {
                    //ignore exception??
                }


                _SessionFactories.Remove(t);
            }
        }

        private static ISessionFactory RebuildSessionFactory()
        {
            ResetSessionFactory(MultitenancyOperationContextExt.Current.Tenant);

            return SessionFactory;
        }

        public static void CloseSession()
        {
            if (CurrentSession != null)
            {
                CurrentSession.Close();
                CurrentSession.Dispose();
                CurrentSession = null;
            }
        }

        public static ISession OpenSession()
        {
            try
            {

                Thread.CurrentThread.CurrentCulture = new CultureInfo("de-DE");
                //System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");

                CloseSession();
                ISession session = SessionFactory.OpenSession(new UpdInsInterceptor());
                if (session == null)
                {
                    session = RebuildSessionFactory().OpenSession(new UpdInsInterceptor());
                }
                CurrentSession = session;

                return CurrentSession;
            }
            catch (Exception e)
            {
                throw new FaultException(e.StackTrace + e.InnerException != null ? e.InnerException.Message : string.Empty);
            }
        }

        public static bool TenantExists()
        {
            String path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Multitenancy\" + MultitenancyOperationContextExt.Current.Tenant + ".config");

            return File.Exists(path);
        }
    }
}