using System;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using Autofac;
using IntraService.API.Toolkit.GlobalFilters;
using IntraService.App_Start;
using IntraService.Configuration;
using IntraService.Domain.Binders;
using IntraService.Domain.Helpers;
using IntraService.Mvc.Infrastructure;
using IntraService.Mvc.Infrastructure.Attributes;
using IntraService.Security;
using StackExchange.Profiling;

namespace IntraService
{
    public class MvcApplication : HttpApplication
    {
        public static IContainer Container;

        protected void Application_Start()
        {
            var version = ResourceHelper.GeneralResource("Common.Version");

            Container = BootStrapper.ConfigureApplication();

            AreaRegistration.RegisterAllAreas();

            var config = GlobalConfiguration.Configuration;

            config.Filters.Add(new VersionFilter(version));

            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            MvcHandler.DisableMvcResponseHeader = true;
            ViewEngines.Engines.Clear();
            var razorViewEngine = new RazorViewEngine();

            var viewLocations = new[]
            {
                "~/RazorViews/{1}/{0}.cshtml",
                "~/RazorViews/CustomTaskTypes/{1}/{0}.cshtml",
                "~/RazorViews/Shared/{0}.cshtml",
                "~/RazorViews/Shared/_EntityFormAttributeGroup/{1}/{0}.cshtml",
                "~/RazorViews/Shared/_EntityFormAttributeGroup/{0}.cshtml",
                "~/RazorViews/Shared/Task/{0}.cshtml",
                "~/RazorViews/Shared/TaskType/{0}.cshtml"
            };

            razorViewEngine.ViewLocationFormats = viewLocations;
            razorViewEngine.PartialViewLocationFormats = viewLocations;
            razorViewEngine.MasterLocationFormats = viewLocations;

            ViewEngines.Engines.Add(razorViewEngine);

            WebApiConfig.Register(config);

            RouteConfig.RegisterRoutes(RouteTable.Routes);

            GlobalBundleConfig.RegisterBundles(BundleTable.Bundles);

            HandlerConfig.RegisterHandlers(GlobalConfiguration.Configuration.MessageHandlers);

            ModelBinders.Binders.Add(typeof (DateTime), new DateTimeModelBinder());
            ModelBinders.Binders.Add(typeof (DateTime?), new DateTimeModelBinder());

            ModelBinders.Binders.Add(typeof (decimal), new DecimalModelBinder());
            ModelBinders.Binders.Add(typeof (decimal?), new DecimalModelBinder());

            ModelBinders.Binders.Add(typeof (IIntraServiceIdentity), new IntraServiceIdentityModelBinder());

            ModelBinders.Binders.Add(typeof (IIntraServicePrincipal), new IntraServicePrincipalModelBinder());

            #region Web.Api binders

            config.BindParameter(typeof (IIntraServicePrincipal),
                new API.Toolkit.Binders.IntraServicePrincipalModelBinder());

            config.BindParameter(typeof (IIntraServiceIdentity),
                new API.Toolkit.Binders.IntraServiceIdentityModelBinder());

            #endregion

            ControllerBuilder.Current.SetControllerFactory(new SessionStateControllerFactory());

            //Подсовываем свой провайдер мета-данных что бы обрабатывать кастомные атрибуты
            ModelMetadataProviders.Current = new MyLocalizationProvider();

            #region hub config
            int hubConfig_ConnectionTimeout;
            if (!int.TryParse(System.Web.Configuration.WebConfigurationManager.AppSettings["hubConfig_ConnectionTimeout"], out hubConfig_ConnectionTimeout))
            {
                hubConfig_ConnectionTimeout = 10;
            }
            Microsoft.AspNet.SignalR.GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromSeconds(hubConfig_ConnectionTimeout);

            int hubConfig_DisconnectTimeout;
            if (!int.TryParse(System.Web.Configuration.WebConfigurationManager.AppSettings["hubConfig_DisconnectTimeout"], out hubConfig_DisconnectTimeout))
            {
                hubConfig_DisconnectTimeout = 6;
            }

            //в документации советуют ставить кратную 3, т.к. параметр KeepAlive равен DisconnectTimeout/3 (если мы не поставили свое значение)
            if (hubConfig_DisconnectTimeout < 6)
                hubConfig_DisconnectTimeout = 6;

            Microsoft.AspNet.SignalR.GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromSeconds(hubConfig_DisconnectTimeout);

            //если у нас есть свое значение, иначе KeepAlive будет посчитан автоматически как DisconnectTimeout/3
            int hubConfig_KeepAlive;
            if(int.TryParse(System.Web.Configuration.WebConfigurationManager.AppSettings["hubConfig_KeepAlive"], out hubConfig_KeepAlive)){
                Microsoft.AspNet.SignalR.GlobalHost.Configuration.KeepAlive = TimeSpan.FromSeconds(hubConfig_KeepAlive);
            }
            #endregion

            GlobalConfiguration.Configuration.EnsureInitialized();
        }


        protected void Application_BeginRequest(Object sender, EventArgs e)
        {
            //Считываем и кешируем настройки.
            BootStrapper.ReadSettings(HttpContext.Current);
            BootStrapper.ReadCustomControllers(HttpContext.Current);

            //Воркэраунд для инициализации по первому запросу
            if (!FirstRequestInitialization.SInitializedAlready)
            {
                FirstRequestInitialization.Initialize(((HttpApplication) sender).Context);
            }

#if DEBUG
            MiniProfiler.Start();
#endif
        }

        /// <summary>
        /// Вызывается после того, как ядро ASP.NET получает текущий контекст (state) запроса (данные сессии).
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Application_AcquireRequestState(Object sender, EventArgs e)
        {
            var context = HttpContext.Current;
            HttpContext.Current.Response.Headers.Remove("Server");
            BootStrapper.Localization(context);
        }

        protected void Session_Start(Object sender, EventArgs e)
        {
            ReinitUserPermission.Init();
            BootStrapper.LocalizationOnSessionStart(HttpContext.Current);
        }

        protected void Application_EndRequest()
        {
            MiniProfiler.Stop();
        }

        //Костыль для сохранения состояния оператора.
        //TODO: После реализации API состояния -  убрать 
        protected void Application_PostAuthorizeRequest()
        {
            if (HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.StartsWith("~/api"))
                HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required);
        }
    }

    public static class FirstRequestInitialization
    {
        public static bool SInitializedAlready = false;
        private static readonly Object SLock = new Object();

        //Здесь производим инициализацию для которой требуется объект запроса в контексте
        public static void Initialize(HttpContext context)
        {
            lock (SLock)
            {
                SInitializedAlready = true;
                BootStrapper.ConfigureWindowsAuthentication(context);
            }
        }
    }
}
