using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

using C4IT.Configuration;
using C4IT.F4SD.DisplayFormatting;
using C4IT.FASD.Base;
using C4IT.FASD.Cockpit.Communication;
using C4IT.Logging;
using C4IT.MultiLanguage;

using F4SD_AdaptableIcon.Enums;

using FasdDesktopUi.Basics.CustomEvents;
using FasdDesktopUi.Basics.Enums;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.UiActions;
using FasdDesktopUi.Pages.DetailsPage.Models;
using FasdDesktopUi.Pages.SlimPage.Models;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;

using static C4IT.FASD.Base.cF4SDHealthCardRawData;
using static C4IT.Logging.cLogManager;

namespace FasdDesktopUi.Basics.Helper
{
    public class cHealthCardDataHelper
    {
        #region sub helpers

        public readonly cHealthCardSlimPageHelper SlimCard;
        public readonly cHealthCardHistoryDataHelper HistoryData;
        public readonly cHealthCardDetailPageHelper DetailPage;
        public readonly cHealthCardDataLoadingHelper LoadingHelper;
        public readonly cHealthCardCustomizableSectionHelper CustomizableSectionHelper;

        #endregion sub helpers

        #region public properties, fields & events

        public cHealthCard SelectedHealthCard { get; private set; }

        public cF4SDHealthCardRawData HealthCardRawData { get; private set; } = new cF4SDHealthCardRawData();

        public bool IsInEditMode
        {
            get => isInEditMode; set
            {
                isInEditMode = value;
                EditModeChanged?.Invoke(this, new BooleanEventArgs() { BooleanArg = value });
            }
        }

        public static event EventHandler<BooleanEventArgs> EditModeChanged;

        #endregion public properties, fields & events

        #region private properties, fields & events

        private readonly cSupportCaseDataProvider dataProvider;
        private bool isInEditMode;

        private Dictionary<enumFasdInformationClass, cHeadingDataModel> HeadingData { get; set; }

        private readonly MenuItemDataProvider _menuDataProvider;

        #endregion private properties, fields & events

        public cHealthCardDataHelper(cSupportCaseDataProvider dataProvider)
        {
            this.dataProvider = dataProvider;
            _menuDataProvider = new MenuItemDataProvider(dataProvider);
            cUtility.RawValueFormatter.SetDefaultCulture(new CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage));
            cUtility.RawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local);

            HistoryData = new cHealthCardHistoryDataHelper(this);
            SlimCard = new cHealthCardSlimPageHelper(this);
            DetailPage = new cHealthCardDetailPageHelper(this);
            LoadingHelper = new cHealthCardDataLoadingHelper(this);
            CustomizableSectionHelper = new cHealthCardCustomizableSectionHelper(this);
        }

        public void Reset()
        {
            try
            {
                HeadingData = null;

                if (HealthCardRawData?.Tables?.Count > 0)
                {
                    var tablesToRemove = HealthCardRawData.Tables.Values.Select(value => value.InformationClass)
                        .Distinct()
                        .ToList();
                    RemoveTablesWithUpdatedIdentities(tablesToRemove);
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        public void RemoveTablesWithUpdatedIdentities(List<enumFasdInformationClass> updatedInformationClasses)
        {
            try
            {
                if (updatedInformationClasses.Count <= 0)
                    return;

                //var dataProvider = cDataProviderBase.CurrentPorvider;

                if (dataProvider is null)
                    return;

                var tablesToRemove = dataProvider.HealthCardDataHelper.HealthCardRawData?.Tables?.Where(table => updatedInformationClasses.Contains(table.Value.InformationClass))
                    .Select(table => table.Key)
                    .ToArray();

                foreach (var tableToRemove in tablesToRemove)
                {
                    dataProvider.HealthCardDataHelper.HealthCardRawData?.Tables?.Remove(tableToRemove);
                }

                dataProvider.HealthCardDataHelper.HealthCardRawData?.Tables?.Remove("agnt-user");
                dataProvider.HealthCardDataHelper.HealthCardRawData?.Tables?.Remove("agnt-computer");
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        #region GetHealthCardData

        private static cHealthCard GetAvailableHealthCard(List<enumFasdInformationClass> informationClasses)
        {
            try
            {
                if (informationClasses is null)
                    return null;

                foreach (var healthCard in cF4SDCockpitXmlConfig.Instance?.HealthCardConfig?.HealthCards.Values)
                {
                    bool found = true;

                    foreach (var informationClass in informationClasses)
                    {
                        found &= healthCard.InformationClasses.Any(healthCardInformationClass => healthCardInformationClass == informationClass);
                        if (!found)
                            break;
                    }

                    found &= HasCockpitUserRequiredRoles(healthCard.RequiredRoles);

                    if (found)
                        return healthCard;
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
            }

            return null;
        }

        public static bool HasAvailableHealthCard(List<enumFasdInformationClass> informationClasses)
        {
            return GetAvailableHealthCard(informationClasses) != null;
        }

        public bool TrySetSelectedHealthcard(List<enumFasdInformationClass> informationClasses)
        {
            var _hc = GetAvailableHealthCard(informationClasses);
            if (_hc != null)
            {
                SelectedHealthCard = _hc;
                return true;
            }
            return false;
        }

        #endregion GetHealthCardData

        #region Helper

        public static bool IsUiVisible(IUiVisibilityInformation visibilityInformation, cNamedParameterList NamedParameters = null)
        {
            if (visibilityInformation == null)
                return true;

            if (visibilityInformation.IsHidden)
                return false;

            if (!string.IsNullOrEmpty(visibilityInformation.IsVisibleByParameter))
                if (!IsNamedParameterTrue(visibilityInformation.IsVisibleByParameter, NamedParameters))
                    return false;

            if (visibilityInformation.RequiredRoles != null && visibilityInformation.RequiredRoles.Count > 0)
            {
                if (!HasCockpitUserRequiredRoles(visibilityInformation.RequiredRoles))
                    return false;
            }

            return true;
        }

        private static bool HasCockpitUserRequiredRoles(List<string> requiredRoles)
        {
            try
            {
                if (requiredRoles is null || requiredRoles.Count == 0)
                    return true;

                List<string> roles = null;
                lock (cFasdCockpitCommunicationBase.CockpitUserInfoLock)
                {
                    roles = cFasdCockpitCommunicationBase.CockpitUserInfo?.Roles;
                }
                if (roles is null || roles.Count == 0)
                    return false;

                foreach (var requiredRole in requiredRoles)
                {
                    if (roles.Contains(requiredRole, StringComparer.InvariantCultureIgnoreCase))
                        return true;
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            return false;
        }

        private List<object> GetValuesOfHealthCardTableColumn(int startingIndex, cF4SDHealthCardRawData.cHealthCardTableColumn healthCardColumn)
        {
            List<object> output = new List<object>();

            if (healthCardColumn?.Values == null)
                return output;

            try
            {
                for (int i = 0; i < startingIndex; i++)
                {
                    output.Add(null);
                }

                output.AddRange(healthCardColumn.Values);
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return output;
        }

        private List<object> GetStateValues(cHealthCardTableColumn tableColumn)
        {
            if (tableColumn == null)
                return new List<object>();
            else return GetValuesOfHealthCardTableColumn(tableColumn.Table.StartingIndex, tableColumn);
        }

        private List<object> GetStateValues(cValueAddress DatabaseInfo, bool isStatic)
        {
            List<object> output = new List<object>();
            try
            {
                if (DatabaseInfo != null)
                {
                    var healthCardTable = HealthCardRawData.GetTableByName(DatabaseInfo.ValueTable, isStatic);

                    if (healthCardTable != null)
                        if (healthCardTable.Columns.TryGetValue(DatabaseInfo.ValueColumn, out var healthCardColumn))
                            output = GetValuesOfHealthCardTableColumn(healthCardTable.StartingIndex, healthCardColumn);
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            return output;
        }

        private object GetStateValueAt(cValueAddress DatabaseInfo, int index, bool isStatic)
        {
            var stateValues = GetStateValues(DatabaseInfo, isStatic);

            if (stateValues.Count <= index)
                return null;

            return stateValues[index];
        }

        private enumHighlightColor GetHighlightColorWithReference(object rawValue, cHealthCardStateBase stateDefinition)
        {
            try
            {
                object rawValueLeveling = rawValue;
                cHealthCardStateBase stateDefinitionForLeveling = stateDefinition;

                if (stateDefinition is cHealthCardStateRefLink refLinkState)
                {
                    rawValueLeveling = null;
                    var referencedStateDefinition = cF4SDHealthCardConfig.GetReferencableStateWithName(refLinkState.ParentNode, refLinkState.Reference);
                    if (referencedStateDefinition == null)
                        return enumHighlightColor.none;

                    stateDefinitionForLeveling = referencedStateDefinition;
                    if (referencedStateDefinition?.DatabaseInfo != null)
                        rawValueLeveling = GetStateValueAt(referencedStateDefinition.DatabaseInfo, 0, true);
                }

                var _color = GetHighlightColor(rawValueLeveling, stateDefinitionForLeveling, 0, true);
                return _color;
            }
            catch (Exception ex)
            {
                LogException(ex);
            }
            return enumHighlightColor.none;
        }

        private enumHighlightColor GetHighlightColor(object value, cHealthCardStateBase stateDefinition, int referenceDays, bool isStatic)
        {
            if (stateDefinition == null)
                return enumHighlightColor.none;

            enumHighlightColor output = enumHighlightColor.none;

            if (stateDefinition is cHealthCardStateAggregation _stateAggregation)
                return GetSummaryStatusColor(_stateAggregation.States, isStatic, referenceDays) ?? enumHighlightColor.none;

            try
            {
                if (value == null)
                    return output;

                if (stateDefinition is cHealthCardStateLevel stateLevel)
                {
                    var valueDouble = cF4SDHealthCardRawData.GetDouble(value);
                    if (valueDouble != null)
                    {
                        if (stateLevel.IsDirectionUp)
                            output = valueDouble >= stateLevel.Error ? enumHighlightColor.red : valueDouble >= stateLevel.Warning ? enumHighlightColor.orange : stateDefinition.IsNotTransparent ? enumHighlightColor.green : enumHighlightColor.none;
                        else
                            output = valueDouble <= stateLevel.Error ? enumHighlightColor.red : valueDouble <= stateLevel.Warning ? enumHighlightColor.orange : stateDefinition.IsNotTransparent ? enumHighlightColor.green : enumHighlightColor.none;
                    }
                }
                else if (stateDefinition is cHealthCardStateVersion stateVersion)
                {
                    var valueVersion = cF4SDHealthCardRawData.GetVersion(value);
                    if (valueVersion != null)
                    {
                        if (stateVersion.IsDirectionUp)
                            output = valueVersion >= stateVersion.Error ? enumHighlightColor.red : valueVersion >= stateVersion.Warning ? enumHighlightColor.orange : stateDefinition.IsNotTransparent ? enumHighlightColor.green : enumHighlightColor.none;
                        else
                            output = valueVersion <= stateVersion.Error ? enumHighlightColor.red : valueVersion <= stateVersion.Warning ? enumHighlightColor.orange : stateDefinition.IsNotTransparent ? enumHighlightColor.green : enumHighlightColor.none;
                    }
                }
                else if (stateDefinition is cHealthCardStateDateTime stateDateTime)
                {
                    var valueDateTime = cF4SDHealthCardRawData.GetDateTime(value);

                    if (valueDateTime != null)
                    {
                        var tempDateTime = valueDateTime ?? DateTime.Now;

                        var differenceHours = Math.Floor((DateTime.UtcNow.AddDays(-referenceDays) - tempDateTime).TotalHours);

                        if (stateDateTime.IsDirectionUp)
                            output = differenceHours >= stateDateTime.ErrorHours ? enumHighlightColor.red : differenceHours >= stateDateTime.WarningHours ? enumHighlightColor.orange : stateDefinition.IsNotTransparent ? enumHighlightColor.green : enumHighlightColor.none;
                        else
                            output = differenceHours <= stateDateTime.ErrorHours ? enumHighlightColor.red : differenceHours <= stateDateTime.WarningHours ? enumHighlightColor.orange : stateDefinition.IsNotTransparent ? enumHighlightColor.green : enumHighlightColor.none;
                    }
                }
                else if (stateDefinition is cHealthCardStateInfo)
                {
                    output = stateDefinition.IsNotTransparent ? enumHighlightColor.blue : enumHighlightColor.none;
                }
                else if (stateDefinition is cHealthCardStateTranslation stateTranslation)
                {
                    var abstractTranslation = cF4SDHealthCardConfig.GetTranslationsWithName(stateTranslation, stateTranslation.Translation);
                    if (abstractTranslation == null || !(abstractTranslation is cHealthCardTranslator translation))
                        return output;

                    enumHealthCardStateLevel translationStateLevel = translation.DefaultTranslation?.StateLevel ?? enumHealthCardStateLevel.Info;
                    foreach (var translationEntry in translation.Translations)
                    {
                        if (translationEntry.Values.Any(translationValue => value.ToString().Equals(translationValue, StringComparison.InvariantCultureIgnoreCase)))
                            translationStateLevel = translationEntry.StateLevel;
                    }

                    switch (translationStateLevel)
                    {
                        case enumHealthCardStateLevel.None:
                            output = enumHighlightColor.none;
                            break;
                        case enumHealthCardStateLevel.Ok:
                            if (stateDefinition.IsNotTransparent)
                                output = enumHighlightColor.green;
                            break;
                        case enumHealthCardStateLevel.Warning:
                            output = enumHighlightColor.orange;
                            break;
                        case enumHealthCardStateLevel.Error:
                            output = enumHighlightColor.red;
                            break;
                        case enumHealthCardStateLevel.Info:
                            if (stateDefinition.IsNotTransparent)
                                output = enumHighlightColor.blue;
                            break;
                    }
                }
                else if (stateDefinition is cHealthCardStateRefLink stateRefLink)
                {
                    //if (cHealthCardPrerequisites.GetReferencableStates(SelectedHealthCard).TryGetValue(stateRefLink.Reference, out var referencedState))
                    //    output = GetHighlightColor(thresholdValues);
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            return output;
        }

        private enumHighlightColor? GetSummaryStatusColor(List<cHealthCardStateBase> stateDefinitions, bool isStatic, int dayIndex = 0)
        {
            enumHighlightColor? output = null;
            try
            {
                foreach (var stateDefinition in stateDefinitions)
                {
                    if (!IsUiVisible(stateDefinition, dataProvider.NamedParameterEntries))
                        continue;

                    var stateValue = GetStateValueAt(stateDefinition.DatabaseInfo, dayIndex, isStatic);

                    enumHighlightColor? tempColor = null;
                    if (stateValue != null)
                    {
                        tempColor = GetHighlightColor(stateValue, stateDefinition, dayIndex, isStatic);
                        if (tempColor == enumHighlightColor.none && stateValue != null)
                            tempColor = enumHighlightColor.green;
                    }

                    if (output == null)
                        output = tempColor;
                    else if (tempColor != null)
                        output = (enumHighlightColor)Math.Max((int)tempColor, (int)output);
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            return output;
        }

        private cDataHistoryValueModel ProcessSingleStateValue(cProcessStateRequirements Requirements, object value, object thresholdValue, int columnIndex)
        {
            try
            {
                var cellContent = new cDataHistoryValueModel() { Content = null, HighlightColor = enumHighlightColor.none, IsLoading = Requirements.valueTableColumn?.IsIncomplete ?? false };

                if (Requirements.valueState is cHealthCardStateAggregation stateAggregation)
                {
                    cellContent.Content = "Ø";
                    cellContent.HighlightColor = GetSummaryStatusColor(stateAggregation.States, Requirements.isStatic, columnIndex);
                    if (cellContent.HighlightColor == null)
                    {
                        cellContent.Content = "-";
                        cellContent.HighlightColor = enumHighlightColor.none;
                    }
                }
                else
                {
                    FormattingOptions options = new FormattingOptions() { ReferenceDate = DateTime.UtcNow.Date.AddDays(columnIndex), TimeZone = TimeZoneInfo.Local };
                    var _c = cUtility.RawValueFormatter.GetDisplayValue(value, Requirements.valueState.DisplayType, options);
                    if (!string.IsNullOrWhiteSpace(_c))
                        cellContent.Content = _c;

                    cellContent.ThresholdValues = new cStateThresholdValues() { Value = thresholdValue, StateDefinition = Requirements.valueState.StateProcessingRequirements.tresholdState, ReferenceDays = columnIndex };
                    cellContent.HighlightColor = GetHighlightColor(cellContent.ThresholdValues.Value, Requirements.valueState.StateProcessingRequirements.tresholdState, columnIndex, Requirements.isStatic);

                    if (Requirements.valueState.StateProcessingRequirements.translation != null && cellContent.Content != null)
                    {
                        var translationValue = Requirements.valueState.StateProcessingRequirements.translation.DefaultTranslation?.Translation.GetValue() ?? cellContent.Content;
                        foreach (var translationEntry in Requirements.valueState.StateProcessingRequirements.translation.Translations)
                        {
                            if (translationEntry.Values.Any(_val => cellContent.Content.Equals(_val, StringComparison.CurrentCultureIgnoreCase)))
                                translationValue = translationEntry.Translation.GetValue();
                        }
                        cellContent.Content = translationValue;
                    }

                    if (cellContent.Content == null)
                        cellContent.Content = "-";

                    if (!cellContent.IsLoading && Requirements.valueTableColumn?.Table != null)
                    {
                        int maxColumnCount = 0;
                        if (Requirements.valueTableColumn.Table.Columns?.Count > 0)
                            maxColumnCount = Requirements.valueTableColumn.Table.Columns.Max(column => column.Value?.Values?.Count ?? 1);

                        if (columnIndex < Requirements.valueTableColumn.Table.StartingIndex || columnIndex >= Requirements.valueTableColumn.Table.StartingIndex + maxColumnCount)
                            cellContent.IsLoading = Requirements.valueTableColumn.Table.IsIncomplete;
                    }
                }

                if (Requirements.valueState.Details != null && value != null)
                    cellContent.UiAction = new cShowDetailedDataAction(Requirements.valueState, columnIndex);

                return cellContent;
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return null;
        }

        private cProcessStateRequirements CreateProcessStateRequirements(cHealthCardStateBase stateDefinition, bool isStatic)
        {
            var ProcessRequirements = new cProcessStateRequirements()
            {
                valueState = stateDefinition,
                valueTableColumn = null,
                isStatic = isStatic,
                Values = new List<object>(),
                ThresholdValues = new List<object>()
            };

            try
            {
                // get the global requirements one which are not support case dependent
                if (stateDefinition.StateProcessingRequirements == null)
                {
                    stateDefinition.StateProcessingRequirements = new cHealthCardStateBase.cStateProcessingRequirements() { tresholdState = stateDefinition, translation = null };

                    // if we have a ref link, get the referenced stateDefinition and state values
                    ProcessRequirements.ThresholdValues = ProcessRequirements.Values;
                    if (stateDefinition is cHealthCardStateRefLink ReferencedLinkState)
                    {
                        var refState = cF4SDHealthCardConfig.GetReferencableStateWithName(ReferencedLinkState.ParentNode, ReferencedLinkState.Reference);
                        if (refState != null)
                        {
                            stateDefinition.StateProcessingRequirements.tresholdState = refState;
                        }
                    }

                    //in state is translation state, get the translation
                    if (stateDefinition is cHealthCardStateTranslation _StateTranslation)
                    {
                        var abstractTranslation = cF4SDHealthCardConfig.GetTranslationsWithName(_StateTranslation, _StateTranslation.Translation);
                        if (abstractTranslation is cHealthCardTranslator castedTranslation)
                            stateDefinition.StateProcessingRequirements.translation = castedTranslation;
                    }

                }

                // get the state values
                if (stateDefinition.DatabaseInfo != null)
                {
                    var _table = HealthCardRawData.GetTableByName(stateDefinition.DatabaseInfo.ValueTable, isStatic);
                    if (_table != null)
                    {
                        _table.Columns.TryGetValue(stateDefinition.DatabaseInfo.ValueColumn, out ProcessRequirements.valueTableColumn);
                        ProcessRequirements.Values = GetValuesOfHealthCardTableColumn(_table.StartingIndex, ProcessRequirements.valueTableColumn);
                    }
                }

                // get the treshold values
                if (stateDefinition == stateDefinition.StateProcessingRequirements.tresholdState)
                    ProcessRequirements.ThresholdValues = ProcessRequirements.Values;
                else
                    ProcessRequirements.ThresholdValues = GetStateValues(stateDefinition.StateProcessingRequirements.tresholdState.DatabaseInfo, isStatic);
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return ProcessRequirements;
        }

        private cUiActionBase GetUiActionByQuickActionNames(List<string> names, string uiActionName, string uiActionDescription)
        {
            try
            {
                if (names?.Count is null || names.Count == 0)
                    return null;

                if (names.Count > 1)
                {
                    List<cMenuDataBase> uiActions = _menuDataProvider.GetMenuItemData()
                        .Where(data => names.Contains(data.UiAction.Name) && data.UiAction.DisplayType != enumActionDisplayType.hidden)
                        .OrderBy(action => names.IndexOf(action.UiAction.Name))
                        .Select(action => SelectWithRecommendation(action, uiActionName, uiActionDescription))
                        .ToList();

                    if (uiActions?.Count == 0)
                        return null;

                    if (uiActions?.Count == 1)
                        return uiActions[0].UiAction;

                    return new cSubMenuAction(false)
                    {
                        SubMenuData = uiActions,
                        Name = uiActionName,
                        Description = uiActionDescription,
                        DisplayType = enumActionDisplayType.enabled
                    };
                }
                else
                {
                    string quickActionName = names[0];
                    if (string.IsNullOrWhiteSpace(quickActionName))
                        return null;

                    cUiActionBase uiAction = _menuDataProvider.GetMenuItemData()
                        // .Where(data => data is cUiQuickAction)
                        .FirstOrDefault(data => data.UiAction.Name == quickActionName && data.UiAction.DisplayType == enumActionDisplayType.enabled)?.UiAction;

                    if (uiAction is cUiQuickAction uiQuickAction)
                        uiQuickAction.QuickActionRecommendation = new cRecommendationDataModel() { Category = uiActionName, Recommendation = uiActionDescription };

                    return uiAction;
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return null;

            cMenuDataBase SelectWithRecommendation(cMenuDataBase menuData, string category, string recommendation)
            {
                if (!(menuData.UiAction is cUiQuickAction uiQuickAction))
                    return menuData;

                uiQuickAction.QuickActionRecommendation = new cRecommendationDataModel() { Category = category, Recommendation = recommendation };
                return menuData;
            }
        }

        private cDataHistoryValueModel GetTitleColumnOfHealthCardState(cHealthCardStateBase stateDefinition)
        {
            cDataHistoryValueModel output = null;

            try
            {
                var titleRowContent = stateDefinition.Names.GetValue();
                var titleRowDescription = stateDefinition.Descriptions.GetValue(Default: titleRowContent);
                var titleRowPresentationStyle = stateDefinition is cHealthCardStateAggregation ? enumHistoryTitleType.aggregate : enumHistoryTitleType.header;
                cUiActionBase titleRowQuickAction = GetUiActionByQuickActionNames(stateDefinition.QuickActions, stateDefinition.Names.GetValue(), stateDefinition.Descriptions.GetValue(Default: null));

                output = new cDataHistoryValueModel() { Content = titleRowContent, ContentDescription = titleRowDescription, PresentationStyle = titleRowPresentationStyle, UiAction = titleRowQuickAction };
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return output;
        }

        private static bool IsNamedParameterTrue(string namedParameter, cNamedParameterList NamedParameters)
        {
            if (NamedParameters == null)
                return false;
            if (!NamedParameters.TryGetValue(namedParameter, out var entry))
                return false;

            var entryValue = entry.GetValue();
            cConfigRegistryHelper.ReadFromStringBoolean(entryValue, out var result);
            return result;
        }

        #endregion

        #region Editable

        public List<KeyValuePair<object, string>> GetEditInformationSelectionValues(cHealthCardStateBase stateDefinition)
        {
            List<KeyValuePair<object, string>> output = null;
            try
            {
                if (!(stateDefinition.EditInfo is cStateEditableSelection editableSelectionInfo))
                    return output;

                List<object> listValues = null;
                if (editableSelectionInfo.SelectionRawValueDatabaseInfo != null)
                    listValues = GetStateValues(editableSelectionInfo.SelectionRawValueDatabaseInfo, false);

                List<string> listDisplayValues = listValues.Select(value => value.ToString()).ToList();

                if (editableSelectionInfo.SelectionDisplayValueDatabaseInfo != null)
                    listDisplayValues = GetStateValues(editableSelectionInfo.SelectionDisplayValueDatabaseInfo, false)
                        .Select(value => value.ToString())
                        .ToList();

                if (editableSelectionInfo.Translation != null)
                {
                    var translation = cF4SDHealthCardConfig.GetTranslationsWithName(stateDefinition, editableSelectionInfo.Translation);
                    if (translation != null && translation is cHealthCardTranslator translator)
                    {
                        foreach (var displayValue in listDisplayValues.ToArray())
                        {
                            var matchingTranslation = translator.Translations.FirstOrDefault(translatorTranslation => translatorTranslation.Values.Any(value => value.Equals(displayValue, StringComparison.InvariantCultureIgnoreCase)));

                            if (matchingTranslation != null)
                                listDisplayValues[listDisplayValues.IndexOf(displayValue)] = matchingTranslation.Translation.GetValue();
                            else
                                listDisplayValues[listDisplayValues.IndexOf(displayValue)] = translator.DefaultTranslation?.Translation?.GetValue() ?? displayValue;
                        }
                    }
                }

                if (listValues.Count != listDisplayValues.Count)
                    LogEntry($"The count of edit-values and edit-display-values doesn't match in the State '{stateDefinition.Name}'.", LogLevels.Warning);

                output = Enumerable
                    .Zip(listValues, listDisplayValues, (value, displayValue) => new KeyValuePair<object, string>(value, displayValue ?? value.ToString()))
                    .ToList();
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return output;
        }

        public async Task<bool> UpdateHealthcardTableDataAsync(cValueAddress databaseInfo, object newValue)
        {
            bool output = false;
            try
            {
                var table = HealthCardRawData.GetTableByName(databaseInfo.ValueTable, false);

                if (table is null)
                    return false;

                var identity = dataProvider.Identities.FirstOrDefault(identityEnty => identityEnty.Class == table.InformationClass);
                Guid id = identity?.Id ?? Guid.Empty;

                cF4SDWriteParameters updateParameter = new cF4SDWriteParameters()
                {
                    id = id,
                    TableName = databaseInfo.ValueTable,
                    Values = new Dictionary<string, object>() { [databaseInfo.ValueColumn] = newValue }
                };

                await cFasdCockpitCommunicationBase.Instance.UpdateHealthcardTableData(updateParameter);
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return output;
        }

        #endregion

        #region Page Common

        public List<cHeadingDataModel> GetHeadingDataWithoutOnlineStatus()
        {
            Dictionary<enumFasdInformationClass, cHeadingDataModel> outputDictionary = new Dictionary<enumFasdInformationClass, cHeadingDataModel>();

            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                if (HeadingData != null)
                    outputDictionary = HeadingData;

                var healthCardHeaderConfig = SelectedHealthCard.HeaderValues;
                bool isOnline = false;

                foreach (var headerValue in healthCardHeaderConfig)
                {
                    string headingText = null;
                    var selectedTable = HealthCardRawData.GetTableByName(headerValue.DatabaseInfo.ValueTable, true);
                    if (selectedTable != null)
                        if (selectedTable.Columns.TryGetValue(headerValue.DatabaseInfo.ValueColumn, out var selectedColumn))
                            headingText = cF4SDHealthCardRawData.GetString(selectedColumn.Values[0], null);

                    cHeadingDataModel singleHeadingValue = null;
                    if (outputDictionary != null && outputDictionary.TryGetValue(headerValue.InformationClass, out singleHeadingValue))
                        if (singleHeadingValue.IsOnline && singleHeadingValue.HeadingText.Equals(headingText))
                            continue;

                    cF4sdIdentityList headingIdentities = dataProvider.Identities;

                    singleHeadingValue = new cHeadingDataModel() { InformationClass = headerValue.InformationClass, HeadingText = headingText, IsOnline = isOnline, Identities = headingIdentities };
                    outputDictionary[headerValue.InformationClass] = singleHeadingValue;
                }

                foreach (enumFasdInformationClass informationClass in Enum.GetValues(typeof(enumFasdInformationClass)))
                {
                    if (outputDictionary.ContainsKey(informationClass))
                        continue;

                    string headingText = string.Empty;

                    switch (informationClass)
                    {
                        case enumFasdInformationClass.Computer:
                            headingText = cMultiLanguageSupport.GetItem("Header.Select.Computer");
                            break;
                        case enumFasdInformationClass.Ticket:
                            headingText = cMultiLanguageSupport.GetItem("Header.Select.Ticket");
                            break;
                        case enumFasdInformationClass.VirtualSession:
                            headingText = cMultiLanguageSupport.GetItem("Header.Select.VirtualSession");
                            break;
                        case enumFasdInformationClass.MobileDevice:
                            headingText = cMultiLanguageSupport.GetItem("Header.Select.MobileDevice");
                            break;
                    }

                    outputDictionary[informationClass] = new cHeadingDataModel() { InformationClass = informationClass, HeadingText = headingText };
                }

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

            return outputDictionary.Values.ToList();
        }

        public async Task<List<cHeadingDataModel>> UpdateOnlineStatusAsync()
        {
            try
            {
                if (HeadingData is null)
                    return null;

                if (dataProvider.NamedParameterEntries.TryGetValue("AgentDeviceId", out var agentDeviceIdParameter))
                    if (int.TryParse(agentDeviceIdParameter.GetValue(), out int agentDeviceId))
                        HeadingData[enumFasdInformationClass.Computer].IsOnline = await cFasdCockpitCommunicationBase.Instance.GetAgentOnlineStatus(agentDeviceId);

                if (dataProvider.NamedParameterEntries.TryGetValue("AgentDeviceId", out var agentDeviceIdParameterUserContext))
                    if (int.TryParse(agentDeviceIdParameterUserContext.GetValue(), out int agentDeviceId))
                        if (dataProvider.NamedParameterEntries.TryGetValue("AgentUserId", out var agentUserIdParameter))
                            if (int.TryParse(agentUserIdParameter.GetValue(), out int agentUserId))
                                HeadingData[enumFasdInformationClass.User].IsOnline = await cFasdCockpitCommunicationBase.Instance.GetAgentOnlineStatus(agentDeviceId, agentUserId);
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return HeadingData?.Values?.ToList();
        }

        public string GetInformationObjectHeadingName(enumFasdInformationClass InfoClass)
        {
            if (HeadingData.TryGetValue(InfoClass, out var infoClassHeadingData))
                return infoClassHeadingData.HeadingText;
            return null;
        }

        private async Task<List<cHeadingDataModel>> GetHeadingDataAsync()
        {
            Dictionary<enumFasdInformationClass, cHeadingDataModel> outputDictionary = new Dictionary<enumFasdInformationClass, cHeadingDataModel>();

            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                if (HeadingData != null)
                    outputDictionary = HeadingData;

                var healthCardHeaderConfig = SelectedHealthCard.HeaderValues;
                bool isOnline = false;

                foreach (var headerValue in healthCardHeaderConfig)
                {
                    string headingText = null;
                    var selectedTable = HealthCardRawData.GetTableByName(headerValue.DatabaseInfo.ValueTable, true);
                    if (selectedTable != null)
                        if (selectedTable.Columns.TryGetValue(headerValue.DatabaseInfo.ValueColumn, out var selectedColumn))
                            headingText = cF4SDHealthCardRawData.GetString(selectedColumn.Values[0], null);

                    cHeadingDataModel singleHeadingValue = null;
                    if (outputDictionary != null)
                        outputDictionary.TryGetValue(headerValue.InformationClass, out singleHeadingValue);


                    cF4sdIdentityList headingIdentities = dataProvider.Identities;

                    switch (headerValue.InformationClass)
                    {
                        case enumFasdInformationClass.Computer:
                            if (dataProvider.NamedParameterEntries.TryGetValue("AgentDeviceId", out var agentDeviceIdParameter))
                                if (int.TryParse(agentDeviceIdParameter.GetValue(), out int agentDeviceId))
                                    isOnline = await cFasdCockpitCommunicationBase.Instance.GetAgentOnlineStatus(agentDeviceId);
                            break;
                        case enumFasdInformationClass.User:
                            if (dataProvider.NamedParameterEntries.TryGetValue("AgentDeviceId", out var agentDeviceIdParameterUserContext))
                                if (int.TryParse(agentDeviceIdParameterUserContext.GetValue(), out int agentDeviceId))
                                    if (dataProvider.NamedParameterEntries.TryGetValue("AgentUserId", out var agentUserIdParameter))
                                        if (int.TryParse(agentUserIdParameter.GetValue(), out int agentUserId))
                                            isOnline = await cFasdCockpitCommunicationBase.Instance.GetAgentOnlineStatus(agentDeviceId, agentUserId);
                            break;
                        case enumFasdInformationClass.Ticket:

                            //todo: check ticket status not via stored relations!
                            if (dataProvider.CaseRelations != null && dataProvider.CaseRelations.TryGetValue(enumFasdInformationClass.Ticket, out var ticketValues))
                            {
                                var selectedTicket = ticketValues.FirstOrDefault(value => dataProvider.Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.Ticket)?.Id == value.id);
                                if (selectedTicket != null)
                                {
                                    if (selectedTicket.Infos.TryGetValue("StatusId", out var statusIdString))
                                    {
                                        Enum.TryParse(statusIdString, out enumTicketStatus statusId);
                                        isOnline = statusId != enumTicketStatus.Closed;
                                    }
                                }
                            }
                            break;
                        case enumFasdInformationClass.VirtualSession:

                            if (dataProvider.CaseRelations != null && dataProvider.CaseRelations.TryGetValue(enumFasdInformationClass.VirtualSession, out var virtualSessionValues))
                            {
                                var selectedVirtualSession = virtualSessionValues.FirstOrDefault(value => dataProvider.Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.VirtualSession)?.Id == value.id);
                                if (selectedVirtualSession != null)
                                {
                                    if (selectedVirtualSession.Infos.TryGetValue("Status", out var statusIdString))
                                    {
                                        Enum.TryParse(statusIdString, out enumCitrixSessionStatus statusId);
                                        isOnline = statusId == enumCitrixSessionStatus.Active;
                                    }
                                }
                            }
                            break;
                        case enumFasdInformationClass.MobileDevice:

                            //todo: check ticket status not via stored relations!
                            if (dataProvider.CaseRelations != null && dataProvider.CaseRelations.TryGetValue(enumFasdInformationClass.MobileDevice, out var mobileDeviceValues))
                            {
                                var selectedMobileDevice = mobileDeviceValues.FirstOrDefault(value => dataProvider.Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.MobileDevice)?.Id == value.id);
                            }
                            break;
                    }

                    singleHeadingValue = new cHeadingDataModel() { InformationClass = headerValue.InformationClass, HeadingText = headingText, IsOnline = isOnline, Identities = headingIdentities };
                    outputDictionary[headerValue.InformationClass] = singleHeadingValue;
                }

                foreach (enumFasdInformationClass informationClass in Enum.GetValues(typeof(enumFasdInformationClass)))
                {
                    if (outputDictionary.ContainsKey(informationClass))
                        continue;

                    string headingText = string.Empty;

                    switch (informationClass)
                    {
                        case enumFasdInformationClass.Computer:
                            headingText = cMultiLanguageSupport.GetItem("Header.Select.Computer");
                            break;
                        case enumFasdInformationClass.Ticket:
                            headingText = cMultiLanguageSupport.GetItem("Header.Select.Ticket");
                            break;
                    }

                    outputDictionary[informationClass] = new cHeadingDataModel() { InformationClass = informationClass, HeadingText = headingText };
                }

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

            return outputDictionary.Values.ToList();
        }

        private List<cMenuDataBase> GetMenuBarData() => _menuDataProvider.GetMenuItemData()
            .Where(data => (data.MenuSections?.Count == 0 || data.IconPositionIndex > -1) && data.UiAction?.DisplayType != enumActionDisplayType.hidden)
            .ToList();

        #endregion

        #region NamedParameters

        public string ReplaceNamedParameters(string rawString, bool shouldUseHtml)
        {
            var output = rawString;
            try
            {
                foreach (var namedParameterEntry in dataProvider.NamedParameterEntries)
                {
                    try
                    {
                        if (namedParameterEntry.Value is cNamedParameterEntryCopyTemplate _)
                            continue;

                        var parameterName = namedParameterEntry.Key;

                        var (Title, Value) = namedParameterEntry.Value.GetTitleValuePair();
                        var parameterLabel = string.Format("{0}:", Title);
                        var parameterValue = Value;

                        if (shouldUseHtml)
                            parameterValue = namedParameterEntry.Value.GetHtmlValue();

                        output = output.Replace("%" + parameterName + ".Label%", parameterLabel);
                        output = output.Replace("%" + parameterName + ".Value%", parameterValue);
                    }
                    catch { }
                }

                bool found = true;
                while (found)
                {
                    var _pos1 = output.IndexOf(".Label%");
                    var _pos2 = output.IndexOf(".Value%");
                    int _pos = -1;
                    if (_pos1 < 0)
                        _pos = _pos2;
                    else if (_pos2 < 0)
                        _pos = _pos1;
                    else
                        _pos = Math.Min(_pos1, _pos2);

                    if (_pos < 0)
                    {
                        found = false;
                        continue;
                    }

                    var _strSub = output.Substring(0, _pos);
                    _pos1 = _strSub.LastIndexOf("%");
                    if (_pos1 > 0)
                    {
                        _strSub = output.Substring(_pos1, _pos + 7 - _pos1);
                        output = output.Replace(_strSub, "");
                    }
                    else
                        found = false;
                }
                ;
            }
            catch (Exception E)
            {
                LogException(E);
            }
            return output;
        }

        internal void UpdateNamedParameterEntries()
        {
            try
            {
                var namedParameters = cHealthCardPrerequisites.GetNamedParameters(SelectedHealthCard);

                foreach (var namedParameter in namedParameters)
                {
                    try
                    {
                        if (namedParameter.Value.ParameterName == null)
                            continue;

                        string namedParameterTitle = namedParameter.Value.Names.GetValue();

                        var parameterValue = GetStateValueAt(namedParameter.Value.DatabaseInfo, 0, true);
                        string namedParameterValue = cUtility.RawValueFormatter.GetDisplayValue(parameterValue, namedParameter.Value.Display);

                        if (!dataProvider.NamedParameterEntries.ContainsKey(namedParameter.Value.ParameterName))
                            dataProvider.NamedParameterEntries.Add(namedParameter.Value.ParameterName, new cNamedParameterEntryPointer(dataProvider, namedParameter.Value.DatabaseInfo, namedParameter.Value.Display) { Title = namedParameterTitle });
                    }
                    catch (Exception ex)
                    {
                        LogException(ex);
                    }
                }

                const string defaultCopyTemplateParameterName = "Copy_default";
                if (!dataProvider.NamedParameterEntries.ContainsKey(defaultCopyTemplateParameterName))
                {
                    string defaultCopyTemplate = cF4SDCockpitXmlConfig.Instance?.CopyTemplateConfig?.CopyTemplates.DefaultTemplate.Name;
                    dataProvider.NamedParameterEntries.Add(defaultCopyTemplateParameterName, new cNamedParameterEntryCopyTemplate(dataProvider, defaultCopyTemplate));
                }

                foreach (var copyTemplate in cF4SDCockpitXmlConfig.Instance?.CopyTemplateConfig?.CopyTemplates.CopyTemplates)
                {
                    string namedParameterName = "Copy_" + copyTemplate.Key;

                    if (dataProvider.NamedParameterEntries.ContainsKey(namedParameterName))
                        continue;

                    dataProvider.NamedParameterEntries.Add(namedParameterName, new cNamedParameterEntryCopyTemplate(dataProvider, copyTemplate.Key));
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        #endregion

        private class cProcessStateRequirements
        {
            internal cHealthCardStateBase valueState;
            internal bool isStatic;
            internal cHealthCardTableColumn valueTableColumn;
            internal List<object> Values;
            internal List<object> ThresholdValues;
        }

        public abstract class cHealthCardStateSubHelper
        {
            protected readonly cHealthCardDataHelper parent;

            protected cSupportCaseDataProvider dataProvider { get { return parent.dataProvider; } }

            protected cHealthCard SelectedHealthCard { get { return parent.SelectedHealthCard; } }

            protected cF4SDHealthCardRawData HealthCardRawData { get { return parent.HealthCardRawData; } }

            internal cHealthCardStateSubHelper(cHealthCardDataHelper parent)
            {
                this.parent = parent;
            }
        }

        public class cHealthCardHistoryDataHelper : cHealthCardStateSubHelper
        {
            internal cHealthCardHistoryDataHelper(cHealthCardDataHelper parent) : base(parent) { }

            internal cDetailsPageDataHistoryDataModel GetData()
            {
                var CM = MethodBase.GetCurrentMethod();
                LogMethodBegin(CM);

                cDetailsPageDataHistoryDataModel output = new cDetailsPageDataHistoryDataModel();
                try
                {
                    var healthCardHistoryConfig = SelectedHealthCard.CategoriesHistory;

                    if (healthCardHistoryConfig is null)
                        return output;

                    foreach (var stateCategoryDefinition in healthCardHistoryConfig.StateCategories)
                    {
                        if (!IsUiVisible(stateCategoryDefinition, dataProvider.NamedParameterEntries))
                            continue;

                        var categoryContent = stateCategoryDefinition.Names.GetValue();
                        var categoryContentDescription = stateCategoryDefinition.Descriptions.GetValue(Default: categoryContent);
                        cUiActionBase categoryQuickAction = parent.GetUiActionByQuickActionNames(stateCategoryDefinition.QuickActions, stateCategoryDefinition.Names.GetValue(), stateCategoryDefinition.Descriptions.GetValue(Default: null));

                        var titleColumn = new DetailsPageDataHistoryColumnModel()                         //todo: refactor, see same code in titleRow
                        {
                            Content = categoryContent,
                            ContentDescription = categoryContentDescription,
                            UiAction = categoryQuickAction,
                            ColumnValues = new List<cDataHistoryValueModel>()
                        };

                        // Adding columns to history section
                        int valueColumnCount = SelectedHealthCard.MaxAgeInDays;
                        var historySectionValueColumns = new List<DetailsPageDataHistoryColumnModel>(valueColumnCount);
                        for (int i = 0; i < valueColumnCount; i++)
                        {
                            CultureInfo culture = new CultureInfo(cMultiLanguageSupport.CurrentLanguage);
                            var valueColumnHeader = i != 0 ? DateTime.Today.AddDays(-i).ToString(cMultiLanguageSupport.GetItem("Global.Date.Format.ShortDateWithDay", "ddd. dd.MM."), culture) : cMultiLanguageSupport.GetItem("Global.Date.Today");
                            var summaryStatusColor = parent.GetSummaryStatusColor(stateCategoryDefinition.States, false, i);
                            var valueColumn = new DetailsPageDataHistoryColumnModel() { ColumnValues = new List<cDataHistoryValueModel>(), Content = valueColumnHeader, HighlightColor = summaryStatusColor ?? enumHighlightColor.none };
                            historySectionValueColumns.Add(valueColumn);
                        }


                        foreach (var stateDefinition in stateCategoryDefinition.States)
                        {
                            if (!IsUiVisible(stateDefinition, dataProvider.NamedParameterEntries))
                                continue;

                            if (stateDefinition.DatabaseInfo != null && HealthCardRawData.Tables.ContainsKey(stateDefinition.DatabaseInfo.ValueTable) == false)
                                continue;

                            var titleRowData = parent.GetTitleColumnOfHealthCardState(stateDefinition);
                            if (titleRowData != null)
                                titleColumn.ColumnValues.Add(titleRowData);

                            ProcessState(stateDefinition, valueColumnCount, false, historySectionValueColumns);

                            //StateAggregation
                            if (stateDefinition is cHealthCardStateAggregation stateAggregationDefinition)
                            {
                                foreach (var aggregatedStateDefinition in stateAggregationDefinition.States)
                                {
                                    if (!IsUiVisible(aggregatedStateDefinition, dataProvider.NamedParameterEntries))
                                        continue;

                                    var aggregatedTitleRowData = parent.GetTitleColumnOfHealthCardState(aggregatedStateDefinition);
                                    if (aggregatedStateDefinition != null)
                                    {
                                        aggregatedTitleRowData.PresentationStyle = enumHistoryTitleType.subValue;
                                        titleColumn.ColumnValues.Add(aggregatedTitleRowData);
                                    }

                                    ProcessState(aggregatedStateDefinition, valueColumnCount, false, historySectionValueColumns);
                                }
                            }
                        }

                        output.Add(new cDetailsPageDataHistoryCategoryDataModel()
                        {
                            TitleColumn = titleColumn,
                            ValueColumns = historySectionValueColumns
                        });
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }
                finally
                {
                    LogMethodEnd(CM);
                }

                return output;
            }

            private void ProcessState(cHealthCardStateBase stateDefinition, int valueColumnCount, bool isStatic, List<DetailsPageDataHistoryColumnModel> historySectionValueColumns)
            {

                var ProcessRequirements = parent.CreateProcessStateRequirements(stateDefinition, isStatic);

                for (int i = 0; i < valueColumnCount; i++)
                {
                    var Value = ProcessRequirements.Values?.Count > i ? ProcessRequirements.Values[i] : null;
                    var thresholdValue = ProcessRequirements.ThresholdValues?.Count > i ? ProcessRequirements.ThresholdValues[i] : null;

                    var cellContent = parent.ProcessSingleStateValue(ProcessRequirements, Value, thresholdValue, i);

                    historySectionValueColumns[i].ColumnValues.Add(cellContent);
                }
            }

        }

        public class cHealthCardSlimPageHelper : cHealthCardStateSubHelper
        {
            public async Task<cSlimPageData> GetDataAsync()
            {
                var CM = MethodBase.GetCurrentMethod();
                LogMethodBegin(CM);

                cSlimPageData output = new cSlimPageData();
                try
                {
                    if (SelectedHealthCard == null)
                        return output;

                    output.DataProvider = dataProvider;
                    output.HeadingData = await parent.GetHeadingDataAsync();
                    output.WidgetData = GetWidgetData();
                    output.DataHistoryList = GetHistoryData();
                    output.MenuBarData = parent.GetMenuBarData();
                }
                catch (Exception E)
                {
                    LogException(E);
                }
                finally
                {
                    LogMethodEnd(CM);
                }

                return output;
            }

            internal cHealthCardSlimPageHelper(cHealthCardDataHelper parent) : base(parent) { }

            private List<List<cWidgetValueModel>> GetWidgetData()
            {
                var CM = MethodBase.GetCurrentMethod();
                LogMethodBegin(CM);
                var output = new List<List<cWidgetValueModel>>();

                try
                {
                    var healthCardWidgetConfig = SelectedHealthCard.CategoriesStaticSlim;

                    foreach (var categoryDefinition in healthCardWidgetConfig.StateCategories)
                    {
                        if (!IsUiVisible(categoryDefinition, dataProvider.NamedParameterEntries))
                            continue;

                        var widgetValues = new List<cWidgetValueModel>();

                        foreach (var stateDefinition in categoryDefinition.States)
                        {
                            if (!IsUiVisible(stateDefinition, dataProvider.NamedParameterEntries))
                                continue;

                            if (HealthCardRawData.Tables.ContainsKey(stateDefinition.DatabaseInfo?.ValueTable) == false)
                                continue;

                            var stateModel = stateDefinition;

                            var widgetValueToAdd = new cWidgetValueModel { TechnicalName = stateDefinition.ParameterName };

                            if (!stateDefinition.IsTitleOptional && stateDefinition.Names.Count > 0)
                                widgetValueToAdd.Title = stateDefinition.Names.GetValue();

                            if (stateDefinition.DatabaseInfo != null)
                            {
                                object widgetValue = parent.GetStateValueAt(stateDefinition.DatabaseInfo, 0, true);
                                widgetValueToAdd.Value = cUtility.RawValueFormatter.GetDisplayValue(widgetValue, stateDefinition.DisplayType);

                                object stateValue = widgetValue;
                                if (stateDefinition is cHealthCardStateRefLink refLinkState)
                                {
                                    stateModel = cF4SDHealthCardConfig.GetReferencableStateWithName(stateDefinition.ParentNode, refLinkState.Reference);
                                    stateValue = parent.GetStateValueAt(stateModel.DatabaseInfo, 0, true);
                                }

                                var widgetHighlightColor = parent.GetHighlightColor(stateValue, stateModel, 0, true);
                                widgetValueToAdd.HighlightIn = widgetHighlightColor;

                                widgetValues.Add(widgetValueToAdd);
                            }
                        }

                        if (widgetValues?.Count <= 0)
                            continue;

                        output.Add(widgetValues);
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }
                finally
                {
                    LogMethodEnd(CM);
                }

                return output;
            }

            private List<cSlimPageDataHistoryModel> GetHistoryData()
            {
                var CM = MethodBase.GetCurrentMethod();
                LogMethodBegin(CM);

                List<cSlimPageDataHistoryModel> output = new List<cSlimPageDataHistoryModel>();
                try
                {
                    var healthCardHistoryConfig = SelectedHealthCard.CategoriesHistory;

                    if (healthCardHistoryConfig is null)
                        return output;

                    foreach (var categoryDefinition in healthCardHistoryConfig.StateCategories)
                    {
                        if (!IsUiVisible(categoryDefinition, dataProvider.NamedParameterEntries))
                            continue;

                        var slimPageData = new cSlimPageDataHistoryModel()
                        {
                            Content = categoryDefinition.Names.GetValue(),
                            ContentDescription = categoryDefinition.Descriptions.GetValue(),
                            ValueColumns = new List<cDataHistoryValueModel>()
                        };

                        for (int i = 0; i < 6; i++)
                        {
                            bool isLoading = false;
                            foreach (var stateDefinition in categoryDefinition?.States)
                            {
                                if (!IsUiVisible(stateDefinition, dataProvider.NamedParameterEntries))
                                    continue;

                                if (stateDefinition.DatabaseInfo != null)
                                {
                                    var stateTable = HealthCardRawData.GetTableByName(stateDefinition.DatabaseInfo.ValueTable, false);
                                    if (stateTable != null)
                                    {
                                        int tableColumnCount = 0;
                                        try
                                        {
                                            if (stateTable?.Columns?.Count > 0)
                                                tableColumnCount = stateTable.Columns.Max(column => column.Value?.Values?.Count ?? 1); //todo: check for better implementation
                                        }
                                        catch { }

                                        if (i < stateTable.StartingIndex || i >= stateTable.StartingIndex + tableColumnCount)
                                            isLoading = stateTable.IsIncomplete;
                                    }
                                }

                            }

                            var tempContent = i != 0 ? DateTime.Today.AddDays(-i).ToString("dd.MM") : cMultiLanguageSupport.GetItem("Global.Date.Today");
                            var tempHighlightColor = parent.GetSummaryStatusColor(categoryDefinition.States, false, i);
                            slimPageData.ValueColumns.Add(new cDataHistoryValueModel() { Content = tempContent, HighlightColor = tempHighlightColor ?? enumHighlightColor.none, IsLoading = isLoading });
                        }

                        //SummaryValueColumn
                        var summaryValueColumnContent = $"{DateTime.Today.AddDays(-7):dd.MM} - {DateTime.Today.AddDays(-14):dd.MM}";
                        enumHighlightColor summaryValueColumnColor = enumHighlightColor.none;
                        bool isSummaryLoading = false;

                        for (int i = 7; i < 14; i++)
                        {
                            foreach (var stateDefinition in categoryDefinition?.States)
                            {
                                if (!IsUiVisible(stateDefinition, dataProvider.NamedParameterEntries))
                                    continue;
                                if (stateDefinition.DatabaseInfo != null)
                                {
                                    var stateTable = HealthCardRawData.GetTableByName(stateDefinition.DatabaseInfo.ValueTable, false);

                                    if (stateTable != null)
                                    {
                                        int tableColumnCount = 0;
                                        try
                                        {
                                            if (stateTable?.Columns?.Count > 0)
                                                tableColumnCount = stateTable.Columns.Max(column => column.Value?.Values?.Count ?? 1);
                                        }
                                        catch { }

                                        if (i < stateTable.StartingIndex || i >= stateTable.StartingIndex + tableColumnCount)
                                        {
                                            isSummaryLoading = stateTable.IsIncomplete;
                                            break;
                                        }
                                    }
                                }

                            }

                            summaryValueColumnColor = (enumHighlightColor)Math.Max((int)summaryValueColumnColor, (int)(parent.GetSummaryStatusColor(categoryDefinition.States, false, i) ?? enumHighlightColor.none));
                        }

                        var summaryValueColumn = new cDataHistoryValueModel() { Content = summaryValueColumnContent, HighlightColor = summaryValueColumnColor, IsLoading = isSummaryLoading };
                        slimPageData.ValueColumns.Add(summaryValueColumn);

                        output.Add(slimPageData);
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }
                finally
                {
                    LogMethodEnd(CM);
                }

                return output;
            }

        }

        public class cHealthCardDetailPageHelper : cHealthCardStateSubHelper
        {
            public async Task<cDetailsPageData> GetDataAsync()
            {
                var CM = MethodBase.GetCurrentMethod();
                LogMethodBegin(CM);

                cDetailsPageData output = new cDetailsPageData();
                try
                {
                    if (SelectedHealthCard == null)
                        return output;

                    output.DataProvider = dataProvider;
                    output.HeadingData = await parent.GetHeadingDataAsync();
                    output.WidgetData = GetWidgetsData();
                    output.DataHistoryList = parent.HistoryData.GetData();
                    output.DataContainerCollectionList = parent.CustomizableSectionHelper.GetContainerCollectionData();
                    output.MenuBarData = parent.GetMenuBarData();
                }
                catch (Exception E)
                {
                    LogException(E);
                }
                finally
                {
                    LogMethodEnd(CM);
                }

                return output;
            }

            public cDetailsPageData GetDataWithoutHeading()
            {
                cDetailsPageData output = new cDetailsPageData();
                try
                {
                    if (SelectedHealthCard == null)
                        return output;

                    output.DataProvider = dataProvider;
                    output.WidgetData = GetWidgetsData();
                    output.DataHistoryList = parent.HistoryData.GetData();
                    output.DataContainerCollectionList = parent.CustomizableSectionHelper.GetContainerCollectionData();
                    output.MenuBarData = parent.GetMenuBarData();
                }
                catch (Exception E)
                {
                    LogException(E);
                }
                return output;
            }

            internal cHealthCardDetailPageHelper(cHealthCardDataHelper parent) : base(parent) { }

            private List<object[]> getDetailsValuesCsv(string Data, cHealthCardDetailsValued StateDetailsValued)
            {
                MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }

                var _values = new List<object[]>();

                try
                {
                    var _arrRow = Data.Split(StateDetailsValued.RowSeparator);
                    foreach (var _row in _arrRow)
                    {
                        if (string.IsNullOrEmpty(_row))
                            continue;

                        var _entry = new List<object>();
                        if (StateDetailsValued.ColSeparator == null)
                            _entry.Add(_row.Trim());
                        else
                        {
                            var _arrCol = Data.Split((char)StateDetailsValued.ColSeparator);
                            foreach (var _col in _arrCol)
                                _entry.Add(_col.Trim());
                        }

                        while (_entry.Count < StateDetailsValued.Count)
                            _entry.Add(null);

                        _values.Add(_entry.ToArray());
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }
                finally
                {
                    if (CM != null) LogMethodEnd(CM);
                }

                return _values;
            }

            private List<object[]> getDetailsValuesJson(string Data, cHealthCardDetailsValued StateDetailsValued)
            {
                MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }


                try
                {
                    var _rawVals = JsonConvert.DeserializeObject<List<JObject>>(Data);
                    if (_rawVals?.Count > 0)
                    {
                        var _values = new List<object[]>();
                        foreach (JObject _row in _rawVals)
                        {
                            var _props = _row.Children();

                            var _valRow = new object[StateDetailsValued.Count];
                            for (int i = 0; i < StateDetailsValued.Count; i++) _valRow[i] = null;

                            foreach (var _token in _props)
                            {
                                if (!(_token is JProperty jProp))
                                    continue;

                                var _name = jProp.Name;
                                var _i = StateDetailsValued.FindIndex(v => v.Column.Equals(_name, StringComparison.InvariantCultureIgnoreCase));
                                if (_i < 0)
                                    continue;

                                var _col = StateDetailsValued[_i];
                                if (jProp.Value is JValue jValue)
                                {
                                    var _value = jValue.Value;
                                    var _displayString = cUtility.RawValueFormatter.GetDisplayValue(_value, _col.DisplayType);
                                    _valRow[_i] = _displayString;
                                }

                            }
                            _values.Add(_valRow);
                        }

                        return _values;

                    }

                }
                catch (Exception E)
                {
                    LogException(E);
                }
                finally
                {
                    if (CM != null) LogMethodEnd(CM);
                }

                return null;
            }

            private cHealthCardDetailsTable GetDetailTableValued(object _value, cHealthCardDetailsValued StateDetailsValued)
            {
                MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }

                try
                {
                    if (_value == null)
                        return null;

                    var _strData = cUtility.RawValueFormatter.GetDisplayValue(_value, RawValueType.STRING);
                    if (_strData == null)
                        return null;

                    List<object[]> _values = new List<object[]>();
                    if (StateDetailsValued.Format == cHealthCardDetailsValued.ValuedFormat.json)
                        _values = getDetailsValuesJson(_strData, StateDetailsValued);
                    else
                        _values = getDetailsValuesCsv(_strData, StateDetailsValued);

                    var Result = new cHealthCardDetailsTable()
                    {
                        Name = "Details-" + StateDetailsValued.ParentState.Name,
                        Columns = StateDetailsValued.Select(v => v.Names.GetValue()).ToList(),
                        Values = new Dictionary<int, List<object[]>>() { { 0, _values } }
                    };

                    return Result;
                }
                catch (Exception E)
                {
                    LogException(E);
                }
                finally
                {
                    if (CM != null) LogMethodEnd(CM);
                }


                return null;
            }

            private cWidgetValueModel GetWidgetRowData(cHealthCardStateBase stateDefinition)
            {
                try
                {
                    if (!IsUiVisible(stateDefinition, dataProvider.NamedParameterEntries))
                        return null;

                    var widgetRowData = new cWidgetValueModel
                    {
                        Title = stateDefinition.Names?.GetValue(),
                        TechnicalName = stateDefinition.ParameterName,
                        IsLoading = IsValueIncomplete(stateDefinition.DatabaseInfo, true),
                        Value = "N/A",
                        UiActionTitle = parent.GetUiActionByQuickActionNames(stateDefinition.QuickActions, stateDefinition.Names.GetValue(), stateDefinition.Descriptions.GetValue())
                    };

                    if (stateDefinition.DatabaseInfo is null)
                        return widgetRowData;

                    object rawValueDisplay = parent.GetStateValueAt(stateDefinition.DatabaseInfo, 0, true);

                    widgetRowData.HighlightIn = parent.GetHighlightColorWithReference(rawValueDisplay, stateDefinition);

                    widgetRowData.EditValueInformation = GetEditInfo(rawValueDisplay);

                    bool shouldShowValueDetails =
                        (TryGetValuedDetails(rawValueDisplay, out var valuedDetails)
                          && (valuedDetails?.Values?.Values?.FirstOrDefault()?.Count > 1)
                          || (valuedDetails?.Values?.Values?.FirstOrDefault()?.FirstOrDefault()?.Length > 1)
                        )
                        || (stateDefinition.Details is cHealthCardDetails && rawValueDisplay != null && rawValueDisplay.ToString() != "0");

                    if (shouldShowValueDetails)
                    {
                        widgetRowData.ValuedDetails = valuedDetails;
                        widgetRowData.UiActionValue = new cShowDetailedDataAction(stateDefinition, valuedDetailsData: valuedDetails)
                        {
                            DisplayType = enumActionDisplayType.enabled
                        };
                    }

                    widgetRowData.Value = GetDisplayValue(rawValueDisplay, valuedDetails);

                    return widgetRowData;
                }
                catch (Exception ex)
                {
                    LogException(ex);
                }

                return null;

                cEditableValueInformationBase GetEditInfo(object rawValue)
                {
                    if (stateDefinition?.EditInfo is null)
                        return null;

                    switch (stateDefinition.EditInfo)
                    {
                        //todo: add Ids to editableInformation
                        case cStateEditableSelection editableSelectionInfo:
                            var editSelectionValues = parent.GetEditInformationSelectionValues(stateDefinition);
                            return new cEditValueInformationSelection() { CurrentValue = rawValue, Description = stateDefinition.Names.GetValue(), DatabaseInfo = stateDefinition.DatabaseInfo, SelectionValues = editSelectionValues };
                        case cStateEditableText edtiableTextInfo:
                            var editValue = new List<object>(1) { rawValue };
                            return new cEditValueInformationText() { CurrentValue = rawValue, Description = stateDefinition.Names.GetValue(), DatabaseInfo = stateDefinition.DatabaseInfo };
                        default:
                            return null;
                    }
                }

                string GetDisplayValue(object rawValue, cHealthCardDetailsTable detailTable)
                {
                    string displayValue = null;

                    if (stateDefinition is cHealthCardStateTranslation translationDefinition)
                        displayValue = GetTranslationValue(translationDefinition, rawValue);

                    if (detailTable != null)
                        displayValue = GetDetailStringValue(rawValue, detailTable);

                    return displayValue ?? cUtility.RawValueFormatter.GetDisplayValue(rawValue, stateDefinition.DisplayType);
                }

                string GetTranslationValue(cHealthCardStateTranslation translationDefinition, object rawValue)
                {
                    ITranslatorObject abstractTranslation = cF4SDHealthCardConfig.GetTranslationsWithName(translationDefinition, translationDefinition.Translation);

                    if (abstractTranslation is null || !(abstractTranslation is cHealthCardTranslator translation))
                        return null;

                    if (rawValue is null)
                        return translation.DefaultTranslation?.Translation?.GetValue();

                    var translationValue = translation.DefaultTranslation?.Translation?.GetValue() ?? rawValue.ToString();

                    foreach (var translationEntry in translation.Translations)
                    {
                        if (translationEntry.Values.Any(value => rawValue.ToString().Equals(value, StringComparison.InvariantCultureIgnoreCase)))
                            return translationEntry.Translation.GetValue();
                    }
                    return translationValue;
                }

                string GetDetailStringValue(object rawValue, cHealthCardDetailsTable detailTableValueTable)
                {
                    if (detailTableValueTable?.Values is null || detailTableValueTable.Values.Count == 0)
                        return null;

                    var tableValues = detailTableValueTable.Values.First().Value;
                    if (detailTableValueTable.Columns.Count >= 1 && tableValues.Count == 1)
                        return cUtility.RawValueFormatter.GetDisplayValue(detailTableValueTable.Values.First().Value.First()?.First(), stateDefinition.Details.First().DisplayType);
                    else
                        return cUtility.RawValueFormatter.GetDisplayValue(detailTableValueTable.Values.First().Value.Count, RawValueType.STRING);
                }

                bool TryGetValuedDetails(object rawValue, out cHealthCardDetailsTable valuedDetails)
                {
                    valuedDetails = null;

                    if (!(stateDefinition.Details is cHealthCardDetailsValued detailsValued))
                        return false;

                    valuedDetails = GetDetailTableValued(rawValue, detailsValued);
                    return true;
                }
            }

            private List<List<cWidgetValueModel>> GetWidgetsData()
            {
                var CM = MethodBase.GetCurrentMethod();
                LogMethodBegin(CM);

                try
                {
                    return SelectedHealthCard.CategoriesStatic.StateCategories
                        .Where(widgetDefinition => IsUiVisible(widgetDefinition, dataProvider.NamedParameterEntries))
                        .Select(widgetDefinition => GetWidgetData(widgetDefinition))
                        .ToList();
                }
                catch (Exception ex)
                {
                    LogException(ex);
                }
                finally
                {
                    LogMethodEnd(CM);
                }

                return new List<List<cWidgetValueModel>>();

                List<cWidgetValueModel> GetWidgetData(cHealthCardStateCategory widgetDefinition)
                {
                    try
                    {
                        return widgetDefinition.States.Select(GetWidgetRowData)
                            .Where(value => value != null)
                            .ToList();
                    }
                    catch (Exception ex)
                    {
                        LogException(ex);
                    }

                    return new List<cWidgetValueModel>();
                }
            }

            private bool IsValueIncomplete(cValueAddress databaseInfo, bool isStatic)
            {
                try
                {
                    var healthCardTable = HealthCardRawData.GetTableByName(databaseInfo.ValueTable, isStatic);

                    if (healthCardTable is null)
                        return false;

                    if (!healthCardTable.IsIncomplete)
                        return false;

                    if (!healthCardTable.Columns.TryGetValue(databaseInfo.ValueColumn, out var column))
                        return true;

                    return column.IsIncomplete;
                }
                catch (Exception e)
                {
                    LogException(e);
                }

                return false;
            }

        }

        public class cHealthCardDataLoadingHelper : cHealthCardStateSubHelper
        {
            public event EventHandler DataChanged;

            public event EventHandler DataFullyLoaded;

            public event EventHandler DataRefreshed;

            public DateTime? LastDataRequest { get; set; } = null;

            public async Task RefreshLatestDataAsync()
            {
                var CM = MethodBase.GetCurrentMethod();
                LogMethodBegin(CM);
                try
                {
                    if (dataProvider.DirectConnectionHelper.IsDirectConnectionActive)
                    {
                        var actualizeResult = await ActualizeDataAsync();

                        if (actualizeResult == enumActualizeStatus.failed)
                            LogEntry("Failed to actualize data, due to server timeout.", LogLevels.Error);
                    }

                    var requiredTables = HealthCardRawData.Tables.Keys.Where(tableKey => tableKey.StartsWith("Computation_") is false).ToList();

                    if (requiredTables is null || requiredTables.Count <= 0)
                        return;

                    var request = new cF4sdHealthCardRawDataRequest() { Identities = dataProvider.Identities, Tables = requiredTables, MaxAge = cF4SDCockpitXmlConfig.Instance?.HealthCardConfig?.SearchResultAge ?? 14 }; //todo: reduce requested days to 1


                    await LoadingRawDataCriticalSection.EnterAsync();

                    try
                    {
                        var newRawData = await cFasdCockpitCommunicationBase.Instance.GetHealthCardData(request);

                        UpdateLatestValues(newRawData);

                        bool isRawDataIncomplete = false;
                        do
                        {
                            isRawDataIncomplete = false;

                            if (newRawData != null)
                            {
                                newRawData = await cFasdCockpitCommunicationBase.Instance.GetHealthCardData(newRawData.Id);
                                UpdateLatestValues(newRawData);
                            }

                            if (newRawData?.Tables?.Count > 0)
                                if (newRawData.Tables.Values.Any(table => table.IsIncomplete))
                                    isRawDataIncomplete = true;

                        } while (isRawDataIncomplete);

                        LastDataRequest = DateTime.Now;
                        DataRefreshed?.Invoke(this, EventArgs.Empty);
                        DataFullyLoaded?.Invoke(this, EventArgs.Empty);
                    }
                    catch (Exception E)
                    {
                        LogException(E);
                    }

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

            public async Task SetHealthCardRawData(cF4SDHealthCardRawData newHealthCardRawData, cF4sdIdentityList identities)
            {
                var CM = MethodBase.GetCurrentMethod();
                LogMethodBegin(CM);
                try
                {
                    await LoadingRawDataCriticalSection.EnterAsync();

                    parent.dataProvider.Identities = identities;

                    if (newHealthCardRawData != null)
                        parent.HealthCardRawData = newHealthCardRawData;

                    parent.UpdateNamedParameterEntries();

                    bool isDataIncomplete = HealthCardRawData.Tables
                        .Where(table => table.Key.StartsWith("Computation_") == false)
                        .Any(table => table.Value.IsIncomplete);

                    lock (HealthCardRawData)
                    {
                        SelectedHealthCard.DoComputations(HealthCardRawData);
                    }

                    LogEntry("DataChanged - Finished getting Healthcard rawdata.");
                    DataChanged?.Invoke(this, new BooleanEventArgs(true));
                    parent.UpdateNamedParameterEntries();

                    if (!isDataIncomplete)
                        DataFullyLoaded?.Invoke(this, EventArgs.Empty);
                }
                catch (Exception ex)
                {
                    LogException(ex);
                }
                finally
                {
                    LoadingRawDataCriticalSection.Leave();
                    LogMethodEnd(CM);
                }
            }

            internal cHealthCardDataLoadingHelper(cHealthCardDataHelper parent) : base(parent) { }

            private bool WasTableUpdated(cF4SDHealthCardRawData.cHealthCardTable oldTable, cF4SDHealthCardRawData.cHealthCardTable newTable)
            {
                try
                {
                    if (oldTable.IsIncomplete && !newTable.IsIncomplete)
                        return true;

                    if (oldTable.StartingIndex != newTable.StartingIndex)
                        return true;

                    foreach (var oldTableColumn in oldTable.Columns)
                    {
                        if (!newTable.Columns.TryGetValue(oldTableColumn.Key, out var newTableColumn))
                            continue;

                        if (oldTableColumn.Value.Values.Count != newTableColumn.Values.Count)
                            return true;
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }

                return false;
            }

            private async Task<enumActualizeStatus> ActualizeDataAsync()
            {
                var output = enumActualizeStatus.unknown;

                try
                {
                    const int refreshDelayInMilliseconds = 500;
                    const int maxPollCount = 20;

                    if (dataProvider.Identities.Any(identity => identity.Class == enumFasdInformationClass.Computer) is false)
                    {
                        LogEntry("Coudldn't acutalize data. There was no information class of type computer found.", LogLevels.Error);
                        return output;
                    }

                    if (dataProvider.NamedParameterEntries.TryGetValue("AgentDeviceId", out var agentDeviceIdParameter) is false || int.TryParse(agentDeviceIdParameter.GetValue(), out int agentDeviceId) is false)
                    {
                        LogEntry("Coudldn't acutalize data. There was no valid AgentDeviceId found.", LogLevels.Error);
                        return output;
                    }

                    int? agentUserId = null;
                    if (dataProvider.Identities.Any(identity => identity.Class == enumFasdInformationClass.User))
                        if (dataProvider.NamedParameterEntries.TryGetValue("AgentUserId", out var agentUserIdParameter))
                            if (int.TryParse(agentUserIdParameter.GetValue(), out int tempAgentUserId))
                                agentUserId = tempAgentUserId;

                    var actualizeId = await cFasdCockpitCommunicationBase.Instance.ActualizeAgentData(agentDeviceId, agentUserId);

                    if (actualizeId == Guid.Empty)
                        return enumActualizeStatus.failed;

                    enumFasdInformationClass informationClass = agentUserId != null ? enumFasdInformationClass.User : enumFasdInformationClass.Computer;
                    int pollCount = 0;

                    while (output == enumActualizeStatus.unknown)
                    {
                        output = await cFasdCockpitCommunicationBase.Instance.GetActualizeAgentDataStatus(actualizeId, informationClass);

                        if (output == enumActualizeStatus.unknown)
                        {
                            pollCount++;
                            if (pollCount >= maxPollCount)
                                return output;

                            await Task.Delay(refreshDelayInMilliseconds);
                        }
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }

                return output;
            }

            private void UpdateLatestValues(cF4SDHealthCardRawData newRawData)
            {
                try
                {
                    if (newRawData?.Tables is null)
                        return;

                    foreach (var tableName in newRawData.Tables.Keys)
                    {
                        try
                        {
                            if (HealthCardRawData.Tables.TryGetValue(tableName, out var oldTable) == false)
                                continue;

                            if (newRawData.Tables.TryGetValue(tableName, out var newTable) == false)
                                continue;

                            foreach (var oldColumn in oldTable.Columns)
                            {
                                try
                                {
                                    if (newTable.Columns.TryGetValue(oldColumn.Key, out var newTableColumn) == false)
                                        continue;

                                    if (newTable.TableType != eDataHistoryTableType.HistoryEvents)
                                    {
                                        if (newTableColumn.Values is null || newTableColumn.Values?.Count <= 0)
                                            continue;
                                        if (oldColumn.Value?.Values is null || oldColumn.Value.Values.Count <= 0)
                                            continue;

                                        oldColumn.Value.Values[0] = newTableColumn.Values[0];
                                    }
                                    else
                                        oldColumn.Value.Values = newTableColumn.Values;

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

                    SelectedHealthCard.DoComputations(HealthCardRawData);
                    LogEntry("DataChanged - Update Latest Values finished.");
                    DataChanged?.Invoke(this, EventArgs.Empty);
                }
                catch (Exception E)
                {
                    LogException(E);
                }
            }

            public async Task UpdateHealthcardRawData(cF4SDHealthCardRawData updatedHealthCardRawData)
            {
                var CM = MethodBase.GetCurrentMethod();
                LogMethodBegin(CM);
                try
                {
                    if (updatedHealthCardRawData is null)
                        return;

                    bool isDataIncomplete = true;
                    await LoadingRawDataCriticalSection.EnterAsync();
                    try
                    {
                        lock (HealthCardRawData)
                        {
                            var incompleteRawTables = HealthCardRawData.Tables.Where(table => table.Value.IsIncomplete
                                                    && table.Key.StartsWith("Computation_") == false)
                                              .ToDictionary(table => table.Key, table => table.Value);

                            if (updatedHealthCardRawData is null)
                            {
                                var _msg = new List<string>
                                {
                                    $"Couldn't recieve complete healthcard raw data with id {HealthCardRawData?.Id}.",
                                    " Incomplete health cards:"
                                };

                                foreach (var incompleteTable in HealthCardRawData.Tables.Where(table => table.Value.IsIncomplete))
                                {
                                    _msg.Add($"  {incompleteTable.Value.Name}");
                                    foreach (var incompleteColumn in incompleteTable.Value.Columns.Values.Where(column => column.IsIncomplete))
                                    {
                                        incompleteColumn.IsIncomplete = false;
                                    }

                                    incompleteTable.Value.IsIncomplete = false;
                                }

                                cLogManager.DefaultLogger.LogList(LogLevels.Error, _msg);

                                SelectedHealthCard.DoComputations(HealthCardRawData);
                                LogEntry("DataChanged - Couldn't complete healthcard raw data.");
                                DataChanged?.Invoke(this, EventArgs.Empty);
                                return;
                            }

                            Dictionary<string, cHealthCardTable> rawTablesToUpdate = updatedHealthCardRawData.Tables
                                .Where(table => HealthCardRawData.Tables.TryGetValue(table.Key, out var oldTable) && WasTableUpdated(oldTable, table.Value))
                                .ToDictionary(table => table.Key, table => table.Value);

                            foreach (var oldTable in rawTablesToUpdate)
                            {
                                cHealthCardTable newTable = updatedHealthCardRawData.Tables[oldTable.Key];
                                cHealthCardTable oldTableValues = HealthCardRawData.Tables[oldTable.Key];

                                cHealthCardTable mergedTable = oldTableValues;

                                foreach (var newTableColumnKeys in newTable.Columns.Keys)
                                {
                                    if (mergedTable.Columns.ContainsKey(newTableColumnKeys) == false)
                                        mergedTable.Columns[newTableColumnKeys] = new cHealthCardTableColumn(mergedTable);

                                    int mergedTableColumnValueCount = mergedTable.Columns[newTableColumnKeys].Values.Count;
                                    int mergedTableColumnLength = Math.Max(mergedTable.StartingIndex + mergedTableColumnValueCount, newTable.StartingIndex + newTable.Columns[newTableColumnKeys].Values.Count); //mergedTable.Columns[newTableColumnKeys].Values.Count + newTable.Columns.Count;
                                    object[] mergedTableColumnValues = new object[mergedTableColumnLength];

                                    for (int i = mergedTable.StartingIndex; i < mergedTable.StartingIndex + mergedTableColumnValueCount; i++)
                                    {
                                        mergedTableColumnValues[i] = mergedTable.Columns[newTableColumnKeys].Values[i - mergedTable.StartingIndex];
                                    }

                                    for (int i = newTable.StartingIndex; i < newTable.StartingIndex + newTable.Columns[newTableColumnKeys].Values.Count; i++)
                                    {
                                        mergedTableColumnValues[i] = newTable.Columns[newTableColumnKeys].Values[i - newTable.StartingIndex];
                                    }

                                    int newStartingIndex = Math.Min(mergedTable.StartingIndex, newTable.StartingIndex);
                                    mergedTable.Columns[newTableColumnKeys].Values = mergedTableColumnValues.Skip(newStartingIndex).ToList();
                                    mergedTable.Columns[newTableColumnKeys].IsIncomplete = newTable.Columns[newTableColumnKeys].IsIncomplete;
                                    mergedTable.StartingIndex = newStartingIndex;
                                    mergedTable.IsIncomplete = newTable.IsIncomplete;
                                }

                                HealthCardRawData.Tables[oldTable.Key] = mergedTable;
                            }

                            isDataIncomplete = HealthCardRawData.Tables
                                .Where(table => table.Key.StartsWith("Computation_") == false)
                                .Any(table => table.Value.IsIncomplete);

                            if (rawTablesToUpdate?.Count > 0)
                            {
                                SelectedHealthCard.DoComputations(HealthCardRawData);
                                LogEntry($"DataChanged - {rawTablesToUpdate.Count} Tables where updated with last GetHealthcardData-Request.");
                                DataChanged?.Invoke(this, EventArgs.Empty);
                            }
                        }
                    }
                    catch (Exception E)
                    {
                        LogException(E);
                    }

                    if (!isDataIncomplete)
                        DataFullyLoaded?.Invoke(this, EventArgs.Empty);
                }
                catch (Exception ex)
                {
                    LogException(ex);
                }
                finally
                {
                    LoadingRawDataCriticalSection.Leave();
                    LogMethodEnd(CM);
                }
            }

            private static class LoadingRawDataCriticalSection
            {
                private readonly static SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);

                public static async Task EnterAsync()
                {
                    await _semaphore.WaitAsync();
                }

                public static void Leave()
                {
                    _semaphore.Release();
                }
            }

        }

        public class cHealthCardCustomizableSectionHelper : cHealthCardStateSubHelper
        {
            public List<cContainerData> GetContainerDataFromConfig(cHealthCardStateContainer containerConfig)
            {
                List<cContainerData> output = new List<cContainerData>();
                try
                {
                    if (containerConfig is null)
                        return null;

                    List<IContainerHelperClass> containerHelpers = new List<IContainerHelperClass>();

                    foreach (var stateContainerElementConfig in containerConfig.StateContainerElements)
                    {
                        var containerHelper = GetContainerHelperFromConfigElement(stateContainerElementConfig);
                        containerHelpers.Add(containerHelper);
                    }

                    if (containerHelpers?.Count <= 0)
                        return null;

                    int maxValueCountOfContainerHelpers = containerHelpers.Max(helper => helper.MaxValueCount);

                    for (int i = 0; i < maxValueCountOfContainerHelpers; i++)
                    {
                        var containerToAdd = new cContainerData() { IsMaximizable = containerConfig.IsMaximizable, IsAddable = containerConfig.IsAddable, IsDeletable = containerConfig.IsDeletable };

                        bool shouldSkipContainer = false;
                        foreach (var containerHelper in containerHelpers)
                        {
                            var containerValue = GetContainerDataAtIndexFromHelper(containerHelper, i);
                            containerToAdd.Add(containerValue);

                            if (containerHelper.IsValueRequired && containerValue.HasValue is false)
                                shouldSkipContainer = true;
                        }

                        if (shouldSkipContainer)
                            continue;

                        output.Add(containerToAdd);
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }
                return output;
            }

            internal cHealthCardCustomizableSectionHelper(cHealthCardDataHelper parent) : base(parent) { }

            internal List<cContainerCollectionData> GetContainerCollectionData()
            {
                var CM = MethodBase.GetCurrentMethod();
                LogMethodBegin(CM);

                var output = new List<cContainerCollectionData>();

                try
                {
                    var customizableSectionConfig = SelectedHealthCard.CustomizableSection;

                    if (customizableSectionConfig is null)
                        return output;

                    foreach (var containerConfigList in customizableSectionConfig.ContainerList)
                    {
                        try
                        {
                            if (containerConfigList is null)
                                continue;

                            var containerCollectionToAdd = new cContainerCollectionData() { ColumnSpan = containerConfigList.ColumnSpan };

                            foreach (var containerConfig in containerConfigList.StateContainers)
                            {
                                var containerValuesToAdd = GetContainerDataFromConfig(containerConfig);
                                containerCollectionToAdd.AddRange(containerValuesToAdd);
                            }

                            output.Add(containerCollectionToAdd);
                        }
                        catch (Exception E)
                        {
                            LogException(E);
                        }
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }
                finally
                {
                    LogMethodEnd(CM);
                }

                return output;
            }

            private IContainerData GetContainerDataAtIndexFromHelper(IContainerHelperClass containerHelper, int index = 0)
            {
                IContainerData output = null;

                try
                {
                    switch (containerHelper)
                    {
                        case cContainerValueHelper containerValue:
                            {
                                string displayValue = string.Empty;
                                cEditableValueInformationBase editableValueInformation = containerValue.EditableValueInformation;

                                if (containerValue.RawValues.Count > index)
                                {
                                    displayValue = cUtility.RawValueFormatter.GetDisplayValue(containerValue.RawValues[index], containerValue.DisplayType);

                                    if (editableValueInformation != null)
                                        editableValueInformation.CurrentValue = containerValue.RawValues[index];
                                }

                                string maximizeValue = string.Empty;
                                if (containerValue.RawMaximizeValues.Count > index)
                                    maximizeValue = cUtility.RawValueFormatter.GetDisplayValue(containerValue.RawMaximizeValues[index], containerValue.DisplayType);

                                output = new cContainerValue()
                                {
                                    DisplayValue = displayValue,
                                    MaximizeValue = maximizeValue,
                                    FontSize = containerValue.FontSize,
                                    FontWeight = containerValue.FontWeight,
                                    Description = containerValue.Description,
                                    IsEditOnly = containerValue.IsEditOnly,
                                    EditableValueInformation = editableValueInformation
                                };

                                break;
                            }
                        case cContainerIconHelper containerIcon:
                            {
                                output = new cContainerIcon(enumInternIcons.none);
                                if (containerIcon.Icons.Count > index)
                                    output = containerIcon.Icons[index];
                                break;
                            }
                        case cContainerStackPanelHelper containerStackPanel:
                            {
                                var outputStackPanelData = new List<IContainerData>();

                                foreach (var stackPanelData in containerStackPanel.StackPanelHelperData)
                                {
                                    try
                                    {
                                        var dataToAdd = GetContainerDataAtIndexFromHelper(stackPanelData, index);
                                        outputStackPanelData.Add(dataToAdd);
                                    }
                                    catch (Exception E)
                                    {
                                        LogException(E);
                                    }
                                }

                                output = new cContainerStackPanel()
                                {
                                    StackPanelData = outputStackPanelData,
                                    Orientation = containerStackPanel.Orientation
                                };

                                break;
                            }
                        case cContainerContentHelper containerContent:
                            {
                                var outputContentData = GetContainerDataAtIndexFromHelper(containerContent.Content, index);
                                output = new cContainerPrimaryContent() { Value = outputContentData };
                                break;
                            }
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }

                return output;
            }

            private FontWeight GetFontWeightFromConfigFontWeight(enumFontWeights configFontWeight)
            {
                var output = FontWeights.Normal;
                try
                {
                    switch (configFontWeight)
                    {
                        case enumFontWeights.Thin:
                            output = FontWeights.Thin;
                            break;
                        case enumFontWeights.ExtraLight:
                            output = FontWeights.ExtraLight;
                            break;
                        case enumFontWeights.UltraLight:
                            output = FontWeights.UltraLight;
                            break;
                        case enumFontWeights.Light:
                            output = FontWeights.Light;
                            break;
                        case enumFontWeights.Normal:
                            output = FontWeights.Normal;
                            break;
                        case enumFontWeights.Regular:
                            output = FontWeights.Regular;
                            break;
                        case enumFontWeights.Medium:
                            output = FontWeights.Medium;
                            break;
                        case enumFontWeights.DemiBold:
                            output = FontWeights.DemiBold;
                            break;
                        case enumFontWeights.SemiBold:
                            output = FontWeights.SemiBold;
                            break;
                        case enumFontWeights.Bold:
                            output = FontWeights.Bold;
                            break;
                        case enumFontWeights.ExtraBold:
                            output = FontWeights.ExtraBold;
                            break;
                        case enumFontWeights.UltraBold:
                            output = FontWeights.UltraBold;
                            break;
                        case enumFontWeights.Black:
                            output = FontWeights.Black;
                            break;
                        case enumFontWeights.Heavy:
                            output = FontWeights.Heavy;
                            break;
                        case enumFontWeights.ExtraBlack:
                            output = FontWeights.ExtraBlack;
                            break;
                        case enumFontWeights.UltraBlack:
                            output = FontWeights.UltraBlack;
                            break;
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }
                return output;
            }

            private IContainerData GetPlaceHolderContainerDataFromConfigElement(IStateContainerElement stateContainerElementConfig)
            {
                IContainerData output = null;

                try
                {
                    switch (stateContainerElementConfig)
                    {
                        case cHealthCardStateStylable stylableStateConfig:
                            {
                                var fontWeight = GetFontWeightFromConfigFontWeight(stylableStateConfig.FontWeight);

                                output = new cContainerValue()
                                {
                                    DisplayValue = stylableStateConfig.Names.GetValue(),
                                    FontSize = stylableStateConfig.FontSize,
                                    FontWeight = fontWeight,
                                    Description = parent.GetTitleColumnOfHealthCardState(stylableStateConfig).ContentDescription,
                                };

                                break;
                            }
                        case cHealthCardStateIconTranslation iconTranslationStateConfig:
                            {
                                output = new cContainerIcon() { IconType = enumIconType.intern, IconName = "f4sd" };
                                break;
                            }
                        case cHealthCardStateStackPanel stackPanelConfig:
                            {
                                var orientation = Orientation.Horizontal;
                                Enum.TryParse(stackPanelConfig.Orientation.ToString(), out orientation);

                                var stackPanelData = new List<IContainerData>();
                                foreach (var stackPanelState in stackPanelConfig.Children)
                                {
                                    var childData = GetPlaceHolderContainerDataFromConfigElement(stackPanelState);
                                    stackPanelData.Add(childData);
                                }

                                output = new cContainerStackPanel() { Orientation = orientation, StackPanelData = stackPanelData };
                                break;
                            }
                        case cHealthCardStateContainerContent containerContentConfig:
                            {
                                var content = GetPlaceHolderContainerDataFromConfigElement(containerContentConfig.Content);
                                output = new cContainerPrimaryContent() { Value = content };
                                break;
                            }
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }

                return output;
            }

            private IContainerHelperClass GetContainerHelperFromConfigElement(IStateContainerElement stateContainerElementConfig)
            {
                IContainerHelperClass output = null;

                try
                {
                    switch (stateContainerElementConfig)
                    {
                        case cHealthCardStateStylable stylableStateConfig:
                            {
                                var values = parent.GetStateValues(stylableStateConfig.DatabaseInfo, false);
                                var display = stylableStateConfig.DisplayType;
                                var maximingValues = parent.GetStateValues(stylableStateConfig.MaximizedDatabaseInfo, false);
                                var fontWeight = GetFontWeightFromConfigFontWeight(stylableStateConfig.FontWeight);

                                cEditableValueInformationBase editableInformation = null;
                                if (stylableStateConfig.EditInfo != null)
                                {
                                    switch (stylableStateConfig.EditInfo)
                                    {
                                        case cStateEditableSelection edtiableSelectionInfo:
                                            var editSelectionValues = parent.GetEditInformationSelectionValues(stylableStateConfig);
                                            editableInformation = new cEditValueInformationSelection() { DatabaseInfo = stylableStateConfig.DatabaseInfo, SelectionValues = editSelectionValues, Description = stylableStateConfig.Names.GetValue() };
                                            break;
                                        case cStateEditableText editableTextInfo:
                                            editableInformation = new cEditValueInformationText() { DatabaseInfo = stylableStateConfig.DatabaseInfo, Description = stylableStateConfig.Names.GetValue() };
                                            break;
                                        default:
                                            break;

                                    }
                                }

                                output = new cContainerValueHelper()
                                {
                                    RawValues = values,
                                    RawMaximizeValues = maximingValues,
                                    DisplayType = display,
                                    Description = parent.GetTitleColumnOfHealthCardState(stylableStateConfig).ContentDescription,
                                    FontSize = stylableStateConfig.FontSize,
                                    FontWeight = fontWeight,
                                    EditableValueInformation = editableInformation,
                                    IsValueRequired = stateContainerElementConfig.IsRequired
                                };
                                break;
                            }
                        case cHealthCardStateIconTranslation iconTranslationStateConfig:
                            {
                                var rawValues = parent.GetStateValues(iconTranslationStateConfig.DatabaseInfo, false);
                                var translation = cF4SDHealthCardConfig.GetTranslationsWithName(iconTranslationStateConfig, iconTranslationStateConfig.Translation);
                                var icons = new List<cContainerIcon>();

                                foreach (var rawValue in rawValues)
                                {
                                    var iconName = "none";
                                    enumIconType iconType = enumIconType.intern;
                                    enumHighlightColor highlightColor = enumHighlightColor.none;

                                    if (translation is cHealthCardIconTranslator iconTranslation)
                                    {
                                        var selectedTranslation = iconTranslation.IconTranslations.FirstOrDefault(tempTranslation => tempTranslation.Values.Contains(rawValue)) ?? iconTranslation.DefaultIconTranslation;
                                        if (selectedTranslation != null)
                                        {
                                            iconName = selectedTranslation.Icon.Name;
                                            iconType = selectedTranslation.Icon.IconType;

                                            switch (selectedTranslation.StateLevel)
                                            {
                                                case enumHealthCardStateLevel.Ok:
                                                    highlightColor = enumHighlightColor.green;
                                                    break;
                                                case enumHealthCardStateLevel.Warning:
                                                    highlightColor = enumHighlightColor.orange;
                                                    break;
                                                case enumHealthCardStateLevel.Error:
                                                    highlightColor = enumHighlightColor.red;
                                                    break;
                                                case enumHealthCardStateLevel.Info:
                                                    highlightColor = enumHighlightColor.blue;
                                                    break;
                                            }

                                            string toolTipText = selectedTranslation.Descriptions.GetValue(null, string.Empty);

                                            icons.Add(new cContainerIcon() { IconName = iconName, IconType = iconType, HighlightColor = highlightColor, ToolTipText = toolTipText });
                                        }
                                    }
                                }

                                output = new cContainerIconHelper() { Icons = icons, IsValueRequired = stateContainerElementConfig.IsRequired };
                                break;
                            }
                        case cHealthCardStateStackPanel stackPanelConfig:
                            {
                                var orientation = Orientation.Horizontal;
                                Enum.TryParse(stackPanelConfig.Orientation.ToString(), out orientation);

                                var stackPanelData = new List<IContainerHelperClass>();
                                foreach (var stackPanelState in stackPanelConfig.Children)
                                {
                                    var childData = GetContainerHelperFromConfigElement(stackPanelState);
                                    stackPanelData.Add(childData);
                                }

                                output = new cContainerStackPanelHelper() { Orientation = orientation, StackPanelHelperData = stackPanelData, IsValueRequired = stateContainerElementConfig.IsRequired };
                                break;
                            }
                        case cHealthCardStateContainerContent containerContentConfig:
                            {
                                var content = GetContainerHelperFromConfigElement(containerContentConfig.Content);
                                output = new cContainerContentHelper() { Content = content, IsValueRequired = stateContainerElementConfig.IsRequired || content.IsValueRequired };
                                break;
                            }
                        case cHealthCardStateEditable editableStateConfig:
                            {
                                cEditableValueInformationBase editableInformation = null;
                                if (editableStateConfig.EditInfo is null)
                                    break;

                                switch (editableStateConfig.EditInfo)
                                {
                                    case cStateEditableSelection edtiableSelectionInfo:
                                        var editSelectionValues = parent.GetEditInformationSelectionValues(editableStateConfig);
                                        editableInformation = new cEditValueInformationSelection() { DatabaseInfo = editableStateConfig.DatabaseInfo, SelectionValues = editSelectionValues, Description = editableStateConfig.Names.GetValue() };
                                        break;
                                    case cStateEditableText editableTextInfo:
                                        editableInformation = new cEditValueInformationText() { DatabaseInfo = editableStateConfig.DatabaseInfo, Description = editableStateConfig.Names.GetValue() };
                                        break;
                                    default:
                                        break;

                                }

                                output = new cContainerValueHelper()
                                {
                                    RawValues = new List<object>() { editableStateConfig.Names.GetValue() },
                                    IsEditOnly = true,
                                    EditableValueInformation = editableInformation,
                                    IsValueRequired = stateContainerElementConfig.IsRequired
                                };
                                break;
                            }
                    }


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

                return output;
            }

        }

        private class cStateValueInfo
        {
            public string Content { get; set; }
            public enumHighlightColor HighlightColor { get; set; }
        }
    }
}
