using C4IT.F4SD.DisplayFormatting;
using C4IT.F4SD.SupportCaseProtocoll.Models;
using C4IT.FASD.Base;
using C4IT.MultiLanguage;
using F4SD_AdaptableIcon.Enums;
using FasdDesktopUi.Basics.Converter;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.Services.ProtocollService;
using FasdDesktopUi.Basics.UiActions;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using static C4IT.Logging.cLogManager;

namespace FasdDesktopUi.Basics.UserControls
{
    public partial class QuickActionStatusMonitor : UserControl, IBlurInvoker
    {
        private const string veiledText = "********";
        private bool secretsAreShown = false;
        private readonly IRawValueFormatter _rawValueFormatter = new RawValueFormatter();

        #region Helperclasses QuickAction Output

        public abstract class cQuickActionOutput
        {
            protected readonly IRawValueFormatter _rawValueFormatter = new RawValueFormatter();

            public cQuickActionOutput(cF4sdQuickActionRevision.cOutput scriptOutput)
            {
                _rawValueFormatter.SetDefaultCulture(new System.Globalization.CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage));
                _rawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local);
                ErrorCode = scriptOutput.ErrorCode;
                ErrorDescription = scriptOutput.ErrorDescription;
                ResultCode = scriptOutput.ResultCode.GetValueOrDefault();
                IsError = HasError(scriptOutput);
            }

            public cSupportCaseDataProvider DataProvider { get; private set; }
            public enumQuickActionSuccess? ResultCode { get; set; }
            public int? ErrorCode { get; set; }
            public string ErrorDescription { get; set; }

            public bool IsError { get; private set; }

            internal static KeyValuePair<string, RawValueType> GetDisplayType(dynamic columnTypeObject)
            {
                var output = new KeyValuePair<string, RawValueType>();

                try
                {
                    var columnType = columnTypeObject.ToObject<dynamic>();
                    string name = string.Empty;
                    RawValueType type = RawValueType.STRING;


                    if (columnType.Name != null)
                        if (columnType.Name is Newtonsoft.Json.Linq.JValue nameJValue)
                            name = nameJValue.Value.ToString();

                    if (columnType.Type != null)
                        if (columnType.Type is Newtonsoft.Json.Linq.JValue typeJValue)
                            if (Enum.TryParse(typeJValue.Value.ToString(), out RawValueType typeJValueType))
                                type = typeJValueType;

                    output = new KeyValuePair<string, RawValueType>(name, type);

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

                return output;
            }

            public static cQuickActionOutput GetQuickActionOutput(cF4sdQuickActionRevision.cOutput scriptOutput, cSupportCaseDataProvider dataProvider)
            {
                if (scriptOutput == null)
                    return null;

                try
                {
                    if (scriptOutput?.Values == null)
                    {
                        var output = new cQuickActionOutputSingle(scriptOutput) { DataProvider = dataProvider };
                        return output;
                    }
                    else if (scriptOutput.Values is JArray scriptValueJArray)
                    {
                        var scriptValues = scriptValueJArray.ToObject<List<dynamic>>();
                        if (scriptValues != null && scriptValues.Count > 0)
                        {
                            var output = new cQuickActionOutputList(scriptOutput) { DataProvider = dataProvider };

                            foreach (var scriptValue in scriptValues)
                            {
                                if (scriptValue is JObject scriptValueJObject)
                                {
                                    try
                                    {
                                        var scriptValueHelperDictionary = scriptValueJObject.ToObject<Dictionary<string, object>>();
                                        output.Values.Add(scriptValueHelperDictionary.ToList());
                                    }
                                    catch (Exception E)
                                    {
                                        LogException(E);
                                    }
                                }
                            }

                            return output;
                        }
                    }
                    else if (scriptOutput.Values is JObject scriptValueJObject)
                    {
                        try
                        {
                            var output = new cQuickActionOutputObject(scriptOutput) { DataProvider = dataProvider };
                            return output;
                        }
                        catch (Exception E)
                        {
                            LogException(E);
                        }
                    }
                    else
                    {
                        return new cQuickActionOutputSingle(scriptOutput) { DataProvider = dataProvider };
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }

                return null;
            }

            public static bool HasError(cF4sdQuickActionRevision.cOutput quickActionOutput)
            {
                if ((quickActionOutput?.ResultCode == null || quickActionOutput?.ResultCode == enumQuickActionSuccess.finished || quickActionOutput?.ResultCode == enumQuickActionSuccess.successfull)
                    && (quickActionOutput?.ErrorCode == null || quickActionOutput?.ErrorCode == 0)
                    && string.IsNullOrEmpty(quickActionOutput?.ErrorDescription))
                    return false;
                return true;
            }
        }

        public class cQuickActionOutputSingle : cQuickActionOutput
        {
            public cQuickActionOutputSingle(cF4sdQuickActionRevision.cOutput scriptOutput) : base(scriptOutput)
            {
                Instantiate(scriptOutput);
            }


            public RawValueType DisplayType { get; set; }
            public string Key { get; set; }
            public object Value { get; set; }

            private void Instantiate(cF4sdQuickActionRevision.cOutput scriptOutput)
            {
                try
                {
                    Value = scriptOutput.Values;

                    if (scriptOutput.Values is JObject scriptValueJObject)
                    {
                        string scriptValueKey = null;

                        try
                        {
                            var scriptValueHelperDictionary = scriptValueJObject.ToObject<Dictionary<string, object>>();
                            scriptValueKey = scriptValueHelperDictionary.Keys.ToList()[0];

                            Key = scriptValueKey;
                            Value = scriptValueHelperDictionary[scriptValueKey];
                        }
                        catch (Exception E)
                        {
                            LogException(E);
                        }

                        if (scriptOutput.ColumnTypes is JArray columnTypeJArray)
                        {
                            var columnTypes = columnTypeJArray.ToObject<List<dynamic>>();
                            if (columnTypes != null && columnTypes.Count > 0)
                            {
                                foreach (var columnTypeObject in columnTypes)
                                {
                                    var displayType = cQuickActionOutput.GetDisplayType(columnTypeObject);

                                    if (displayType.Key == scriptValueKey)
                                        DisplayType = displayType.Value;
                                }
                            }

                        }
                        else if (scriptOutput.ColumnTypes is JObject columnTypeJObject)
                        {
                            try
                            {
                                var dispayType = cQuickActionOutput.GetDisplayType(columnTypeJObject);
                                DisplayType = dispayType.Value;
                            }
                            catch (Exception E)
                            {
                                LogException(E);
                            }
                        }
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }
            }

            public string GetDisplayValue(Dictionary<string, cColumnOutputFormatting> columnOutputFormattings, bool getSecretValue = false)
            {
                string output = null;

                try
                {
                    output = _rawValueFormatter.GetDisplayValue(Value, DisplayType);

                    cColumnOutputFormatting outputFormatting = null;

                    if (string.IsNullOrEmpty(Key))
                        outputFormatting = columnOutputFormattings?.Values.FirstOrDefault();
                    else
                        columnOutputFormattings?.TryGetValue(Key, out outputFormatting);

                    if (outputFormatting != null)
                    {
                        if (outputFormatting.IsSecret && !getSecretValue)
                            return veiledText;

                        if (outputFormatting.DisplayType != null)
                            output = _rawValueFormatter.GetDisplayValue(Value, outputFormatting.DisplayType.Value);

                        if (outputFormatting.Translation != null)
                        {
                            var abstractTranslation = cF4SDHealthCardConfig.GetTranslationsWithName(DataProvider?.HealthCardDataHelper?.SelectedHealthCard, outputFormatting.Translation);
                            if (abstractTranslation != null && abstractTranslation is cHealthCardTranslator translator)
                            {
                                output = translator.DefaultTranslation?.Translation.GetValue() ?? Value.ToString();

                                foreach (var translation in translator.Translations)
                                {
                                    if (translation.Values.Any(value => value.Equals(Value.ToString(), StringComparison.InvariantCultureIgnoreCase)))
                                        output = translation.Translation.GetValue();
                                }
                            }
                        }
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }

                return output;
            }
        }

        public class cQuickActionOutputObject : cQuickActionOutput
        {
            public Dictionary<string, RawValueType> DisplayTypes { get; set; } = new Dictionary<string, RawValueType>();
            public List<KeyValuePair<string, object>> Values { get; set; } = new List<KeyValuePair<string, object>>();

            public cQuickActionOutputObject(cF4sdQuickActionRevision.cOutput scriptOutput) : base(scriptOutput)
            {
                try
                {
                    InstantiateDisplayTypes(scriptOutput);
                    InstantiateValues(scriptOutput);
                }
                catch (Exception E)
                {
                    LogException(E);
                }
            }

            private void InstantiateDisplayTypes(cF4sdQuickActionRevision.cOutput scriptOutput)
            {
                try
                {
                    if (scriptOutput.ColumnTypes is Newtonsoft.Json.Linq.JArray columnTypeJArray)
                    {
                        var columnTypes = columnTypeJArray.ToObject<List<dynamic>>();
                        if (columnTypes != null && columnTypes.Count > 0)
                        {
                            foreach (var columnTypeObject in columnTypes)
                            {
                                var displayType = GetDisplayType(columnTypeObject);
                                DisplayTypes[displayType.Key] = displayType.Value;
                            }
                        }
                    }
                    else if (scriptOutput.ColumnTypes is Newtonsoft.Json.Linq.JObject columnTypeJObject)
                    {
                        try
                        {
                            var displayType = GetDisplayType(columnTypeJObject);

                            DisplayTypes[displayType.Key] = displayType.Value;
                        }
                        catch (Exception E)
                        {
                            LogException(E);
                        }
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }
            }

            private void InstantiateValues(cF4sdQuickActionRevision.cOutput scriptOutput)
            {
                try
                {
                    if (!(scriptOutput.Values is JObject valuesJObject))
                        return;

                    if (valuesJObject.Properties() == null)
                        return;

                    foreach (var property in valuesJObject.Properties())
                    {
                        Values.Add(new KeyValuePair<string, object>(property.Name, property.Value));
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }
            }

            public string GetDisplayValue(int index, Dictionary<string, cColumnOutputFormatting> columnOutputFormattings, bool getSecretValue = false)
            {
                string output = null;

                try
                {
                    if (Values.Count <= index)
                        return null;

                    var selectedItem = Values[index];

                    RawValueType displayType = RawValueType.STRING;
                    DisplayTypes.TryGetValue(selectedItem.Key, out displayType);
                    output = _rawValueFormatter.GetDisplayValue(selectedItem.Value, displayType);

                    if (columnOutputFormattings != null && columnOutputFormattings.TryGetValue(selectedItem.Key, out var outputFormatting))
                    {
                        if (outputFormatting.Hidden)
                            return string.Empty;

                        if (outputFormatting.IsSecret && !getSecretValue)
                            return veiledText;

                        if (outputFormatting.DisplayType != null)
                            output = _rawValueFormatter.GetDisplayValue(selectedItem.Value, outputFormatting.DisplayType.Value);

                        if (outputFormatting.Translation != null)
                        {
                            var abstractTranslation = cF4SDHealthCardConfig.GetTranslationsWithName(DataProvider?.HealthCardDataHelper?.SelectedHealthCard, outputFormatting.Translation);
                            if (abstractTranslation != null && abstractTranslation is cHealthCardTranslator translator)
                            {
                                output = translator.DefaultTranslation?.Translation.GetValue() ?? selectedItem.Value.ToString();

                                foreach (var translation in translator.Translations)
                                {
                                    if (translation.Values.Any(value => value.Equals(selectedItem.Value.ToString(), StringComparison.InvariantCultureIgnoreCase)))
                                        output = translation.Translation.GetValue();
                                }
                            }
                        }
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }

                return output;
            }
        }

        public class cQuickActionOutputList : cQuickActionOutput
        {
            public cQuickActionOutputList(cF4sdQuickActionRevision.cOutput scriptOutput) : base(scriptOutput)
            {
                InstantiateDisplayTypes(scriptOutput);
            }

            public Dictionary<string, RawValueType> DisplayTypes { get; set; } = new Dictionary<string, RawValueType>();
            public List<List<KeyValuePair<string, object>>> Values { get; set; } = new List<List<KeyValuePair<string, object>>>();

            private void InstantiateDisplayTypes(cF4sdQuickActionRevision.cOutput scriptOutput)
            {
                try
                {
                    if (scriptOutput.ColumnTypes is Newtonsoft.Json.Linq.JArray columnTypeJArray)
                    {
                        var columnTypes = columnTypeJArray.ToObject<List<dynamic>>();
                        if (columnTypes != null && columnTypes.Count > 0)
                        {
                            foreach (var columnTypeObject in columnTypes)
                            {
                                var displayType = GetDisplayType(columnTypeObject);
                                DisplayTypes[displayType.Key] = displayType.Value;
                            }
                        }
                    }
                    else if (scriptOutput.ColumnTypes is Newtonsoft.Json.Linq.JObject columnTypeJObject)
                    {
                        try
                        {
                            var displayType = GetDisplayType(columnTypeJObject);

                            DisplayTypes[displayType.Key] = displayType.Value;
                        }
                        catch (Exception E)
                        {
                            LogException(E);
                        }
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }
            }

            public string GetDisplayValue(int row, int column, Dictionary<string, cColumnOutputFormatting> columnOutputFormattings, bool getSecretValue = false)
            {
                string output = null;

                try
                {
                    RawValueType displayType = RawValueType.STRING;
                    DisplayTypes.TryGetValue(Values[row][column].Key, out displayType);
                    output = _rawValueFormatter.GetDisplayValue(Values[row][column].Value, displayType);

                    if (columnOutputFormattings != null && columnOutputFormattings.TryGetValue(Values[row][column].Key, out var outputFormatting))
                    {
                        if (outputFormatting.Hidden)
                            return string.Empty;

                        if (outputFormatting.IsSecret && !getSecretValue)
                            return veiledText;

                        if (outputFormatting.DisplayType != null)
                            output = _rawValueFormatter.GetDisplayValue(Values[row][column].Value, outputFormatting.DisplayType.Value);

                        if (outputFormatting.Translation != null)
                        {
                            var abstractTranslation = cF4SDHealthCardConfig.GetTranslationsWithName(DataProvider?.HealthCardDataHelper?.SelectedHealthCard, outputFormatting.Translation);
                            if (abstractTranslation != null && abstractTranslation is cHealthCardTranslator translator)
                            {
                                output = translator.DefaultTranslation?.Translation.GetValue() ?? Values[row].ToList()[column].Value.ToString();

                                foreach (var translation in translator.Translations)
                                {
                                    if (translation.Values.Any(value => value.Equals(Values[row].ToList()[column].Value.ToString(), StringComparison.InvariantCultureIgnoreCase)))
                                        output = translation.Translation.GetValue();
                                }
                            }
                        }
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }

                return output;
            }
        }

        public class cQuickActionMeasureValue
        {
            public int Id { get; set; }
            public cMultiLanguageDictionary Names { get; set; }
            public object Value { get; set; }
            public object PostValue { get; set; }

            public object Difference
            {
                get
                {
                    switch (Display)
                    {
                        case RawValueType.INTEGER:
                        case RawValueType.PERCENT:
                        case RawValueType.PERCENT100:
                        case RawValueType.PERCENT1000:
                        case RawValueType.BYTES:
                            var valueDouble = cF4SDHealthCardRawData.GetDouble(Value);
                            var postValueDouble = cF4SDHealthCardRawData.GetDouble(PostValue);

                            if (valueDouble != null && postValueDouble != null)
                                return postValueDouble - valueDouble;
                            break;
                    }
                    return null;
                }
            }

            public RawValueType Display { get; set; }
        }

        #endregion

        #region Properties

        private CancellationTokenSource tokenSource;
        private bool quickActionIsRunning = false;
        private cQuickActionStatusMonitorModel tempQuickActionData;
        private readonly RevisionStatusToAdaptableIconConverter revisionStatusToIconConverter = new RevisionStatusToAdaptableIconConverter();
        public cSupportCaseDataProvider DataProvider { get; set; }

        public bool HasQuickActionDataChangedSinceRun { get => QuickActionData == null || !QuickActionData.Equals(tempQuickActionData); }

        #region QuickActionData

        private static void QuickActionDataChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is QuickActionStatusMonitor _me && e.NewValue is cQuickActionStatusMonitorModel quickActionData)
            {
                _me.SetQuickActionCompletionSteps(quickActionData.ActionSteps);
                _me.CopyButton.Visibility = Visibility.Collapsed;
                _me.secretsAreShown = false;
                _me.SecretButton.SelectedMaterialIcon = MaterialIcons.MaterialIconType.ic_visibility;
                _me.SecretButton.Visibility = Visibility.Collapsed;
                _me.AdjustableParameterSectionUc.ToggleIsActive(true);
            }
        }

        public static readonly DependencyProperty QuickActionDataProperty =
            DependencyProperty.Register("QuickActionData", typeof(cQuickActionStatusMonitorModel), typeof(QuickActionStatusMonitor), new PropertyMetadata(new cQuickActionStatusMonitorModel(), new PropertyChangedCallback(QuickActionDataChangedCallback)));


        public cQuickActionStatusMonitorModel QuickActionData
        {
            get { return (cQuickActionStatusMonitorModel)GetValue(QuickActionDataProperty); }
            set { SetValue(QuickActionDataProperty, value); }
        }

        #endregion

        #region IsCloseButtonVisible

        public static readonly DependencyProperty IsCloseButtonVisibleProperty =
            DependencyProperty.Register("IsCloseButtonVisible", typeof(bool), typeof(QuickActionStatusMonitor), new PropertyMetadata(false));

        public bool IsCloseButtonVisible
        {
            get { return (bool)GetValue(IsCloseButtonVisibleProperty); }
            set { SetValue(IsCloseButtonVisibleProperty, value); }
        }

        #endregion

        #region QuickActionOutputs

        private ObservableCollection<cF4sdQuickActionRevision.cOutput> quickActionOutputs = new ObservableCollection<cF4sdQuickActionRevision.cOutput>();

        public ObservableCollection<cF4sdQuickActionRevision.cOutput> QuickActionOutputs
        {
            get { return quickActionOutputs; }
            set
            {
                QuickActionResultStack.Children.Clear();
                quickActionOutputs.CollectionChanged -= QuickActionOutputsChanged;
                quickActionOutputs = value;
                quickActionOutputs.CollectionChanged += QuickActionOutputsChanged;
            }
        }

        private void QuickActionOutputsChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            try
            {
                if (e.Action is NotifyCollectionChangedAction.Reset)
                    QuickActionResultStack.Children.Clear();

                if (e.Action is NotifyCollectionChangedAction.Add)
                {
                    foreach (cF4sdQuickActionRevision.cOutput quickActionOutput in e.NewItems)
                    {
                        try
                        {
                            if (!cQuickActionOutput.HasError(quickActionOutput))
                            {
                                if (quickActionOutput?.Values is null)
                                    continue;

                                var helperQuickActionOutput = cQuickActionOutput.GetQuickActionOutput(quickActionOutput, DataProvider);

                                if (helperQuickActionOutput is null)
                                    continue;

                                if (helperQuickActionOutput is cQuickActionOutputObject outObj && outObj.Values.Count <= 0)
                                    continue;

                                if (helperQuickActionOutput is cQuickActionOutputList outList && outList.Values.Count <= 0)
                                    continue;
                            }

                            var outputElement = new QuickActionStatusMonitorResultElement();
                            outputElement.SetQuickActionOutputData(quickActionOutput, DataProvider, QuickActionData.QuickActionDefinition);
                            QuickActionResultStack.Children.Add(outputElement);
                        }
                        catch (Exception E)
                        {
                            LogException(E);
                        }
                    }
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        #endregion

        #region QuickActionMeasureValues

        private static void QuickActionMeasureValuesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (!(d is QuickActionStatusMonitor _me))
                return;

            if (!(e.NewValue is List<cQuickActionMeasureValue> newValue))
                return;

            _me.UpdateQuickActionMeasureValues(newValue);
        }

        public static readonly DependencyProperty MeasureValuesProperty =
            DependencyProperty.Register("MeasureValues", typeof(List<cQuickActionMeasureValue>), typeof(QuickActionStatusMonitor), new PropertyMetadata(null, new PropertyChangedCallback(QuickActionMeasureValuesChanged)));


        public List<cQuickActionMeasureValue> MeasureValues
        {
            get { return (List<cQuickActionMeasureValue>)GetValue(MeasureValuesProperty); }
            set { SetValue(MeasureValuesProperty, value); }
        }

        #endregion

        public Action CloseButtonClickedAction { get; set; }

        #endregion

        public QuickActionStatusMonitor()
        {
            InitializeComponent();
            tokenSource = new CancellationTokenSource();
            quickActionOutputs.CollectionChanged += QuickActionOutputsChanged;
        }

        public void BlurInvoker_IsActiveChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            BlurInvoker.InvokeVisibilityChanged(this, new EventArgs());
        }

        public bool BlurInvoker_IsActive => IsVisible;

        public void SetQuickActionCompletionSteps(List<cQuickActionStatusMonitorModel.cQuickActionStep> ActionSteps)
        {
            try
            {
                ResetExecuteButton();

                //required to prevent binding errors
                //todo: add clean way to remove bindings of Quick Action Steps
                foreach (var child in CompletionStatusPanel.Children)
                {
                    if (!(child is Panel panelElement))
                        continue;

                    foreach (var childElement in panelElement.Children)
                    {
                        if (childElement is AdaptableIcon.AdaptableIcon childIcon)
                        {
                            BindingOperations.ClearBinding(childIcon, AdaptableIcon.AdaptableIcon.SelectedInternIconProperty);
                            BindingOperations.ClearBinding(childIcon, AdaptableIcon.AdaptableIcon.SelectedInternGifProperty);
                            BindingOperations.ClearBinding(childIcon, AdaptableIcon.AdaptableIcon.SelectedMaterialIconProperty);
                        }

                        if (childElement is Panel childPanel)
                        {
                            foreach (var panelChildElement in childPanel.Children)
                            {
                                if (panelChildElement is AdaptableIcon.AdaptableIcon panelChildIcon)
                                {
                                    BindingOperations.ClearBinding(panelChildIcon, AdaptableIcon.AdaptableIcon.SelectedInternIconProperty);
                                    BindingOperations.ClearBinding(panelChildIcon, AdaptableIcon.AdaptableIcon.SelectedInternGifProperty);
                                    BindingOperations.ClearBinding(panelChildIcon, AdaptableIcon.AdaptableIcon.SelectedMaterialIconProperty);
                                }
                            }
                        }
                    }
                }

                CompletionStatusPanel.Children.Clear();

                if (ActionSteps == null || ActionSteps.Count < 1)
                    return;

                foreach (var step in ActionSteps)
                {
                    DockPanel actionStepStatusPanel = new DockPanel() { Margin = new Thickness(0, 2.5, 0, 2.5), LastChildFill = false };
                    DockPanel.SetDock(actionStepStatusPanel, Dock.Top);

                    AdaptableIcon.AdaptableIcon completionIcon = new AdaptableIcon.AdaptableIcon() { IconHeight = 12, IconWidth = 12, BorderPadding = new Thickness(0) };
                    Binding adaptableIconBinding = new Binding($"QuickActionData.ActionSteps[{ActionSteps.IndexOf(step)}].Status")
                    {
                        ElementName = nameof(QuickActionStatusMonitorUc),
                        Converter = revisionStatusToIconConverter
                    };
                    completionIcon.SetBinding(AdaptableIcon.AdaptableIcon.SelectedInternIconProperty, adaptableIconBinding);
                    completionIcon.SetBinding(AdaptableIcon.AdaptableIcon.SelectedInternGifProperty, adaptableIconBinding);
                    completionIcon.SetBinding(AdaptableIcon.AdaptableIcon.SelectedMaterialIconProperty, adaptableIconBinding);

                    TextBlock actionStepTextBlock = new TextBlock() { Text = step.DisplayName, Margin = new Thickness(5, 0, 5, 0) };

                    DockPanel.SetDock(completionIcon, Dock.Left);
                    DockPanel.SetDock(actionStepTextBlock, Dock.Left);

                    actionStepStatusPanel.Children.Add(completionIcon);
                    actionStepStatusPanel.Children.Add(actionStepTextBlock);

                    CompletionStatusPanel.Children.Add(actionStepStatusPanel);

                    if (step.SubSteps?.Count > 0)
                    {
                        StackPanel subStackPanel = new StackPanel() { Margin = new Thickness(25, 0, 0, 0), Visibility = Visibility.Collapsed, Tag = step.QuickActionName };
                        DockPanel.SetDock(subStackPanel, Dock.Top);

                        foreach (var subStep in step.SubSteps)
                        {
                            DockPanel subActionStepStatusPanel = new DockPanel() { Margin = new Thickness(0, 2.5, 0, 2.5), LastChildFill = false };
                            DockPanel.SetDock(subActionStepStatusPanel, Dock.Top);

                            AdaptableIcon.AdaptableIcon subCompletionIcon = new AdaptableIcon.AdaptableIcon() { IconHeight = 12, IconWidth = 12, BorderPadding = new Thickness(0) };
                            Binding subAdaptableIconBinding = new Binding($"QuickActionData.ActionSteps[{ActionSteps.IndexOf(step)}].SubSteps[{step.SubSteps.IndexOf(subStep)}].Status")
                            {
                                ElementName = nameof(QuickActionStatusMonitorUc),
                                Converter = revisionStatusToIconConverter
                            };
                            subCompletionIcon.SetBinding(AdaptableIcon.AdaptableIcon.SelectedInternIconProperty, subAdaptableIconBinding);
                            subCompletionIcon.SetBinding(AdaptableIcon.AdaptableIcon.SelectedInternGifProperty, subAdaptableIconBinding);
                            subCompletionIcon.SetBinding(AdaptableIcon.AdaptableIcon.SelectedMaterialIconProperty, subAdaptableIconBinding);

                            TextBlock subActionStepTextBlock = new TextBlock() { Text = subStep.DisplayName, Margin = new Thickness(5, 0, 5, 0) };

                            DockPanel.SetDock(subCompletionIcon, Dock.Left);
                            DockPanel.SetDock(subActionStepTextBlock, Dock.Left);

                            subActionStepStatusPanel.Children.Add(subCompletionIcon);
                            subActionStepStatusPanel.Children.Add(subActionStepTextBlock);

                            subStackPanel.Children.Add(subActionStepStatusPanel);
                        }

                        CompletionStatusPanel.Children.Add(subStackPanel);
                    }

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

        private void UpdateQuickActionMeasureValues(List<cQuickActionMeasureValue> measureValues)
        {
            try
            {
                MeasureValueGrid.Children.Clear();
                MeasureValueGrid.RowDefinitions.Clear();

                if (measureValues?.Count <= 0)
                    return;

                _rawValueFormatter.SetDefaultCulture(new System.Globalization.CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage));
                _rawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local);

                for (int i = 0; i < measureValues.Count; i++)
                {
                    var measureValue = measureValues[i];

                    MeasureValueGrid.RowDefinitions.Add(new RowDefinition());

                    WrapPanel wrapPanel = new WrapPanel() { Orientation = Orientation.Horizontal };

                    Border titleBorder = new Border() { Padding = new Thickness(5, 2.5, 5, 2.5) };
                    TextBlock titleTextBlock = new TextBlock()
                    {
                        Text = measureValue.Names.GetValue(),
                        TextWrapping = TextWrapping.Wrap,
                        VerticalAlignment = VerticalAlignment.Center,
                        Style = (Style)FindResource("DetailsPage.DataHistory.TitleColumn.OverviewTitle")
                    };

                    titleBorder.Child = titleTextBlock;
                    wrapPanel.Children.Add(titleBorder);

                    TextBlock valueTextBlock = new TextBlock()
                    {
                        Text = _rawValueFormatter.GetDisplayValue(measureValue.Value, measureValue.Display),
                        Margin = new Thickness(5, 2.5, 5, 2.5),
                        VerticalAlignment = VerticalAlignment.Center,
                        FontWeight = FontWeights.Normal,
                        Style = (Style)FindResource("DetailsPage.DataHistory.TitleColumn.OverviewTitle")
                    };
                    wrapPanel.Children.Add(valueTextBlock);

                    TextBlock arrowTextBlock = new TextBlock()
                    {
                        Text = "➜",
                        VerticalAlignment = VerticalAlignment.Center,
                        Style = (Style)FindResource("DetailsPage.DataHistory.TitleColumn.OverviewTitle")
                    };
                    wrapPanel.Children.Add(arrowTextBlock);

                    TextBlock postValueTextBlock = new TextBlock()
                    {
                        Text = _rawValueFormatter.GetDisplayValue(measureValue.PostValue, measureValue.Display),
                        Margin = new Thickness(5, 2.5, 5, 2.5),
                        VerticalAlignment = VerticalAlignment.Center,
                        FontWeight = FontWeights.Bold,
                        Style = (Style)FindResource("DetailsPage.DataHistory.TitleColumn.OverviewTitle")

                    };
                    wrapPanel.Children.Add(postValueTextBlock);

                    if (measureValue.Difference != null)
                    {
                        TextBlock differenceTextBlock = new TextBlock()
                        {
                            Text = $"(∆ {_rawValueFormatter.GetDisplayValue(measureValue.Difference, measureValue.Display)})",
                            VerticalAlignment = VerticalAlignment.Center,
                            FontWeight = FontWeights.Normal,
                            Style = (Style)FindResource("DetailsPage.DataHistory.TitleColumn.OverviewTitle")
                        };

                        wrapPanel.Children.Add(differenceTextBlock);
                    }

                    Grid.SetRow(wrapPanel, i);
                    MeasureValueGrid.Children.Add(wrapPanel);
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        #region Events

        #region CloseButton_Click

        private void CloseButton_Click()
        {
            CloseButtonClickedAction?.Invoke();
        }

        private void CloseButton_MouseUp(object sender, MouseButtonEventArgs e)
        {
            CloseButton_Click();
        }

        private void CloseButton_TouchDown(object sender, TouchEventArgs e)
        {
            CloseButton_Click();
        }

        #endregion

        #region ExecuteButton_Click

        private void ResetExecuteButton()
        {
            try
            {
                ExecuteButton.SelectedInternIcon = enumInternIcons.misc_play;
                ExecuteButton.SelectedMaterialIcon = null;
                ExecuteButton.BorderPadding = new Thickness(2.5);
                ExecuteButton.ClearValue(AdaptableIcon.AdaptableIcon.PrimaryIconColorProperty);
                ExecuteButton.ClearValue(CursorProperty);
                ExecuteButton.ClearValue(IsHitTestVisibleProperty);
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        public void CancelQuickAction()
        {
            try
            {
                tokenSource.Cancel(true);
                quickActionIsRunning = false;
                ResetExecuteButton();
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private void VisualizeQuickActionStart()
        {
            try
            {
                ExecuteButton.ClearValue(AdaptableIcon.AdaptableIcon.PrimaryIconColorProperty);
                ExecuteButton.SelectedInternIcon = null;
                ExecuteButton.SelectedMaterialIcon = MaterialIcons.MaterialIconType.ic_stop;
                ExecuteButton.BorderPadding = new Thickness(0);
                cQuickActionStatusMonitorModel.cQuickActionStep.SetAllQuickActionStepStatuses(QuickActionData.ActionSteps, enumQuickActionRevisionStatus.inProgress);
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        public void VisualizeQuickActionFinish(enumQuickActionRevisionStatus status)
        {
            if (HasQuickActionDataChangedSinceRun) //todo: think about better solution
                return;

            switch (status)
            {
                case enumQuickActionRevisionStatus.finishedSuccessfull:
                    ExecuteButton.SelectedMaterialIcon = null;
                    ExecuteButton.SelectedInternIcon = enumInternIcons.status_good;
                    ExecuteButton.PrimaryIconColor = (SolidColorBrush)FindResource("Color.Green");
                    ExecuteButton.IsHitTestVisible = false;
                    break;
                case enumQuickActionRevisionStatus.finishedWithError:
                    ExecuteButton.SelectedMaterialIcon = null;
                    ExecuteButton.SelectedInternIcon = enumInternIcons.status_bad;
                    ExecuteButton.PrimaryIconColor = (SolidColorBrush)FindResource("Color.Red");
                    ExecuteButton.IsHitTestVisible = false;
                    break;
                case enumQuickActionRevisionStatus.canceled:
                default:
                    ResetExecuteButton();
                    break;
            }
        }

        public async Task RunQuickActionAsync()
        {
            var status = enumQuickActionRevisionStatus.unknown;

            try
            {
                tokenSource.Dispose();
                tokenSource = new CancellationTokenSource();

                quickActionIsRunning = true;

                VisualizeQuickActionStart();
                tempQuickActionData = QuickActionData;

                Dictionary<cAdjustableParameter, object> parameterValues = null;

                if (QuickActionData.QuickActionParameters != null)
                {
                    parameterValues = AdjustableParameterSectionUc.ParameterValues;
                    AdjustableParameterSectionUc.ToggleIsActive(false);
                }

                List<object> result = await QuickActionData.RunQuickAction.Invoke(tokenSource.Token, parameterValues);

                if (QuickActionData.ActionSteps.Any(step => step.Status == enumQuickActionRevisionStatus.finishedWithError))
                    status = enumQuickActionRevisionStatus.finishedWithError;
                else if (QuickActionData.ActionSteps.Any(step => step.Status == enumQuickActionRevisionStatus.canceled))
                    status = enumQuickActionRevisionStatus.canceled;
                else if (QuickActionData.ActionSteps.All(step => step.Status == enumQuickActionRevisionStatus.finishedSuccessfull))
                    status = enumQuickActionRevisionStatus.finishedSuccessfull;

                RaiseEvent(new QuickActionEventArgs(QuickActionFinishedEvent, this) { QuickActionResult = result, QuickActionStatus = status, QuickAction = QuickActionData.QuickActionDefinition});

                CopyButton.Visibility = Visibility.Visible;

                if (QuickActionData.QuickActionDefinition.ColumnOutputFormattings?.Values.Any(formatting => formatting.IsSecret) ?? false)
                    SecretButton.Visibility = Visibility.Visible;

                quickActionIsRunning = false;
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                VisualizeQuickActionFinish(status);
            }
        }

        private async void ExecuteButton_Click()
        {
            try
            {
                if (quickActionIsRunning)
                {
                    CancelQuickAction();
                }
                else
                {
                    await RunQuickActionAsync();
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private void ExecuteButton_MouseUp(object sender, MouseButtonEventArgs e)
        {
            ExecuteButton_Click();
        }

        private void ExecuteButton_TouchDown(object sender, TouchEventArgs e)
        {
            ExecuteButton_Click();
        }

        #endregion

        #region CopyButton_Click

        private async Task CopyButton_ClickAsync()
        {
            try
            {
                if (quickActionIsRunning || DataProvider is null)
                    return;

                if (CopyButton.SelectedInternIcon == enumInternIcons.misc_check)
                    return;

                DataObject copyObject = null;

                if (QuickActionData.QuickActionDefinition is cF4sdQuickActionChained chainedQuickAction)
                {
                    int protocollCount = QuickActionData.ActionSteps.Count(step => step.Status == enumQuickActionRevisionStatus.finishedSuccessfull);
                    if (QuickActionData.ActionSteps.Count > protocollCount)
                        if (QuickActionData.ActionSteps[protocollCount].Status != enumQuickActionRevisionStatus.canceled)
                            protocollCount++;

                    copyObject = F4SDProtocoll.Instance.GetOfTypeAsDataObject<QuickActionProtocollEntry>(false, protocollCount);
                }
                else
                    copyObject = F4SDProtocoll.Instance.GetLatestOfTypeAsDataObject<QuickActionProtocollEntry>(false);

                System.Windows.Forms.Clipboard.SetDataObject(copyObject);

                await cUtility.ChangeIconToCheckAsync(CopyButton);
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private async void CopyButton_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) => await CopyButton_ClickAsync();

        private async void CopyButton_TouchDown(object sender, TouchEventArgs e) => await CopyButton_ClickAsync();

        #endregion

        #region VisbilityButton_Click

        private void SecretButton_Click(object sender)
        {
            secretsAreShown = !secretsAreShown;

            foreach (var resultElement in QuickActionResultStack.Children.OfType<QuickActionStatusMonitorResultElement>())
            {
                resultElement.ToggleSecretVisibility(secretsAreShown);
            }

            if (sender is AdaptableIcon.AdaptableIcon icon)
                icon.SelectedMaterialIcon = secretsAreShown ? MaterialIcons.MaterialIconType.ic_visibility_off : MaterialIcons.MaterialIconType.ic_visibility;

        }

        private void SecretButton_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) => SecretButton_Click(sender);

        private void SecretButton_TouchDown(object sender, TouchEventArgs e) => SecretButton_Click(sender);

        #endregion

        #region QuickActionFinished RoutedEvent

        public delegate void UiActionEventHandlerDelegate(object sender, QuickActionEventArgs args);

        public static readonly RoutedEvent QuickActionFinishedEvent = EventManager.RegisterRoutedEvent("QuickActionFinished", RoutingStrategy.Bubble, typeof(UiActionEventHandlerDelegate), typeof(QuickActionStatusMonitor));

        public event RoutedEventHandler QuickActionFinished
        {
            add { AddHandler(QuickActionFinishedEvent, value); }
            remove { RemoveHandler(QuickActionFinishedEvent, value); }
        }

        #endregion

        #endregion
    }

    public class QuickActionEventArgs : RoutedEventArgs
    {
        public List<object> QuickActionResult { get; set; }

        public cFasdQuickAction QuickAction { get; set; }

        public enumQuickActionRevisionStatus QuickActionStatus { get; set; }

        public QuickActionEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source)
        {
        }
    }
}
