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 BeWo.Data.Access;
using BeWo.Data.Entities;
using BeWo.Service.ServiceImplementations;

using BS.Shared;
using BS.Shared.Core;

using NHibernate;
using Configuration = NHibernate.Cfg.Configuration;

namespace BeWoPlanerMobil.Service
{
    public class ASPHibernateSessionManager : IHttpModule
    {
		private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
		
		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 MobileUpdInsInterceptor()).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;
                        }

                        // ---------------------------------------------------------------
                        if (!ConfigureHibernateSession())
                        {
                            return;
                        }

                        var userLoaded = TryAuthenticateWithLoginForm(context);

                        if (!userLoaded && MobileSessionFacade.LoggedInUser != null && MobileSessionFacade.LoggedInUser.Oid.HasValue)
                        {
                            MobileSessionFacade.LoggedInUser = DAOFactory.GenericDAO.LoadByID<ApplicationUser>(MobileSessionFacade.LoggedInUser.Oid.Value);
                        }
                    }
                };

            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;
        }

	    private static bool ConfigureHibernateSession()
        {
	        var lTenant = MobileSessionFacade.Tenant;

            if (String.IsNullOrEmpty(lTenant))
            {
                return false;
            }

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

        private static bool TryAuthenticateWithLoginForm(HttpApplication context)
        {
            var name = context.Request.Params["tb_login"];
            var password = context.Request.Params["tb_password"];

	        if (Utils.IsAnyNullOrEmpty(name, password))
	        {
	            return false;
	        }

	        var s = new UserServiceImp();

			log.Info(String.Format("TryAuthenticateWithLoginForm with username: {0}, Tenant: {1}", name, MobileSessionFacade.Tenant));

	        if (s.IsUserValid(name, password, null, "MobilClient", false) == UserValidationResult.UserValid)
	        {
		        var user = DAOFactory.UserDAO.FindUserByLoginName(name);

		        if (user == null || !DAOFactory.UserDAO.CheckPassword(user, password)) return false;

		        MobileSessionFacade.LoggedInUser = user;
	        }

	        return true;
        }

        public static bool ConfigureHibernateSessionForWebService()
        {
            return ConfigureHibernateSession();
        }
    }
}