using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using System.IO;
using System.Diagnostics;
using System.Web;

using Microsoft.Win32;

using Newtonsoft.Json;

using FasdDesktopUi.Basics;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.Helper;
using FasdDesktopUi.Pages.CustomMessageBox;
using FasdDesktopUi.Pages.DetailsPage.Models;
using FasdDesktopUi.Pages.SplashScreenView;
using FasdDesktopUi.Pages.M42AuthenticationPage;
using FasdDesktopUi.Pages.SearchPage;

using C4IT.FASD.Base;
using C4IT.FASD.Cockpit.Communication;
using C4IT.Logging;
using C4IT.MultiLanguage;
using C4IT.F4SD.TAPI;

using static C4IT.Logging.cLogManager;


namespace FasdDesktopUi
{
    public class cAppStartUp
    {
        public const string constUrlProtocol = "F4SDSEND";
        public const string constUrlCommand = "sendurl";
        private static bool AreAppComponentsInitialized = false;

        private static SplashScreenView splashScreen;

        public static async Task<bool> StartAsync(string[] startArguments)
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
#if isDemo
                cFasdCockpitCommunicationBase.Instance = new cFasdCockpitCommunicationDemo();
#else
                cFasdCockpitCommunicationBase.Instance = new cFasdCockpitCommunicationWeb();
#endif

                if (!startArguments.Contains("SilentStart", StringComparer.InvariantCultureIgnoreCase))
                {
                    splashScreen = new SplashScreenView();
                    splashScreen?.Show();
                }

                var searchPageView = SearchPageView.Instance;
                var settingsPageView = FasdDesktopUi.Pages.SettingsPage.SettingsPageView.Create();

                splashScreen?.SetStatusText(cMultiLanguageSupport.GetItem("StartUp.SplashScreen.CheckServerConnection"));
                if (!await InitializeCommunicationAsync())
                {
                    LogEntry("Error when initializing communication components.", LogLevels.Fatal);
                    CustomMessageBox.Show("Error when initializing communication components.", "Fatal Error", enumHealthCardStateLevel.Error);
                    Application.Current.Shutdown();
                }

                if (cConnectionStatusHelper.Instance.ApiConnectionStatus >= cConnectionStatusHelper.enumOnlineStatus.illegalConfig)
                {
                    splashScreen?.SetStatusText(cMultiLanguageSupport.GetItem("StartUp.SplashScreen.InitAppComponents"));
                    if (!await InitializeUiElementsAsync())
                        return false;
                }
                cConnectionStatusHelper.ApiConnectionStatusChanged += ApiConnectionStatusChanged;

                // Aufruf der neuen Prominenteren Suche (work in progress)
                //var advancedPaged = new AdvancedSearchPage();
                //advancedPaged.Show();

                return true;
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                splashScreen?.Hide();
                LogMethodEnd(CM);
            }

            return false;
        }

        public static bool ProcessCommandLine(string[] Args)
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                if (DefaultLogger.IsDebug)
                {
                    var _msg = new List<string>() { "command line arguments:" };
                    foreach (var _entry in Args)
                        _msg.Add(_entry);
                    DefaultLogger.LogList(LogLevels.Debug, _msg);
                }

                var Command = Args[0].ToLowerInvariant();
                bool shouldShutdown = true;

                switch (Command)
                {
                    case "search":
                        if (Args.Length < 2)
                        {
                            LogEntry($"Missing search value on command line for command {Command}.", LogLevels.Error);
                            break;
                        }
                        var Search = Args[1];
                        cAppStartUp.SendSearchValue(Search);
                        break;
                    case "phonesearch":
                        try
                        {
                            if (Args.Length < 2)
                            {
                                LogEntry($"Missing search value on command line for command {Command}.", LogLevels.Error);
                                break;
                            }

                            var searchInfo = new cPhoneSearchParameters
                            {
                                phone = Args[1]
                            };
                            if (Args.Length >= 3)
                                searchInfo.name = Args[2];
                            SendPhoneSearchValues(searchInfo);
                        }
                        catch (Exception E)
                        {
                            LogException(E);
                        }
                        break;
                    case "computerdomainsearch":
                        try
                        {
                            if (Args.Length < 2)
                            {
                                LogEntry($"Missing a search value on command line for command {Command}.", LogLevels.Error);
                                break;
                            }

                            var searchInfo = new cComputerDomainSearchParameters()
                            {
                                name = Args[1],
                                domain = ""
                            };
                            if (Args.Length >= 3)
                                searchInfo.domain = Args[2];
                            cAppStartUp.SendComputerDomainSearchValues(searchInfo);
                        }
                        catch (Exception E)
                        {
                            LogException(E);
                        }

                        break;
                    case "usersidsearch":
                        try
                        {
                            if (Args.Length < 2)
                            {
                                LogEntry($"Missing a search value on command line for command {Command}.", LogLevels.Error);
                                break;
                            }

                            var searchInfo = new cUserSidSearchParameters()
                            {
                                name = Args[1],
                                sids = ""
                            };
                            if (Args.Length >= 3)
                                searchInfo.sids = Args[2];
                            cAppStartUp.SendUserSidSearchValues(searchInfo);
                        }
                        catch (Exception E)
                        {
                            LogException(E);
                        }

                        break;
                    case "ticketsearch":
                        try
                        {
                            if (Args.Length < 4)
                            {
                                LogEntry($"Missing a search value on command line for command {Command}.", LogLevels.Error);
                                break;
                            }

                            var searchInfo = new cTicketSearchParameters()
                            {
                                ticketName = Args[1],
                                ticketId = Args[2],
                                userName = Args[3],
                                sids = ""
                            };
                            if (Args.Length >= 5)
                                searchInfo.sids = Args[4];
                            cAppStartUp.SendTicketSearchValues(searchInfo);
                        }
                        catch (Exception E)
                        {
                            LogException(E);
                        }

                        break;
                    case constUrlCommand:
                        if (Args.Length < 2)
                        {
                            LogEntry("Missing url on command line.", LogLevels.Error);
                            break;
                        }
                        var Url = Args[1];
                        cAppStartUp.ProcessMessageUrl(Url);
                        break;
                    default:
                        shouldShutdown = false;
                        LogEntry($"Unknown command on commandline: {Command}", LogLevels.Warning);
                        break;
                }

                return shouldShutdown;
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }

            return false;
        }

        public static void ProcessMessageUrl(string url)
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                if (url.Length <= constUrlProtocol.Length + 3)
                {
                    LogEntry($"No valid {constUrlProtocol} message.", LogLevels.Warning);
                    return;
                }

                var urlPrefix = url.Substring(0, constUrlProtocol.Length + 3).ToLowerInvariant();
                if (urlPrefix != constUrlProtocol.ToLowerInvariant() + "://")
                {
                    LogEntry($"Unknown protocol prefix {urlPrefix}. Should be {constUrlProtocol}://", LogLevels.Warning);
                    return;
                }

                var arr1 = url.Split('?');

                if (arr1.Length < 2)
                {
                    LogEntry("No valid url parameters.", LogLevels.Warning);
                    return;
                }

                var arrParams = arr1[1].Split('&');
                var dicParams = new Dictionary<string, string>();

                foreach (var param in arrParams)
                {
                    var arr2 = param.Split('=');
                    if (arr2.Length != 2)
                    {
                        LogEntry($"Invalid url parameter: {param}", LogLevels.Warning);
                        continue;
                    }

                    var name = HttpUtility.UrlDecode(arr2[0]).Trim().ToLowerInvariant();
                    var value = HttpUtility.UrlDecode(arr2[1]).Trim();
                    dicParams[name] = value;
                }

                if (!dicParams.TryGetValue("command", out var commandType))
                {
                    LogEntry("Missing command parameter in url.", LogLevels.Warning);
                    return;
                }

                switch (commandType.ToLowerInvariant())
                {
                    case "search":
                        if (!dicParams.TryGetValue("value", out var searchValue))
                        {
                            LogEntry("Missing value parameter in url.", LogLevels.Warning);
                            return;
                        }
                        SendSearchValue(searchValue);
                        break;
                    case "phonesearch":
                        {
                            if (!dicParams.TryGetValue("phone", out var searchPhone))
                            {
                                LogEntry("Missing phone parameter in url.", LogLevels.Warning);
                                return;
                            }
                            if (!dicParams.TryGetValue("name", out var searchName))
                                searchName = null;
                            var searchInfo = new cPhoneSearchParameters() { phone = searchPhone, name = searchName };
                            SendPhoneSearchValues(searchInfo);
                        }
                        break;
                    case "usersidsearch":
                        {
                            if (!dicParams.TryGetValue("name", out var searchName))
                            {
                                LogEntry("Missing name parameter in url.", LogLevels.Warning);
                                return;
                            }
                            if (!dicParams.TryGetValue("sids", out var searchSids))
                                searchSids = null;
                            var searchInfo = new cUserSidSearchParameters() { name = searchName, sids = searchSids };
                            SendUserSidSearchValues(searchInfo);
                        }
                        break;
                    case "computerdomainsearch":
                        {
                            if (!dicParams.TryGetValue("name", out var searchName))
                            {
                                LogEntry("Missing name parameter in url.", LogLevels.Warning);
                                return;
                            }
                            if (!dicParams.TryGetValue("domain", out var searchDomain))
                                searchDomain = null;
                            var searchInfo = new cComputerDomainSearchParameters() { name = searchName, domain = searchDomain };
                            SendComputerDomainSearchValues(searchInfo);
                        }
                        break;
                    case "ticketsearch":
                        {
                            if (!dicParams.TryGetValue("tname", out var _tname))
                            {
                                LogEntry("Missing ticket name parameter in url.", LogLevels.Warning);
                                return;
                            }
                            if (!dicParams.TryGetValue("tid", out var _tid))
                            {
                                LogEntry("Missing ticket id parameter in url.", LogLevels.Warning);
                                return;
                            }
                            if (!dicParams.TryGetValue("uname", out var _uname))
                            {
                                LogEntry("Missing ticket id parameter in url.", LogLevels.Warning);
                                return;
                            }

                            var searchInfo = new cTicketSearchParameters()
                            {
                                ticketName = _tname,
                                ticketId = _tid,
                                userName = _uname
                            };
                            if (dicParams.TryGetValue("sids", out var _sids))
                                searchInfo.sids = _sids;
                            SendTicketSearchValues(searchInfo);
                        }
                        break;
                    default:
                        LogEntry($"Unknown url command parameter: {commandType}.", LogLevels.Warning);
                        break;
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }
        }

        public static void SendSearchValue(string searchValue)
        {
            cF4sdPipeClient.Send("search:" + searchValue, App.PipeName);
        }

        public static void SendPhoneSearchValues(cPhoneSearchParameters search)
        {
            var jsonSearch = JsonConvert.SerializeObject(search);
            cF4sdPipeClient.Send("phonesearch:" + jsonSearch, App.PipeName);
        }

        public static void SendComputerDomainSearchValues(cComputerDomainSearchParameters search)
        {
            var jsonSearch = JsonConvert.SerializeObject(search);
            cF4sdPipeClient.Send("computerdomainsearch:" + jsonSearch, App.PipeName);
        }

        public static void SendUserSidSearchValues(cUserSidSearchParameters search)
        {
            var jsonSearch = JsonConvert.SerializeObject(search);
            cF4sdPipeClient.Send("usersidsearch:" + jsonSearch, App.PipeName);
        }

        public static void SendTicketSearchValues(cTicketSearchParameters search)
        {
            var jsonSearch = JsonConvert.SerializeObject(search);
            cF4sdPipeClient.Send("ticketsearch:" + jsonSearch, App.PipeName);
        }

        private static async Task<bool> InitializeCommunicationAsync()
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                if (!cFasdCockpitCommunicationBase.Instance.CheckConnectionInfo())
                {
                    CustomMessageBox.Show("No valid server URL found in registry.", "First Aid Service Desk", enumHealthCardStateLevel.Error);
                    LogEntry("No valid server URL found in registry.");
                    return false;
                }

                var _csh = new cConnectionStatusHelper();
                _csh.M42FormBasedAuthentication += F4sdM42FormsAuthentication.M42FormBasedAuthenticationDelegate;
                cConnectionStatusHelper.Instance = _csh;

                await cConnectionStatusHelper.Instance.RunConnectionStatusCheckAsync(splashScreen);
                cConnectionStatusHelper.Instance.OnApiConnectionStatusChanged();

                return true;
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }

            return false;
        }

        private static async void ApiConnectionStatusChanged(cConnectionStatusHelper.enumOnlineStatus? Status)
        {
            try
            {
                if (AreAppComponentsInitialized || Status != cConnectionStatusHelper.enumOnlineStatus.online)
                    return;

                await InitializeUiElementsAsync();
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private static bool CheckSwyxIt()
        {
            try
            {
                var regObj = Registry.GetValue("HKEY_CLASSES_ROOT\\WOW6432Node\\CLSID\\{F8E552F8-4C00-11D3-80BC-00105A653379}\\VersionIndependentProgID", null, null);
                if ((regObj is string strObj) && (strObj.ToLowerInvariant() == "clmgr.clientlinemgr"))
                    return true;
                regObj = Registry.GetValue("HKEY_CLASSES_ROOT\\CLSID\\{F8E552F8-4C00-11D3-80BC-00105A653379}\\VersionIndependentProgID", null, null);
                if ((regObj is string strObj2) && (strObj2.ToLowerInvariant() == "clmgr.clientlinemgr"))
                    return true;
            }
            catch (Exception E)
            {
                LogException(E);
            }
            return false;
        }

        private static void TapiMessageHandler(C4TapiHelper.C4TapiLineInfo lineInfo)
        {
            try
            {
                if (lineInfo.eventType == C4TapiHelper.eTapiEventType.connected)
                {

                    var CM = MethodBase.GetCurrentMethod();
                    LogMethodBegin(CM);
                    try
                    {
                        if (lineInfo.IsOutbound && !cFasdCockpitConfig.Instance.PhoneSupport.SignalOutgoingCalls)
                        {
                            LogEntry("An outgoing call is signaled but signaling outgoing calls is not enabled.");
                            return;
                        }

                        var phone = lineInfo.participantPhoneNumber;
                        var phone2 = phone.Trim();
                        if (!string.IsNullOrEmpty(cFasdCockpitConfig.Instance.PhoneSupport.ExternalCallPrefix) && phone2.StartsWith(cFasdCockpitConfig.Instance.PhoneSupport.ExternalCallPrefix))
                            phone2 = phone2.Remove(0, cFasdCockpitConfig.Instance.PhoneSupport.ExternalCallPrefix.Length);

                        if (phone2.StartsWith("+"))
                        {
                            var _r = Math.Min(phone2.Length, 3);
                            phone2 = phone2.Remove(0, _r);
                        }
                        else if (phone2.StartsWith("00"))
                        {
                            var _r = Math.Min(phone2.Length, 4);
                            phone2 = phone2.Remove(0, _r);
                        }
                        if (phone2.StartsWith("0"))
                            phone2 = phone2.Remove(0, 1);

                        var phone3 = "";
                        foreach (var C in phone2)
                            if ((C >= '0') && (C <= '9'))
                                phone3 += C;

                        var phoneSearch = new cPhoneSearchParameters()
                        {
                            phone = phone3,
                            name = lineInfo.participantName.Trim()
                        };
                        SendPhoneSearchValues(phoneSearch);
                    }
                    catch (Exception E)
                    {
                        LogException(E);
                    }
                    finally
                    {
                        LogMethodEnd(CM);
                    }
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private static void StartPhoneCallMonitoring()
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);

            // check phone support disabled
            if (cFasdCockpitConfig.Instance.PhoneSupport.DisablePhoneSupport)
                return;

            var disposeTapi = false;
            try
            {
                // get the TAPI lines
                lock (C4TapiHelper.InstanceLock)
                {
                    C4TapiHelper.Instance = new C4TapiHelper();
                    disposeTapi = true;
                    C4TapiHelper.Instance.Initialize(TapiMessageHandler);
                    C4TapiHelper.Instance.GetLines();
                }


                // check prefer swyxit
                if (cFasdCockpitConfig.Instance.PhoneSupport.PreferSwyxitNative && CheckSwyxIt())
                {
                    if (StartPhoneMonitorExternal("SwyxItNative"))
                        return;
                }

                // check if we autoconnect TAPI
                lock (C4TapiHelper.InstanceLock)
                {
                    string _tapiLine = null;
                    if (C4TapiHelper.Lines != null && !string.IsNullOrEmpty(cFasdCockpitConfig.Instance.PhoneSupport.PreferedTapiLine) && C4TapiHelper.Lines.Contains(cFasdCockpitConfig.Instance.PhoneSupport.PreferedTapiLine))
                        _tapiLine = cFasdCockpitConfig.Instance.PhoneSupport.PreferedTapiLine;
                    else if (C4TapiHelper.Lines != null && C4TapiHelper.Lines.Count == 1)
                        _tapiLine = C4TapiHelper.Lines[0];

                    if (_tapiLine != null)
                    {
                        if (cFasdCockpitConfig.Instance.PhoneSupport.UseTapi32Bit)
                        {
                            if (StartPhoneMonitorExternal(_tapiLine))
                                return;
                        }

                        if (C4TapiHelper.Instance.ConnectLine(C4TapiHelper.Lines[0]))
                            disposeTapi = false;
                    }
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                lock (C4TapiHelper.InstanceLock)
                {
                    if (disposeTapi)
                    {
                        C4TapiHelper.Instance.Dispose();
                        C4TapiHelper.Instance = null;
                    }
                }
                LogMethodEnd(CM);
            }

        }

        private static bool StartPhoneMonitorExternal(string Line)
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                var ass = Assembly.GetEntryAssembly();
                var path = Path.Combine(Path.GetDirectoryName(Path.GetFullPath(ass.Location)), "F4SD-PhoneMonitor.exe");
                if (File.Exists(path))
                {
                    var preFix = cFasdCockpitConfig.Instance.PhoneSupport.ExternalCallPrefix ?? "";
                    var signalExtern = cFasdCockpitConfig.Instance.PhoneSupport.SignalOutgoingCalls ? "1" : "0";
                    var _cmd = "\"" + App.PipeName + "\" \"" + App.PhoneMonitorPipeName + "\" \"" + Line + "\" \"" + preFix + "\" \"" + signalExtern + "\"";
                    var pr = Process.Start(path, _cmd);
                    return true;
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }

            return false;
        }

        private static async Task<bool> InitializeUiElementsAsync()
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                splashScreen?.SetStatusText(cMultiLanguageSupport.GetItem("StartUp.SplashScreen.LoadAppViews"));

                CheckHealthCardAvailability();
                UpdateRegistryGeometryBasedOnFirstDataOfDataProvider();

                // adjust notify icon menu
                cF4sdUserInfo userInfo;
                lock (cFasdCockpitCommunicationBase.CockpitUserInfoLock)
                {
                    userInfo = cFasdCockpitCommunicationBase.CockpitUserInfo;
                }
                if (cFasdCockpitConfig.Instance.HasM42Configuration())
                    if (userInfo?.possibleLogons != null)
                    {
                        if (userInfo.possibleLogons.Contains(enumAdditionalAuthentication.M42WinLogon))
                        {
                            if (App.M42OptionMenuItem != null)
                            {
                                App.M42OptionMenuItem.Visible = true;
                            }
                        }
                    }

                await InitializeViewsAsync();

                AreAppComponentsInitialized = true;

                var PhoneThread = new Thread(StartPhoneCallMonitoring);
                PhoneThread.Start();

                return true;
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }

            return false;
        }

        private static void CheckHealthCardAvailability()
        {
            try
            {
                if (!cHealthCardDataHelper.HasAvailableHealthCard(new List<enumFasdInformationClass>() { enumFasdInformationClass.Ticket }))
                    LogEntry("No available Health Card for Tickets was found.", LogLevels.Info);

                if (!cHealthCardDataHelper.HasAvailableHealthCard(new List<enumFasdInformationClass>() { enumFasdInformationClass.Computer }))
                    LogEntry("No available Health Card for computers was found.", LogLevels.Error);

                if (!cHealthCardDataHelper.HasAvailableHealthCard(new List<enumFasdInformationClass>() { enumFasdInformationClass.User }))
                    LogEntry("No available Health Card for users was found.", LogLevels.Error);
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }


        public static void Terminate()
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                lock (C4TapiHelper.InstanceLock)
                {
                    if (C4TapiHelper.Instance != null)
                    {
                        C4TapiHelper.Instance.Dispose();
                        C4TapiHelper.Instance = null;
                    }
                }

            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }
        }

        #region Views & Geometry

        private static void UpdateRegistryGeometryBasedOnFirstDataOfDataProvider()
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                //Get old geometry from registry
                DetailsPageGeometry lastGeometry = !string.IsNullOrEmpty(cFasdCockpitConfig.Instance.DetailsPageMaxGeometry) ?
                    JsonConvert.DeserializeObject<DetailsPageGeometry>(cFasdCockpitConfig.Instance.DetailsPageMaxGeometry) :
                    new DetailsPageGeometry()
                    {
                        DetailsCollectionGeometry = new DetailsPageDataHistoryCollectionGeometryModel() { SubtitleCount = new List<int>() },
                        WidgetGeometryList = new List<DetailsPageWidgetGeometryModel>()
                    };

                //Get new geometry from DataList
                cHealthCard firstHealthCard = cF4SDCockpitXmlConfig.Instance.HealthCardConfig.HealthCards.FirstOrDefault(healthCard => healthCard.Value.InformationClasses.Contains(enumFasdInformationClass.Computer)).Value;


                DetailsPageGeometry newGeometry = new DetailsPageGeometry()
                {
                    DetailsCollectionGeometry = new DetailsPageDataHistoryCollectionGeometryModel() { SubtitleCount = new List<int>() },
                    WidgetGeometryList = new List<DetailsPageWidgetGeometryModel>()
                };

                foreach (var widgetData in firstHealthCard.CategoriesStatic.StateCategories)
                {
                    if (widgetData.IsHidden)
                        continue;
                    newGeometry.WidgetGeometryList.Add(new DetailsPageWidgetGeometryModel() { WidgetTitleCount = widgetData.States.Count, WidgetDetailCount = widgetData.States.Count });
                }

                newGeometry.DetailsCollectionGeometry.ColumnCount = firstHealthCard.MaxAgeInDays;
                foreach (var detailsData in firstHealthCard.CategoriesHistory.StateCategories)
                {
                    if (detailsData.IsHidden)
                        continue;
                    var stateCount = detailsData.States.Count;
                    foreach (var state in detailsData.States)
                    {
                        if (state.IsHidden)
                            continue;
                        if (state is cHealthCardStateAggregation aggregationState)
                            stateCount += aggregationState.States.Count;
                    }

                    newGeometry.DetailsCollectionGeometry.SubtitleCount.Add(stateCount);
                }

                //Update new geometry
                var lastGeometryWidgetEnumerator = lastGeometry.WidgetGeometryList.GetEnumerator();
                foreach (var widgetGeometry in newGeometry.WidgetGeometryList)
                {
                    if (lastGeometryWidgetEnumerator.MoveNext())
                    {
                        var lastWidgetGeometry = lastGeometryWidgetEnumerator.Current;
                        widgetGeometry.WidgetTitleCount = cUtility.SmoothedInt(lastWidgetGeometry.WidgetTitleCount, widgetGeometry.WidgetTitleCount);
                        widgetGeometry.WidgetDetailCount = cUtility.SmoothedInt(lastWidgetGeometry.WidgetDetailCount, widgetGeometry.WidgetDetailCount);
                    }
                }

                newGeometry.DetailsCollectionGeometry.ColumnCount = cUtility.SmoothedInt(lastGeometry.DetailsCollectionGeometry.ColumnCount, newGeometry.DetailsCollectionGeometry.ColumnCount);

                var lastGeometryDetailsSubtitleEnumerator = lastGeometry.DetailsCollectionGeometry.SubtitleCount.GetEnumerator();

                for (int i = 0; i < newGeometry.DetailsCollectionGeometry.SubtitleCount.Count; i++)
                {
                    if (lastGeometryDetailsSubtitleEnumerator.MoveNext())
                    {
                        int tempSubtitleCountValue = newGeometry.DetailsCollectionGeometry.SubtitleCount[i];
                        int newSubtitleCountValue = cUtility.SmoothedInt(lastGeometryDetailsSubtitleEnumerator.Current, tempSubtitleCountValue);
                        newGeometry.DetailsCollectionGeometry.SubtitleCount[i] = newSubtitleCountValue;
                    }
                }

                //Save new Geometry
                cFasdCockpitConfig.Instance.DetailsPageMaxGeometry = JsonConvert.SerializeObject(newGeometry);
                cFasdCockpitConfig.Instance.Save("DetailsPageMaxGeometry");
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }
        }

        private static DetailsPageGeometry BaseDetailsPageGeometry()
        {
            try
            {
                string registryGeometryString = cFasdCockpitConfig.Instance.DetailsPageMaxGeometry;

                DetailsPageGeometry output = !string.IsNullOrEmpty(registryGeometryString) ?
                    JsonConvert.DeserializeObject<DetailsPageGeometry>(registryGeometryString) :
                    new DetailsPageGeometry() { DetailsCollectionGeometry = new DetailsPageDataHistoryCollectionGeometryModel() { SubtitleCount = new List<int>() }, WidgetGeometryList = new List<DetailsPageWidgetGeometryModel>() };

                return output;
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
            }
            return null;
        }

        private static async Task InitializeViewsAsync()
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                var _arrTasks = new List<Task>
                {
                    Application.Current.Dispatcher.BeginInvoke((Action)delegate { cSupportCaseDataProvider.slimPage = new Pages.SlimPage.SlimPageView(); }, DispatcherPriority.Normal).Task,
                    Application.Current.Dispatcher.BeginInvoke((Action)delegate { cSupportCaseDataProvider.detailsPage = new Pages.DetailsPage.DetailsPageView(); }, DispatcherPriority.Normal).Task
                };
                await Task.WhenAll(_arrTasks);
                _arrTasks = new List<Task>
                {
                    Application.Current.Dispatcher.BeginInvoke((Action)delegate { cSupportCaseDataProvider.detailsPage.SetGeometryValues(BaseDetailsPageGeometry()); }, DispatcherPriority.Normal).Task,
                    Application.Current.Dispatcher.BeginInvoke((Action)delegate { cSupportCaseDataProvider.slimPage.SetZoomValue(cFasdCockpitConfig.Instance.SlimPageZoom); }, DispatcherPriority.Normal).Task,
                    Application.Current.Dispatcher.BeginInvoke((Action)delegate { cSupportCaseDataProvider.detailsPage.SetZoomValue(cFasdCockpitConfig.Instance.DetailsPageZoom); }, DispatcherPriority.Normal).Task
                };
                await Task.WhenAll(_arrTasks);
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }
        }

        #endregion
    }
}
