using System;
using System.Collections.Generic;
using System.Configuration;
using System.Globalization;
using System.IO;
using System.ServiceModel;
using System.Threading;
using System.Web;

using NHibernate;

using Configuration = NHibernate.Cfg.Configuration;

namespace BeWoPlanerAndroid.Service
{
    public class SoapHibernateSessionManager : IHttpModule
    {
        private static readonly Dictionary<string, ISessionFactory> _SessionFactories = new Dictionary<string, ISessionFactory>();
        private static readonly object _Lock = string.Empty;

        private static ISessionFactory SessionFactory
        {
            get
            {
                try
                {
                    Monitor.Enter(_Lock);

                    if (!_SessionFactories.ContainsKey(MobileSessionFacade.Tenant))
                    {
                        var serverPath = HttpContext.Current.Server.MapPath("");

                        serverPath = Path.Combine(serverPath, ConfigurationManager.AppSettings.Get("MultitenancyPath"));
                        serverPath = Path.Combine(serverPath, MobileSessionFacade.Tenant + ".config");

                        _SessionFactories[MobileSessionFacade.Tenant] = new Configuration().Configure(serverPath).SetInterceptor(new MobileUpdInstInterceptor()).BuildSessionFactory();
                    }

                    return _SessionFactories[MobileSessionFacade.Tenant];
                }
                catch (Exception e)
                {
                    throw new FaultException(e.StackTrace + (e.InnerException != null ? e.InnerException.Message : string.Empty));
                }
                finally
                {
                    Monitor.Exit(_Lock);
                }
            }
        }

        public void Dispose() { }

        public void Init(HttpApplication context)
        {
            context.AcquireRequestState += (s, e) =>
            {
                Thread.CurrentThread.CurrentCulture = new CultureInfo("de-DE");

                if (ShouldConfigureHibernateSession(context))
                {
                    // TEST FOR DEVEXPRESS. PROBLEMS WITH THIS MODULE WHEN USING AJAX!
                    if (HttpContext.Current.Session == null)
                    {
                        return;
                    }

                    ConfigureHibernateSession();
                }
            };

            context.PreRequestHandlerExecute += (s, e) =>
            {
                if(HttpContext.Current.Session == null)
                {
                    return;
                }

                var tenant = context.Request.Params["pTenant"];

                var isNhibernateSessionExisting = HttpContext.Current.Items.Contains("hibernateSession");
                if(isNhibernateSessionExisting)
                {
                    return;
                }

                if (tenant != null && MobileSessionFacade.Tenant == null)
                {
                    MobileSessionFacade.Tenant = tenant;
                }

                ConfigureHibernateSession();
            };

            context.EndRequest += (s, e) =>
            {
                if (HttpContext.Current.Items["hibernateSession"] != null)
                {
                    ((ISession) HttpContext.Current.Items["hibernateSession"]).Close();
                }
            };
        }

        private static bool ShouldConfigureHibernateSession(HttpApplication context)
        {
            return string.IsNullOrEmpty(context.Request.FilePath) || context.Request.FilePath.IndexOf("Admin.aspx") < 0;
        }

        public static bool ConfigureHibernateSession()
        {
            if(MobileSessionFacade.Tenant == null)
            {
                MobileSessionFacade.Tenant = AndroidSoapService.Tenant;
            }

            var lTenant = MobileSessionFacade.Tenant;

            if (string.IsNullOrEmpty(lTenant) || HttpContext.Current.Items["hibernateSession"] != null)
            {
                return false;
            }

            HttpContext.Current.Items.Add("hibernateSession", SessionFactory.OpenSession());

            return true;
        }
    }
}