using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace GFATask
{
    public partial class FormSettings : FormEx
    {
        /// <summary>
        /// Gibt den aktuell fokusierten Bildschirm aus, auf dem sich das Einstellungsfenster befindet.
        /// </summary>
        Screen currentscreen = null;


        /// <summary>
        /// Eine Auflistung von gezeichneten Rechtecken, die in Größe, Farbe und Form einem AppButton entsprechen und ringsum um die TestApp angefügt werden
        /// </summary>
        Rectangle[] dummyapps = new Rectangle[0];


        /// <summary>
        /// Eine Auflistung der veränderten Steuerelemente. Dadurch lassen sich einzelne Änderungen rückgängig machen
        /// </summary>
        public List<TableControlChange> ControlChanges { get; } = new List<TableControlChange>();


        /// <summary>
        /// Erstellt die ToolTips für die Steuerelemente
        /// </summary>
        private void SetToolTips()
        {
            tooltip.SetDefaultDesign();
            switch_darkmode.MouseEnter += (sender, e) => tooltip.Show("Die Farben des GFATask werden umgekehrt und Text wird mit weißer Schrift auf schwarzem Hintergrund gezeigt", sender as Control, new Point(0, (sender as Control).Height));
            switch_group_admin .MouseEnter += (sender, e) => tooltip.Show("Sollen die Apps in der Administrator-Liste gruppiert werden", sender as Control, new Point(0, (sender as Control).Height));
            switch_show_admin.MouseEnter += (sender, e) => tooltip.Show("Soll die Administrator-Liste angezeigt werden", sender as Control, new Point(0, (sender as Control).Height));
            switch_group_citrix.MouseEnter += (sender, e) => tooltip.Show("Sollen die Apps in der Citrix-Liste gruppiert werden", sender as Control, new Point(0, (sender as Control).Height));
            switch_show_citrix.MouseEnter += (sender, e) => tooltip.Show("Soll die Citrix-Liste angezeigt werden", sender as Control, new Point(0, (sender as Control).Height));
            switch_group_favorites.MouseEnter += (sender, e) => tooltip.Show("Sollen die Apps in der Favoriten-Liste gruppiert werden", sender as Control, new Point(0, (sender as Control).Height));
            switch_show_favorites.MouseEnter += (sender, e) => tooltip.Show("Soll die Favoriten-Liste angezeigt werden", sender as Control, new Point(0, (sender as Control).Height));
            switch_group_menu.MouseEnter += (sender, e) => tooltip.Show("Sollen die Apps in der Menü-Liste gruppiert werden", sender as Control, new Point(0, (sender as Control).Height));
            switch_group_user.MouseEnter += (sender, e) => tooltip.Show("Sollen die Apps in der Apps-Liste gruppiert werden", sender as Control, new Point(0, (sender as Control).Height));
            switch_show_user.MouseEnter += (sender, e) => tooltip.Show("Soll die Apps-Liste angezeigt werden", sender as Control, new Point(0, (sender as Control).Height));
            numAppBorder.MouseEnter += (sender, e) => tooltip.Show("Zeichnet einen Rahmen um die Apps", sender as Control, new Point(0, (sender as Control).Height));
            numAppHeight.MouseEnter += (sender, e) => tooltip.Show("Verändert die Apps in der Höhe", sender as Control, new Point(0, (sender as Control).Height));
            numAppRadius.MouseEnter += (sender, e) => tooltip.Show("Rundet die App ab", sender as Control, new Point(0, (sender as Control).Height));
            numAppImageRadius.MouseEnter += (sender, e) => tooltip.Show("Rundet den Symbolhintergrund innerhalb der App ab", sender as Control, new Point(0, (sender as Control).Height));
            numAppMargin.MouseEnter += (sender, e) => tooltip.Show("Verändert den Abstand zwischen den Apps", sender as Control, new Point(0, (sender as Control).Height));
            numAppWidth.MouseEnter += (sender, e) => tooltip.Show("Verändert die Apps in der Breite", sender as Control, new Point(0, (sender as Control).Height));
            numDelayHide.MouseEnter += (sender, e) => tooltip.Show("Wartet die angegebene Zeit in Millisekunden, bis der GFA-Task ausgeblendet wird", sender as Control, new Point(0, (sender as Control).Height));
            numDelayShow.MouseEnter += (sender, e) => tooltip.Show("Wartet die angegebene Zeit in Millisekunden, bis der GFA-Task eingeblendet wird." +
                "\nWird ignoriert wenn der GFA-Task per Klick eingeblendet wird", sender as Control, new Point(0, (sender as Control).Height));
            numDelaySpeed.MouseEnter += (sender, e) => tooltip.Show("Verändert die Geschwindigkeit des GFA-Task die er zum Ein- und Ausblenden benötigt", sender as Control, new Point(0, (sender as Control).Height));
            numFontSize.MouseEnter += (sender, e) => tooltip.Show("Verändert die Schriftgröße des GFA-Task", sender as Control, new Point(0, (sender as Control).Height));
            numGrouplistapps.MouseEnter += (sender, e) => tooltip.Show("Wenn eine App-Gruppe geöffnet wird, bestimmt dieser Wert die Anzahl der Apps in einer Zeile.\n" +
                "Kann vom eigentlichen Wert abweichen, wenn die Anzahl der gruppierten Apps nicht an die angegebene Zahl heranreicht,\n" +
                "oder die Breite der Apps nicht der Mindestbreite des Gruppenfensters entspricht", sender as Control, new Point(0, (sender as Control).Height));
            numOpacity.MouseEnter += (sender, e) => tooltip.Show("Verändert die maximale Transparenz des GFA-Task nachdem diese komplett eingeblendet wird", sender as Control, new Point(0, (sender as Control).Height));
            switchNecessaryClick.MouseEnter += (sender, e) => tooltip.Show("Benötigt zum Anzeigen des GFA-Task einen Mausklick am oberen Bildschirmrand", sender as Control, new Point(0, (sender as Control).Height) );
            cbAppSorting.MouseEnter += (sender, e) => tooltip.Show("Sortiert die Apps in den Listen nach" +
                "\n\t- Beliebtheit: Sortiert die Apps nach der Nutzung" +
                "\n\t- Name: Sortiert die Apps alphabetisch aufsteigend", sender as Control, new Point(0, (sender as Control).Height) );
            numActionRegionWidth.MouseEnter += (sender, e) => tooltip.Show("Setzt die Breite der Linie, am unteren Rand des GFATask", sender as Control, new Point(0, (sender as Control).Height));
            cbScreen.MouseEnter += (sender, e) => tooltip.Show("Wählt den Bildschirm aus, auf dem der GFA-Task angezeigt werden soll", sender as Control, new Point(0, (sender as Control).Height));
            switchOnlyImage.MouseEnter += (sender, e) => tooltip.Show("Die App wird mit Bild, aber ohne Text angezeigt", sender as Control, new Point(0, (sender as Control).Height));
        }


        /// <summary>
        /// Zeichnet einen weichen transparenten Übergang 
        /// </summary>
        /// <param name="rec">Der Bereich</param>
        /// <param name="fromcolor">100% Transparenz</param>
        /// <param name="tocolor">0% Transparenz</param>
        /// <param name="wrap">Richtung des Übergangs</param>
        /// <returns></returns>
        private LinearGradientBrush SetBrush(Rectangle rec, Color fromcolor, Color tocolor, WrapMode wrap) =>
            new LinearGradientBrush(new Rectangle(0, 0, rec.Width <= 0 ? 1 : rec.Width, (int)(rec.Height * .5) <= 0 ? 1 : (int)(rec.Height * .5)), fromcolor, tocolor, 0, false) { WrapMode = wrap };
            

        #region Erstellt die Bindings und EventHandler
        /// <summary>
        /// Erstellt die Bindings und EventHandler für die Listeneinstellungen
        /// </summary>
        private void CreateAppListBindings()
        {
            switch_group_menu.Checked = Config.User.Lists.Menu.Grouping;
            switch_group_menu.CheckStateChanged += (sender, e) =>
            {
                if (this.Created) XObjects.PreChanging.Add(Config.User.Lists.Menu, "Grouping", (sender as SwitchButton), (sender as SwitchButton).Checked, DoIt_Menu_Grouping);
            };

            switch_group_citrix.Checked = Config.User.Lists.Citrix.Grouping;
            switch_group_citrix.CheckStateChanged += (sender, e) =>
            {
                if (this.Created) XObjects.PreChanging.Add(Config.User.Lists.Citrix, "Grouping", (sender as SwitchButton), (sender as SwitchButton).Checked, DoIt_Citrix_Grouping);
            };

            switch_show_citrix.Checked = Config.User.Lists.Citrix.Show;
            switch_show_citrix.CheckStateChanged += (sender, e) => 
            {
                if (this.Created) XObjects.PreChanging.Add(Config.User.Lists.Citrix, "Show", (sender as SwitchButton), (sender as SwitchButton).Checked, DoIt_Citrix_Showing);
            };

            switch_group_favorites.Checked = Config.User.Lists.Favorites.Grouping;
            switch_group_favorites.CheckStateChanged += (sender, e) => 
            {
                if (this.Created) XObjects.PreChanging.Add(Config.User.Lists.Favorites, "Grouping", (sender as SwitchButton), (sender as SwitchButton).Checked, DoIt_Favorites_Grouping);
            };

            switch_show_favorites.Checked = Config.User.Lists.Favorites.Show;
            switch_show_favorites.CheckStateChanged += (sender, e) => 
            {
                if (this.Created) XObjects.PreChanging.Add(Config.User.Lists.Favorites, "Show", (sender as SwitchButton), (sender as SwitchButton).Checked, DoIt_Favorites_Showing);
            };

                Task.Run(async delegate
            {
                switch_group_admin.Enabled = (await XObjects.IsAdmin);
                switch_show_admin.Enabled = (await XObjects.IsAdmin);

                switch_group_admin.Checked = Config.User.Lists.Admin.Grouping;
                switch_group_admin.CheckStateChanged += (sender, e) =>
                {
                    if (this.Created) XObjects.PreChanging.Add(Config.User.Lists.Admin, "Grouping", (sender as SwitchButton), (sender as SwitchButton).Checked, DoIt_Admin_Grouping);
                };

                switch_show_admin.Checked = Config.User.Lists.Admin.Show;
                switch_show_admin.CheckStateChanged += (sender, e) =>
                {
                    if (this.Created) XObjects.PreChanging.Add(Config.User.Lists.Admin, "Show", (sender as SwitchButton), (sender as SwitchButton).Checked, DoIt_Admin_Showing);
                };
            });

            switch_group_user.Checked = Config.User.Lists.User.Grouping;
            switch_group_user.CheckStateChanged += (sender, e) =>
            {
                if (this.Created) XObjects.PreChanging.Add(Config.User.Lists.User, "Grouping", (sender as SwitchButton), (sender as SwitchButton).Checked, DoIt_User_Grouping);
            };

            switch_show_user.Checked = Config.User.Lists.User.Show;
            switch_show_user.CheckStateChanged += (sender, e) =>
            {
                if (this.Created) XObjects.PreChanging.Add(Config.User.Lists.User, "Show", (sender as SwitchButton), (sender as SwitchButton).Checked, DoIt_User_Showing);
            };

            numGrouplistapps.Value = Config.User.GroupListColumnCount;
            numGrouplistapps.ValueChanged += (sender, e) =>
            {
                if (this.Created) XObjects.PreChanging.Add(Config.User, "GroupListColumnCount", (sender as NumericEx), (int)(sender as NumericEx).Value, DoIt_GroupListColumnCount);
            };
        }


        /// <summary>
        /// Erstellt die Bindings und EventHandler für die erweiterten Einstellungen
        /// </summary>
        private void CreateExtendedBindings()
        {
            cbAppSorting.DataSource = new List<object>(new object[] { new { name = "Name", value = false }, new { name = "Beliebtheit", value = true } });
            cbAppSorting.DisplayMember = "name";
            cbAppSorting.ValueMember = "value";
            cbAppSorting.SelectedValue = Config.User.Prevalence;
            cbAppSorting.SelectedIndexChanged += (sender, e) => { if (this.Created) XObjects.PreChanging.Add(Config.User, "Prevalence", cbAppSorting, (bool)cbAppSorting.SelectedValue, DoIt_Prevalence); };
            
            numOpacity.Value = (decimal)Config.User.Window.Opacity;
            numOpacity.ValueChanged += (sender, e) => { if (this.Created) XObjects.PreChanging.Add(Config.User.Window, "Opacity", numOpacity, (double)(sender as NumericUpDown).Value, DoIt_Opacity); };

            numActionRegionWidth.Value = (decimal)Config.User.Window.ActionRegionHeight;
            numActionRegionWidth.ValueChanged += (sender, e) => { if (this.Created) XObjects.PreChanging.Add(Config.User.Window, "ActionRegionHeight", numActionRegionWidth, (int)(sender as NumericUpDown).Value, DoIt_ActionRegionWidth); };

            numFontSize.Value = (decimal)Config.User.Window.FontSize;
            numFontSize.ValueChanged += (sender, e) => { if (this.Created) XObjects.PreChanging.Add(Config.User.Window, "FontSize", numFontSize, (float)(sender as NumericUpDown).Value, DoIt_FontSize); } ;

            switch_darkmode.Checked = Config.User.DarkMode;
            switch_darkmode.CheckStateChanged += (sender, e) => { if (this.Created) XObjects.PreChanging.Add(Config.User, "DarkMode", switch_darkmode, bool.Parse(switch_darkmode.Checked.ToString()), DoIt_DarkMode); };


            this.LoadDisplays();
            cbScreen.SelectedIndexChanged += (sender, e) => { if (this.Created) XObjects.PreChanging.Add(Config.User, "Screen", cbScreen, cbScreen.Text.Replace(" [Dieser Monitor]","").Replace(" ",""), DoIt_ScreenChange); };
            cbScreen.DropDown += (sender , e) => { 
                if (this.Created) 
                    cbScreen.SelectedIndex = Screen.AllScreens.Select(scr => scr.DeviceName.Substring(scr.DeviceName.LastIndexOf("\\") + 1)).ToList().FindIndex(scr => scr == Config.User.Screen); 
            };
            cbScreen.SelectedIndex = Screen.AllScreens.Select(scr => scr.DeviceName.Substring(scr.DeviceName.LastIndexOf("\\") + 1)).ToList().FindIndex(scr => scr == Config.User.Screen);
        }


        /// <summary>
        /// Erstellt die Bindings und EventHandler für die Verzögerungseinstellungen
        /// </summary>
        public void CreateMouseFunctions()
        {
            switchNecessaryClick.Checked = Config.User.NecessaryClick;
            switchNecessaryClick.CheckStateChanged += (sender, e) =>
            {
                if (this.Created) XObjects.PreChanging.Add(Config.User, "NecessaryClick", switchNecessaryClick, switchNecessaryClick.Checked, DoIt_NecessaryClick);
            };

            numDelayShow.Value = Config.User.NecessaryClick ? 0 : (decimal)Config.User.Delay.Show;
            numDelayShow.ValueChanged += (sender, e) =>
            {
                if (this.Created) XObjects.PreChanging.Add(Config.User.Delay, "Show", numDelayShow, (float)(sender as NumericUpDown).Value, DoIt_DelayShow);
            };

            numDelayHide.Value = (decimal)Config.User.Delay.Hide;
            numDelayHide.ValueChanged += (sender, e) =>
            {
                if (this.Created) XObjects.PreChanging.Add(Config.User.Delay, "Hide", (Control)sender, (float)(sender as NumericUpDown).Value, DoIt_DelayHide);
            };

            numDelaySpeed.Value = Config.User.Delay.Speed;
            numDelaySpeed.ValueChanged += (sender, e) => 
            { 
                if (this.Created) XObjects.PreChanging.Add(Config.User.Delay, "Speed", numDelaySpeed, (int)(sender as NumericUpDown).Value, DoIt_Speed); 
            };
        }


        /// <summary>
        /// Erstellt die Bindings und EventHandler für die App-Darstellung
        /// </summary>
        private void CreateDeciptionBindings()
        {
            abtnTestApp.ActualWidth = Config.User.Apps.Size.Width;
            abtnTestApp.SizeChanged += abtnTestApp_SizeChanged;
            abtnTestApp.ImageOnly = Config.User.Apps.ImageOnly;
            abtnTestApp.Invalidate();

            switchOnlyImage.Checked = Config.User.Apps.ImageOnly;
            switchOnlyImage.CheckStateChanged += (sender, e) =>
            {
                if (this.Created)
                {
                    numAppWidth.Enabled = !switchOnlyImage.Checked;
                    abtnTestApp.ImageOnly = switchOnlyImage.Checked;
                    this.SetTestAppPanel();

                    XObjects.PreChanging.Add(Config.User.Apps, "ImageOnly", (Control)sender, switchOnlyImage.Checked, DoIt_AppImageOnly);
                }
            };

            numAppWidth.Enabled = !switchOnlyImage.Checked;
            numAppWidth.Value = Config.User.Apps.Size.Width;
            numAppWidth.Maximum = panelMargin.Width - 2;
            numAppWidth.ValueChanged += (sender, e) =>
            {
                if (this.Created && !Config.User.Apps.ImageOnly)
                {
                    abtnTestApp.Width = (int)numAppWidth.Value;
                    abtnTestApp.ActualWidth = (int)numAppWidth.Value;
                    XObjects.PreChanging.Add(Config.User.Apps.Size, "Width", (Control)sender, (int)numAppWidth.Value, DoIt_AppWidth);
                }
            };

            numAppHeight.Value = Config.User.Apps.Size.Height;
            numAppHeight.Maximum = panelMargin.Height - 3;
            numAppHeight.ValueChanged += (sender, e) =>
            {
                if (this.Created)
                {
                    abtnTestApp.Height = (int)numAppHeight.Value;
                    XObjects.PreChanging.Add(Config.User.Apps.Size, "Height", (Control)sender, (int)numAppHeight.Value, DoIt_AppHeight);
                }
            };

            numAppBorder.Value = Config.User.Apps.Border;
            numAppBorder.ValueChanged += NumAppBorder_ValueChanged;
            numAppBorder.ValueChanged += (sender, e) =>
            {
                if (this.Created) XObjects.PreChanging.Add(Config.User.Apps, "Border", (Control)sender, (int)numAppBorder.Value, DoIt_AppBorder);
            };

            numAppRadius.Value = Config.User.Apps.Radius.Button;
            numAppRadius.ValueChanged += NumAppRadius_ValueChanged;
            numAppRadius.ValueChanged += (sender, e) =>
            {
                if (this.Created) XObjects.PreChanging.Add(Config.User.Apps.Radius, "Button", (Control)sender, (int)numAppRadius.Value, DoIt_AppRadius);
            };

            numAppImageRadius.Value = Config.User.Apps.Radius.Button;
            numAppImageRadius.ValueChanged += NumAppImageRadius_ValueChanged;
            numAppImageRadius.ValueChanged += (sender, e) =>
            {
                if (this.Created) XObjects.PreChanging.Add(Config.User.Apps.Radius, "Image", (Control)sender, (int)numAppImageRadius.Value, DoIt_AppImageRadius);
            };

            numAppMargin.Value = Config.User.Apps.Margin;
            numAppMargin.ValueChanged += NumAppMargin_ValueChanged;
            numAppMargin.ValueChanged += (sender, e) =>
            {
                if (this.Created) XObjects.PreChanging.Add(Config.User.Apps, "Margin", (Control)sender, (int)numAppMargin.Value, DoIt_AppMargin);
            };

            panelMargin.Paint += PanelMargin_Paint;
        }
        #endregion


        #region DoIt Methoden
        private void DoIt_Prevalence(object value)
        {
            Config.User.Prevalence = (bool)value;
            XObjects.AllAppListPanels.ForEach(panel =>
            {
                Comparer.SortAllButtons(panel.FlowContent.Controls, Config.User.Prevalence);
            });
        }

        private void DoIt_Opacity(object value)
        {
            Config.User.Window.Opacity = (double)value;
            Config.User.Window.Size = Forms.Main.Size;
            Forms.Main.Opacity = (double)value;
            Forms.Main.SetOpacityStep();
        }

        private void DoIt_ActionRegionWidth(object value)
        {
            Config.User.Window.ActionRegionHeight = (int)value;
            Forms.Main.ActionRegionHeight = Config.User.Window.ActionRegionHeight;
            Forms.Main.SetStartValue();
            Forms.Main.SetOpacityStep();
            XObjects.Delay.Increase();
        }


        private void DoIt_FontSize(object value)
        {
            try
            {
                Config.User.Window.FontSize = Convert.ToSingle(value);
                Forms.Administration.SetDefaultDesign();
                Forms.AppButtonGroup.SetDefaultDesign();
                Forms.AppCreator.SetDefaultDesign();
                Forms.Groups.SetDefaultDesign();
                Forms.Settings.SetDefaultDesign();
                Task.Run(delegate
                {
                    Forms.Main.Invoke(new MethodInvoker(delegate
                    {
                        Forms.Main.SetDefaultDesign();
                        Win32API.SendMessage(Forms.Main.Handle, (int)WM.EXITSIZEMOVE, 0, 0);

                        Forms.Main.SetOpacityStep();
                        Forms.Main.Invalidate(true);
                    }));
                });
                XObjects.AllAppListPanels.ForEach(panel => panel.Invalidate(true));
                
                Config.User.Window.Size = Forms.Main.Size;
            }
            catch (Exception ex)
            {
                Log.EventLog.Write("Fehlerhaft Einstellung - FontSize", LogClassification.LowError, ex);
            }
            
        }

        private void DoIt_DarkMode(object value)
        {
            typeof(Forms).GetProperties().ToList().ForEach(prop =>
            {
                FormEx f = (FormEx)prop.GetValue(typeof(Forms));
                f.SetDefaultDesign();
            });
        }

        private void DoIt_ScreenChange(object value)
        {
            Config.User.Screen = value.ToString();
            Accessor.SetLastAppListPanel();
            Forms.Main.SetMinimumSize();
            Forms.Main.SetStartValue();
            Forms.Main.DesktopAlign();
        }

        private void DoIt_GroupListColumnCount(object value)
        {
            Config.User.GroupListColumnCount = (int)value;
            //Config.User = JSON.Read<Models.Config.User>(Paths.UserConfig.FullName);
        }

        private void DoIt_Menu_Grouping(object value) =>
            Creator.AppListPanel(Accessor.GetAppListPanel(AppType.Menu), Accessor.GetAppList(AppType.Menu));

        private void DoIt_Citrix_Grouping(object value) =>
            Creator.AppListPanel(Accessor.GetAppListPanel(AppType.Citrix), Accessor.GetAppList(AppType.Citrix));

        private void DoIt_Favorites_Grouping(object value) =>
            Creator.AppListPanel(Accessor.GetAppListPanel(AppType.Favorites), Accessor.GetAppList(AppType.Favorites));

        private void DoIt_Admin_Grouping(object value) =>
            Creator.AppListPanel(Accessor.GetAppListPanel(AppType.Admin), Accessor.GetAppList(AppType.Admin));

        private void DoIt_User_Grouping(object value) =>
            Creator.AppListPanel(Accessor.GetAppListPanel(AppType.User), Accessor.GetAppList(AppType.User));

        private void DoIt_Citrix_Showing(object value)
        {
            Accessor.GetAppListPanel(AppType.Citrix).Showing = (bool)value;
            Accessor.SetLastAppListPanel();
        }

        private void DoIt_Favorites_Showing(object value)
        {
            Accessor.GetAppListPanel(AppType.Favorites).Showing = (bool)value;
            Accessor.SetLastAppListPanel();
        }

        private void DoIt_Admin_Showing(object value)
        {
            Accessor.GetAppListPanel(AppType.Admin).Showing = (bool)value;
            Accessor.SetLastAppListPanel();
        }

        private void DoIt_User_Showing(object value)
        {
            Accessor.GetAppListPanel(AppType.User).Showing = (bool)value;
            Accessor.SetLastAppListPanel();
        }

        private void DoIt_Speed(object value)
        {
            XObjects.Delay.Reset(Config.User.Delay.Show, Config.User.Delay.Hide, XObjects.Delay.StartValue, XObjects.Delay.EndValue, (int)numDelaySpeed.Value);
            Forms.Main.SetOpacityStep();
            Win32API.SendMessage(Forms.Main.Handle, (int)WM.EXITSIZEMOVE, 0, 0);
        }

        private void DoIt_NecessaryClick(object value) =>
            Forms.Main.SetActionRegion();
        

        private void DoIt_DelayShow(object value)
        {
            XObjects.Delay.Reset((float)value, Config.User.Delay.Hide, XObjects.Delay.StartValue, XObjects.Delay.EndValue, Config.User.Delay.Speed);
        }

        private void DoIt_DelayHide(object value)
        {
            XObjects.Delay.Reset(Config.User.Delay.Show, (float)value, XObjects.Delay.StartValue, XObjects.Delay.EndValue, Config.User.Delay.Speed);
        }

        private void DoIt_AppBorder(object value)
        {
            Config.User.Apps.Border = (int)value;
            typeof(Forms).GetProperties().ToList().ForEach(prop =>
            {
                FormEx f = (FormEx)prop.GetValue(typeof(Forms));
                f.SetDefaultDesign();
            });
            XObjects.AllAppListPanels.ForEach(panel =>
                panel.FlowContent.Controls.OfType<AppListButton>().ToList().ForEach(button => button.BorderSize = (int)value));
        }

        private void DoIt_AppRadius(object value)
        {
            Config.User.Apps.Radius.Button = (int)value;
            this.SetDefaultDesign();
            XObjects.AllAppListPanels.ForEach(panel =>
                panel.FlowContent.Controls.OfType<AnimationButton>().ToList().ForEach(button => button.Radius = (int)value));
            Forms.Administration.SetDefaultDesign();
        }

        private void DoIt_AppImageRadius(object value)
        {
            Config.User.Apps.Radius.Image = (int)value;
            this.SetDefaultDesign();
            XObjects.AllAppListPanels.ForEach(panel =>
                panel.FlowContent.Controls.OfType<AnimationButton>().ToList().ForEach(button => button.ImageRadius = (int)value));
            Forms.Administration.SetDefaultDesign();
        }

        private void DoIt_AppMargin(object value)
        {
            Config.User.Apps.Margin = (int)value;
            this.SetDefaultDesign();
            XObjects.AllAppListPanels.ForEach(panel =>
                panel.FlowContent.Controls.OfType<AnimationButton>().ToList().ForEach(button => button.Margin = new Padding((int)value)));
            Forms.Administration.SetDefaultDesign();
        }

        private void DoIt_AppImageOnly(object value)
        {
            this.SetDefaultDesign();
            XObjects.AllAppListPanels.ForEach(panel =>
            
                panel.FlowContent.Controls.OfType<AppListButton>().ToList().ForEach(button =>
                {
                    if (button.GetType() == typeof(GroupButton))
                    {
                        ((GroupButton)button).ContainedAppButtons.ToList().ForEach(cbtn =>
                        {
                            cbtn.ImageOnly = (bool)value;
                            cbtn.ImageMargin = (bool)value ? 0 : 3;
                            cbtn.ImageAutoSize = ImageAutoSizeDirection.Height;
                            cbtn.Invalidate();
                        });
                    }
                    button.ImageOnly = (bool)value;
                    button.ImageMargin = (bool)value ? 0 : 3;
                    button.ImageAutoSize = ImageAutoSizeDirection.Height;
                    button.Invalidate();
                }));
            Forms.Administration.SetDefaultDesign();
        }

        private void DoIt_AppWidth(object value)
        {
            if (!switchOnlyImage.Checked)
                Config.User.Apps.Size = new Size((int)value, Config.User.Apps.Size.Height);
            this.SetDefaultDesign();
            XObjects.AllAppListPanels.ForEach(panel =>
                panel.FlowContent.Controls.OfType<AppListButton>().ToList().ForEach(button =>
                {
                    if(button.GetType() == typeof(GroupButton))
                    {
                        ((GroupButton)button).ContainedAppButtons.ToList().ForEach(cbtn =>
                        {
                            cbtn.ActualWidth = (int)value;
                            cbtn.Width = (int)value;
                            cbtn.SetDefaultDesign();
                        });
                    }
                    button.ActualWidth = (int)value;
                    button.Width = (int)value;
                    button.SetDefaultDesign();
                }));

            if (Forms.AppButtonGroup.Visible)
                Forms.AppButtonGroup.Sizing();

            Forms.Administration.SetDefaultDesign();
        }

        private void DoIt_AppHeight(object value)
        {
            Config.User.Apps.Size = new Size(Config.User.Apps.Size.Width, (int)value);
            this.SetDefaultDesign();
            XObjects.AllAppListPanels.ForEach(panel =>
            {
                panel.FlowContent.Controls.OfType<AppListButton>().ToList().ForEach(button => button.Height = (int)value);
                panel.FlowContent.Controls.OfType<GroupButton>().ToList().ForEach(button => button.ContainedAppButtons.ToList().ForEach(cbtn => cbtn.Height = (int)value));
            });

            if (Forms.AppButtonGroup.Visible)
                Forms.AppButtonGroup.Sizing();

            Forms.Administration.SetDefaultDesign();
        }
        #endregion


        private void SetTestAppPanel()
        {
            abtnTestApp.Size = switchOnlyImage.Checked ? new Size((int)numAppHeight.Value, (int)numAppHeight.Value) : Config.User.Apps.Size;
            abtnTestApp.Animation = true;
            abtnTestApp.Location = new Point((panelMargin.Width / 2) - (abtnTestApp.Width / 2), (panelMargin.Height / 2) - (abtnTestApp.Height / 2));
            abtnTestApp.AnimationRegion = AnimationRgn.Both;
            abtnTestApp.ImageMargin = switchOnlyImage.Checked ? 0 : 3;
            abtnTestApp.ImageAutoSize = ImageAutoSizeDirection.Height;
            this.InvalidateDummyApps();
        }

        public void LoadDisplays()
        {
            cbScreen.DataSource = Screen.AllScreens.Select(scr => new { key = Array.IndexOf(Screen.AllScreens, scr) + 1, value = $"{scr.DeviceName.Substring(scr.DeviceName.LastIndexOf("\\") + 1)} {(scr.Bounds.Contains(this.Bounds.Location) ? "[Dieser Monitor]" : "")}" }).ToList();
            // Fügt das Element DYNAMIC hinzu, was bewirkt, dass der GFATask an dem Bildschirm angeheftet wird, auf dem sich der Mauszeiger befindet - Hat noch nicht so richtig funktioniert
            //cbScreen.DataSource = Screen.AllScreens.Select(scr => new { key = Array.IndexOf(Screen.AllScreens, scr) + 1, value = $"{scr.DeviceName.Substring(scr.DeviceName.LastIndexOf("\\") + 1)} {(scr.Bounds.Contains(this.Bounds.Location) ? "[Dieser Monitor]" : "")}" }).Union(new[] { new { key = -2, value = "DYNAMIC" } }).ToList();
            cbScreen.DisplayMember = "Value";
            cbScreen.ValueMember = "Key";
        }

        public FormSettings()
        {
            InitializeComponent();
            this.SetDefaultDesign();

            this.CreateAppListBindings();
            this.CreateExtendedBindings();
            this.CreateDeciptionBindings();
            this.CreateMouseFunctions();
            this.SetTestAppPanel();

            abtnAnwenden.TextAlign = ContentAlignment.MiddleCenter;
            abtnSubmit.TextAlign = ContentAlignment.MiddleCenter;
            abtnVerwerfen.TextAlign = ContentAlignment.MiddleCenter;

            this.Icon = Icon.FromHandle(new Bitmap(File.Open(Paths.Icons.Directory + "optionen.png", FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete)).GetHicon());
            this.DesktopAnchor(DesktopAnchor.Center, this.GripSize);

            tableGeneral.Controls.Cast<Control>().Where(ctl => ctl.GetType() != typeof(Label) && ctl.GetType() != typeof(AnimationButton)).ToList().ForEach(ctl =>
            {
                if (typeof(NumericEx) == ctl.GetType())
                {
                    (ctl as NumericEx).ValueChanged += (s, evt) =>
                    {
                        AddResetButton(ctl);
                    };
                }
                else if (typeof(SwitchButton) == ctl.GetType())
                {
                    (ctl as SwitchButton).CheckStateChanged += (s, evt) =>
                    {
                        AddResetButton(ctl);
                    };
                }
                else if (typeof(ListBox) == ctl.GetType())
                {
                    (ctl as ListBox).SelectedIndexChanged += (s, evt) =>
                    {
                        AddResetButton(ctl);
                    };
                }
                else if (typeof(ComboBox) == ctl.GetType())
                {
                    (ctl as ComboBox).SelectionChangeCommitted += (s, evt) =>
                    {
                        AddResetButton(ctl);
                    };
                }
            });

            label3.Paint += Designer.DrawHeaderLabel;
            label5.Paint += Designer.DrawHeaderLabel;
            label7.Paint += Designer.DrawHeaderLabel;
            label21.Paint += Designer.DrawHeaderLabel;
            this.InvalidateDummyApps();
            this.SetToolTips();
        }


        /// <summary>
        /// Fügt der "Zurücksetzen"-Auflistung das Steuerelement hinzu, damit der alte Wert wiederhergestellt werden kann
        /// </summary>
        /// <param name="control"></param>
        private void AddResetButton(Control control)
        {
            if (!this.ControlChanges.Select(change => change.Control).Contains(control))
            {
                TableControlChange change = new TableControlChange(tableGeneral, control.Location, 25);
                change.Click += (sender, e) =>
                {
                    XObjects.PreChanging.Reset(change.Control);
                    (sender as TableControlChange).Clear();
                    this.ControlChanges.Remove(change);
                    tableGeneral.Invalidate();
                };
                this.ControlChanges.Add(change);
            }
        }


        /// <summary>
        /// Zeichnet die umliegenden AppButtons im Test-Panel neu
        /// </summary>
        private void InvalidateDummyApps()
        {
            int margin = (int)(numAppMargin.Value + (numAppMargin.Value == 0 ? 0 : 3));
            Size size = new Size(abtnTestApp.ClientSize.Width - 1, abtnTestApp.ClientSize.Height - 1);
            dummyapps = new Rectangle[]
           {
                // Left
                new Rectangle(new Point(abtnTestApp.Location.X - abtnTestApp.Width - margin , abtnTestApp.Location.Y ), size),
                // TopLeft
                new Rectangle(new Point(abtnTestApp.Location.X - abtnTestApp.Width - margin , abtnTestApp.Location.Y  - abtnTestApp.Height - margin), size ),
                // Top
                new Rectangle(new Point(abtnTestApp.Location.X , abtnTestApp.Location.Y  - abtnTestApp.Height - margin), size ),
                // TopRight
                new Rectangle(new Point(abtnTestApp.Location.X + abtnTestApp.Width + margin , abtnTestApp.Location.Y  - abtnTestApp.Height - margin), size ),
                // Right
                new Rectangle(new Point(abtnTestApp.Location.X + abtnTestApp.Width + margin , abtnTestApp.Location.Y ), size ),
                // BottomRight
                new Rectangle(new Point(abtnTestApp.Location.X + abtnTestApp.Width + margin , abtnTestApp.Location.Y  + abtnTestApp.Height + margin), size ),
                // Bottom
                new Rectangle(new Point(abtnTestApp.Location.X , abtnTestApp.Location.Y + abtnTestApp.Height + margin), size ),
                // BottomLeft
                new Rectangle(new Point(abtnTestApp.Location.X - abtnTestApp.Width - margin , abtnTestApp.Location.Y + abtnTestApp.Height + margin), size ),
           };
        }


        /// <summary>
        /// Übernimmt alle vorläufigen Speicherungen in die JSON-Config
        /// </summary>
        /// <param name="json">Gibt die JSON-Config Datei an</param>
        private void SaveAll(JSONConfig json)
        {
            XObjects.PreChanging.CommitAll();
            this.ControlChanges.ForEach(change => change.Clear());
            this.ControlChanges.Clear();
            JSON.Save(json);
        }


        /// <summary>
        /// Leert die vorläufigen Speicherungen aus der Auflistung
        /// </summary>
        private void ResetAll()
        {
            XObjects.PreChanging.ResetAll();
            this.ControlChanges.ForEach(change => change.Clear());
            this.ControlChanges.Clear();
            tableGeneral.Invalidate();
        }


        protected override void OnShown(EventArgs e)
        {
            base.OnShown(e);
            // Fügt der Auflistung der vorläufigen Änderungen die aktuellen Anfangswerte hinzu, damit diese wiederhergestellt werden können
            XObjects.PreChanging.GetTemps(Accumulations.Controls(this));
        }

        protected override void OnLocationChanged(EventArgs e)
        {
            base.OnLocationChanged(e);
            if (currentscreen != null || Screen.FromPoint(this.DesktopLocation) != currentscreen)
            {
                this.LoadDisplays();
            }
        }

        private void NumAppBorder_ValueChanged(object sender, EventArgs e)
        {
            if (!this.Created) return;
            this.InvalidateDummyApps();
            abtnTestApp.BorderSize = (int)numAppBorder.Value;
            panelMargin.Invalidate();
        }

        private void NumAppRadius_ValueChanged(object sender, EventArgs e)
        {
            if (!this.Created) return;
            this.InvalidateDummyApps();
            abtnTestApp.Radius = (int)numAppRadius.Value;
            panelMargin.Invalidate();
        }

        private void NumAppImageRadius_ValueChanged(object sender, EventArgs e)
        {
            if (!this.Created) return;
            this.InvalidateDummyApps();
            abtnTestApp.ImageRadius = (int)numAppImageRadius.Value;
            panelMargin.Invalidate();
        }

        private void NumAppMargin_ValueChanged(object sender, EventArgs e)
        {
            if (!this.Created) return;
            this.InvalidateDummyApps();
            panelMargin.Invalidate();
        }

        private void PanelMargin_Paint(object sender, PaintEventArgs e)
        {
            int border = (int)numAppBorder.Value;
            int margin = (int)numAppMargin.Value * 2;

            dummyapps.ToList().ForEach(dummyapp =>
            {
                e.Graphics.FillPath(new SolidBrush(this.BackColor), dummyapp.ToRoundedRectangle(abtnTestApp.Radius, RectangleCorners.All));
                e.Graphics.DrawPath(new Pen(border == 0 ? Color.Empty : Config.Main.Colors.Apps.Default.Border, border) { Alignment = PenAlignment.Outset }, dummyapp.ToRoundedRectangle(abtnTestApp.Radius, RectangleCorners.All));
                e.Graphics.DrawString("Test App", abtnTestApp.Font, new SolidBrush(abtnTestApp.ForeColor), dummyapp, new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
            });

            e.Graphics.FillRectangle(this.SetBrush(e.ClipRectangle, this.BackColor, Color.FromArgb(0, 0, 0, 0), WrapMode.Tile), new Rectangle(e.ClipRectangle.Location, new Size(e.ClipRectangle.Width / 2, e.ClipRectangle.Height)));
            e.Graphics.FillRectangle(this.SetBrush(e.ClipRectangle, Color.FromArgb(0, 0, 0, 0), this.BackColor, WrapMode.TileFlipX), new Rectangle(new Point(e.ClipRectangle.X + e.ClipRectangle.Width / 2, e.ClipRectangle.Y), new Size(e.ClipRectangle.Width / 2, e.ClipRectangle.Height)));

            if (border > 0 && margin > 0)
            {
                e.Graphics.DrawPath(new Pen(Color.Red, 2),
                new Rectangle(abtnTestApp.Right - border - (margin == 0 ? border : margin), abtnTestApp.Bottom - border - margin, (margin * 3) + (border * 3), (margin * 3) + (border * 3)).ToRoundedRectangle(border + margin, RectangleCorners.All));
            }
        }

        private void abtnTestApp_SizeChanged(object sender, EventArgs e)
        {
            var _this = sender as AppListButton;
            //if (!switchOnlyImage.Checked)
            //    numAppWidth.Value = _this.Width;
            //else
            //    numAppWidth.Value = Config.User.Apps.Size.Width;
            numAppHeight.Value = (decimal)_this.Height;

            _this.Width = _this.ImageOnly ? _this.Height : _this.ActualWidth;

            this.InvalidateDummyApps();
            panelMargin.Invalidate();
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            this.ResetAll();
            this.Visible = false;
            e.Cancel = true;
            base.OnClosing(e);
        }

        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);
            if (this.Visible)
                XObjects.Delay.Increase();
        }

        private void abtnAnwenden_Click(object sender, EventArgs e)
        {
            this.SaveAll(JSONConfig.User);
            this.ResetAll();
            this.Close();
        }

        private void abtnVerwerfen_Click(object sender, EventArgs e)
        {
            this.ResetAll();
            this.Close();
        }

        private void abtnSubmit_Click(object sender, EventArgs e)
        {
            this.SaveAll(JSONConfig.User);
            this.ResetAll();
        }

        private void FormSettings_DpiChanged(object sender, DpiChangedEventArgs e)
        {
            e.Cancel = true;
        }
    }
}
