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

namespace GFATask
{
    public partial class FormMain : FormEx
    {
        /// <summary>
        /// Gibt den aktuell fokusierten Bildschirm aus, auf dem sich der GFA-Task befindet
        /// </summary>
        private Screen currentscreen = null;

        /// <summary>
        /// Darstellung des Aktionsbereichs des GFA-Task
        /// </summary>
        Rectangle actionregion = new Rectangle();

        /// <summary>
        /// Gibt die absoluten Y-Koordinaten für das Aus[0]- und Einblenden[1] an
        /// </summary>
        private int[] start_stop_y = new int[2];

        /// <summary>
        /// Speichert den Wert einer einzelnen Einheit ab, die den GFA-Task parallel zum hoch- und runterfahren ein- und ausblendet.
        /// Damit endet der Ein- und Ausblendevorgang zeitgleich mit dem hoch- und runterfahren
        /// </summary>
        private double opacitystep;


        private int _actionregionheight = 1;
        /// <summary>
        /// Zeichenbreite der Aktionslinie des Hauptfensters
        /// </summary>
        public int ActionRegionHeight
        {
            get => _actionregionheight; set
            {
                _actionregionheight = value;
                this.SetActionRegion();
                this.Invalidate();
            }
        }
        

        public FormMain()
        {


            if (Config.User.ErrorHandle)
                Log.EventLog.StartLoggingUI(Config.Main.LoggerAppPath, "");
            Log.EventLog.SetAutoHandleException(true);

            #region Erstellung der Forms zur Laufzeit / in der selben AppDomain
            Forms.Main = this;
            Forms.Info = new FormInfo();
            Forms.Groups = new FormGroups();
            Forms.Settings = new FormSettings();
            Forms.Administration = new FormAdmin();
            Forms.AppCreator = new FormAppCreator();
            Forms.AppButtonGroup = new FormAppButtonGroup();
            #endregion

            InitializeComponent();

            this.UseNewsFeeds();
            Accumulations.Controls(this).Reverse().OfType<AppListPanel>().ToList().ForEach(applistpanel =>
            {
                XObjects.AllAppListPanels.Add(applistpanel);
            });

            #region Configs
            try
            {
                // Lädt das Layout des GFATask 
                this.SetDefaultDesign();
                this.Size = Config.User.Window.Size.Height < this.MinimumSize.Height ? new Size(Config.User.Window.Size.Width, this.MinimumSize.Height) : Config.User.Window.Size;
                _actionregionheight = Config.User.Window.ActionRegionHeight;
                this.SetStartValue();
            }
            catch (Exception ex)
            {
                Log.EventLog.Write("Auslesefehler des Layouts", LogClassification.CriticalError, ex);
            }

            try
            {
                // Lädt die Größe des GFATask 
                XObjects.Delay = new Delay(Config.User.NecessaryClick ? 0 : Config.User.Delay.Show, Config.User.Delay.Hide, Config.User.Delay.Speed == 100 ? 99 : Config.User.Delay.Speed, start_stop_y[0], start_stop_y[1]);
                XObjects.Delay.ValueChanged += Delay_ValueChanged;
                this.SetOpacityStep();
            }
            catch (Exception ex)
            {
                Log.EventLog.Write("Delay nicht erstellt", LogClassification.CriticalError, ex);
            }

            try
            {
                // Richtet den GFATask am Bildschirm aus
                this.DesktopAlign();
            }
            catch (Exception ex)
            {
                Log.EventLog.Write("Fehler in GFATask-Koordinaten", LogClassification.MediumError, ex);
            }
            #endregion

            #region AppListPanels / Apperstellung
            // Richtet im Falle einer Falschsortierung die AppListPanels richtig aus
            this.Controls.SetChildIndex(applistpanelMenu, 4);
            this.Controls.SetChildIndex(applistpanelCitrix, 3);
            this.Controls.SetChildIndex(applistpanelFavorites, 2);
            this.Controls.SetChildIndex(applistpanelAdmin, 1);
            this.Controls.SetChildIndex(applistpanelUser, 0);

            // Lädt die Größe der entsprechenden Appliste aus der Config.User Datei
            XObjects.AllAppListPanels.ForEach(panel =>
            {
                try
                {
                    panel.Height = Accessor.GetListProperties(panel.AppType).Height;
                }
                catch (Exception ex)
                {
                    Log.EventLog.Write(string.Format("Größenfehler in AppListPanel {0}", panel.Tag.ToString().First().ToString() + panel.Tag.ToString().Skip(1).ToString().ToLower()), LogClassification.CriticalError, ex);
                }
            });

            this.CreateAppListPanels();

            Accessor.SetLastAppListPanel();
            #endregion

            #region Active Directory Groups
            try
            {
                // Lädt die Active Directory-Gruppen in das FormGroup
                Forms.Groups.Loading();
            }
            catch (Exception ex)
            {
                Log.EventLog.Write("AD Gruppen konnten nicht ausgelesen werden", LogClassification.CriticalError, ex);
            }
            #endregion

            #region Systemkontextmenü
            this.RemoveSysMenuItem(SystemContextMenuEntry.Maximieren | SystemContextMenuEntry.Minimieren | SystemContextMenuEntry.Schließen | SystemContextMenuEntry.Seperator);
            this.AddSysMenuItem(new ToolStripMenuItem("Meine Gruppen", null, (sender, e) => Accessor.OpenForm("Groups")));
            this.AddSysMenuItem(new ToolStripMenuItem("Info", null, (sender, e) => { SystemApps.Info(out _); }));
            this.InsertSysMenuItem(2, new ToolStripMenuItem("Einstellungen", null, (sender, e) => { SystemApps.Settings(out _); }));
            this.InsertSysMenuItem(3, new ToolStripSeparator());
            this.InsertSysMenuItem(4, new ToolStripMenuItem("Konfiguration sichern", null, (sender, e) => { SystemApps.Backup(out _); }));
            this.InsertSysMenuItem(5, new ToolStripMenuItem("Konfiguration laden", null, (sender, e) => { SystemApps.LoadBackup(out _); }));
            this.InsertSysMenuItem(6, new ToolStripSeparator());
            Task.Run(async delegate
            {
                if (await XObjects.IsADGroupFinish)
                {
                    if (AD.Groups.Select(group => group.Name).Contains(Config.Main.Administration.ActiveDirectoryGroup))
                    {
                        Forms.Main.Invoke(new MethodInvoker(delegate
                        {
                            this.InsertSysMenuItem(7, new ToolStripMenuItem("Administration", null, (sender, e) => { Accessor.OpenForm("Administration"); }));
                            this.InsertSysMenuItem(8, new ToolStripSeparator());
                            this.InsertSysMenuItem(this.SysContextMenu.Items.Count, new ToolStripMenuItem("Beenden", null, (sender, e) => { SystemApps.Kill(out _); }));
                        }));
                    }
                }
            });
            this.InsertSysMenuItem(this.SysContextMenu.Items.Count, new ToolStripMenuItem("Neustart", null, (sender, e) => { SystemApps.Restart(out _); }));
            #endregion

            #region Globale Hooks
            try
            {
                // Installiert die Mouse-Hooks
                Hooks.Mouse.Install();
                Hooks.Mouse.MouseMove += Hooks.Mouse_Move;
                Hooks.Mouse.LeftButtonDown += Hooks.Mouse_Up;
                Hooks.Mouse.RightButtonDown += Hooks.Mouse_Up;

                
            }
            catch (Exception ex)
            {
                Log.EventLog.Write("Konnte Mouse-Hook nicht installieren", LogClassification.Crash, ex);
                throw;
            }

            try
            {
                // Installiert die Tastatur-Hooks für die System-Apps und die SearchBox
                // Fängt die Tastenkombinationen ab, sodass sie für Windows nicht mehr erreichbar sind, solange das Programm läuft
                Hooks.KeyBoard.Interceptor.RegisterHotKey(Modifier.CTRL, Keys.F1, "info");
                Hooks.KeyBoard.Interceptor.RegisterHotKey(Modifier.CTRL, Keys.F2, "settings");
                Hooks.KeyBoard.Interceptor.RegisterHotKey(Modifier.CTRL, Keys.F3, "admin");
                Hooks.KeyBoard.Interceptor.KeyPressed += Hooks.KeyBoard_Intercept_KeyPress;
            }
            catch (Exception ex)
            {
                Log.EventLog.Write("HotKeys konnten nicht registriert werden", LogClassification.MediumError, ex);
            }
            #endregion
        }

        /// <summary>
        /// Erstellt die App- und GoupButtons in den AppListPanels
        /// </summary>
        public void CreateAppListPanels()
        {
            try
            {
                Creator.AppListPanel(applistpanelMenu, AppLists.Menu);
            }
            catch (Exception ex)
            {
                Log.EventLog.Write("Apps in Menü-Liste nicht erstellt", LogClassification.CriticalError, ex);
            }

            try
            {
                Creator.AppListPanel(applistpanelCitrix, AppLists.Citrix);
            }
            catch (Exception ex)
            {
                Log.EventLog.Write("Apps in Citrix-Liste nicht erstellt", LogClassification.CriticalError, ex);
            }

            try
            {
                Creator.AppListPanel(applistpanelFavorites, AppLists.Favorites);
                //Creator.AppListPanel(applistpanelFavorites, AppLists.Favorites);
            }
            catch (Exception ex)
            {
                Log.EventLog.Write("Apps in Favoriten-Liste nicht erstellt", LogClassification.CriticalError, ex);
            }

            try
            {
                Creator.AppListPanel(applistpanelAdmin, AppLists.Admin);
            }
            catch (Exception ex)
            {
                Log.EventLog.Write("Apps in Admin-Liste nicht erstellt", LogClassification.CriticalError, ex);
            }

            try
            {
                Creator.AppListPanel(applistpanelUser, AppLists.User);
            }
            catch (Exception ex)
            {
                Log.EventLog.Write("Apps in User-Apps-Liste nicht erstellt", LogClassification.CriticalError, ex);
            }
        }
       

        /// <summary>
        /// Richtet den GFA-Task mittig am oberen Rand des angegebenen Bildschirms aus
        /// </summary>
        public void DesktopAlign()
        {
            try
            {
                this.SetStartValue();
                this.DesktopLocation = new Point(Desktop.Anchor(this, currentscreen, DesktopAnchor.Top).X, start_stop_y[0]);
            }
            catch (Exception ex)
            {
                Log.EventLog.Write("Ausrichtungsfehler am Bildschirm", LogClassification.CriticalError,
                    new Exception(string.Format("{0}\n\n{1}", "Der Bildschirm auf dem der GFA-Task ausgerichtet werden soll, konnte nicht gefunden werden.", ex.Message), ex.InnerException));

                //if (Notify.Show("Der ausgewählte Bildschirm konnte nicht gefunden werden. Der GFA-Task wird auf dem Hauptbildschirm dargestellt.\n\n" +
                //    "Um den eigentlichen Bildschirm wiederherzustellen, öffnen Sie die App \"Einstellungen\" in der Menüliste und wählen dort einen geeigneten Bildschirm aus", NotifyButtons.OK, NotifyType.Message, Designer.Notify(300, 200), null, "SelfService").Result == DialogResult.OK)
                //{
                //    int primary_id = Array.IndexOf(Screen.AllScreens, Screen.AllScreens.First(scr => scr.Primary)) + 1;
                //    this.MaximumSize = Screen.PrimaryScreen.WorkingArea.Size;
                //    this.DesktopLocation = Desktop.Anchor(this, primary_id, DesktopAnchor.Top, (int)-XObjects.Delay.StartValue);
                //    Config.User.Screen = Screen.AllScreens[ primary_id -1].DeviceName;
                //    JSON.Save(JSONConfig.User);
                //}
            }
            XObjects.Delay.Decrease();
        }


        /// <summary>
        /// Lädt die Symbole der internationalen Welttage, abhängig von den aktivierten Welttages-Zeiträumen im Administrationsbereich
        /// </summary>
        public void UseNewsFeeds()
        {
            // Der Programmname mit dynamischer Versionierung
            this.Text = $"{InfoClass.Program}";

            // Ist heute mindestens ein internationaler Welttag aktiviert
            if (Config.NewsFeeds.Exists(this.GetCurrentNewsFeed()))
            {
                // Liest alle heutigen internationalen Welttage aus der worldday.json aus
                var newsfeeds = Config.NewsFeeds.FindAll(this.GetCurrentNewsFeed());
                newsfeeds.ForEach(newsfeed => this.Text += $" | {newsfeed.Title.Replace("\\n", "\n")}");

                // Sind heute internationale Welttage aktiv, besitzen diese jedoch keine Symbole, dann wird das Grünflächenamt Logo angezeigt
                if (newsfeeds.All(news => news.Icon == null || news.Icon == ""))
                {
                    this.Icon = Icon.FromHandle(new Bitmap(Paths.Icons.Directory + @"\System\GFA.png").GetHicon());
                }
                else
                {
                    // Ist heute nur ein internationaler Welttag in der worldday.json Datei aktiv, oder gibt es nur ein Symbol, wird dieses angezeigt
                    if (newsfeeds.Count == 1 || newsfeeds.Count(news => news.Icon != null && news.Icon != "") == 1)
                    {
                        this.Icon = Icon.FromHandle(new Bitmap(Paths.NewsFeeds.Icons.Directory + newsfeeds.Find(w => w.Icon != null && w.Icon != "").Icon).GetHicon());
                    }
                    else
                    {
                        // Sind mehrere aktiv, so werden diese in einem Symbol zusammengeführt
                        this.Icon = Icon.FromHandle(newsfeeds.Where(w => w.Icon != null && System.IO.File.Exists(Paths.NewsFeeds.Icons.Directory + w.Icon)).Select(w => new Bitmap(Paths.NewsFeeds.Icons.Directory + w.Icon)).ToArray().Merge(this.Icon.Size, 2).GetHicon());
                    }
                }
            }
            // Sind heute keine internationalen Welttage aktiv, dann wird das Grünflächenamt Logo angezeigt
            else
            {
                this.Text = $"{InfoClass.Program} | Herzlich Willkommen";
                this.Icon = Icon.FromHandle(new Bitmap(Paths.Icons.Directory + @"\System\GFA.png").GetHicon());
            }
        }


        /// <summary>
        /// Berechnet einen Schritt um beim Abschluss der Delay Funktion den richtigen Transparenzwert zu erhalten
        /// </summary>
        public void SetOpacityStep() =>
            opacitystep = XObjects.Delay.GetSteps(Config.User.Window.Opacity - .5D);


        /// <summary>
        /// Definiert die Start- und Stop-Y-Koordinate für das Erscheinen und Ausblenden des GFATask
        /// </summary>
        public void SetStartValue()
        {
            // Wenn es den Bildschirm nicht gibt, dann soll der Primäre genommen werden,
            // ansonsten wird geprüft, ob der ausgewählte Bildschirm den obersten Punkt aller Bildschirme enthält.
            // Wenn nicht, wird der Bildschirm mit dem gerinsten Y-Koordinaten-Wert genutzt

            //if(Config.User.Screen == "DYNAMIC")
            //{
            //    currentscreen = Screen.FromPoint(Cursor.Position);
            //}
            //else
            //{

            if (!Screen.AllScreens.ToList().Exists(scr => scr.DeviceName.Replace(@"\\.\", "") == Config.User.Screen))
            {
                currentscreen = Screen.PrimaryScreen;
            }
            else
            {
                Screen tempscreen = Screen.AllScreens.ToList().Find(scr => scr.DeviceName.Replace(@"\\.\", "") == Config.User.Screen);
                if (tempscreen.Bounds.Y != Screen.AllScreens.Min(scr => scr.Bounds.Y) && (tempscreen.Bounds.Right <= Screen.PrimaryScreen.Bounds.Left && tempscreen.Bounds.Left <= Screen.PrimaryScreen.Bounds.Right))
                {
                    currentscreen = Screen.AllScreens.ToList().Find(scr => scr.Bounds.Y == Screen.AllScreens.Min(s => s.Bounds.Y));
                }
                else
                {
                    currentscreen = tempscreen;
                }
            }

            //currentscreen = Screen.AllScreens.ToList().Find(scr => scr.DeviceName.Replace(@"\\.\", "") == Config.User.Screen) == null ?
            //Screen.PrimaryScreen :
            //Screen.AllScreens.ToList().Find(scr => scr.DeviceName.Replace(@"\\.\", "") == Config.User.Screen).Bounds.Y == Screen.AllScreens.Min(scr => scr.Bounds.Y) ?
            //Screen.AllScreens.ToList().Find(scr => scr.DeviceName.Replace(@"\\.\", "") == Config.User.Screen) :
            //Screen.AllScreens.ToList().Find(scr => scr.Bounds.Y == Screen.AllScreens.Min(s => s.Bounds.Y));
            //}

            start_stop_y = new int[]
           {
                 Screen.PrimaryScreen.Bounds.Top +currentscreen.Bounds.Top - (Config.User.Window.Size.Height < this.MinimumSize.Height ? this.MinimumSize.Height : this.Height) + this.GripSize +_actionregionheight - this.BorderWidth,
                 Screen.PrimaryScreen.Bounds.Top +currentscreen.Bounds.Top - this.GripSize - (this.BorderWidth == 0 ? 1 : this.BorderWidth)
           };


            //start_stop_y = new int[]
            //{
            //    (int)Math.Floor((currentscreen.Bounds.Y) * (decimal)Win32API.GetScalingFactor(currentscreen)) - (Config.User.Window.Size.Height < this.MinimumSize.Height ? this.MinimumSize.Height : this.Height) + this.GripSize +_actionregionheight - this.BorderWidth,
            //    (int)Math.Floor((currentscreen.Bounds.Y) * (decimal)Win32API.GetScalingFactor(currentscreen)) - this.GripSize - (this.BorderWidth == 0 ? 1 : this.BorderWidth)
            //};

            // Eingeklappte Y-Koordinate
            XObjects.Delay.StartValue = start_stop_y[0];

            // Ausgeklappte Y-Koordinate
            XObjects.Delay.EndValue = start_stop_y[1];

            this.SetActionRegion();
            this.SetMaximumSize();
        }


        /// <summary>
        /// Anhand der Mindesthöhe der AppListPanels Steuerelemente wird mit dieser Methode die Mindesthöhe des GFATask berechnet
        /// </summary>
        public void SetMinimumSize()
        {
            this.MinimumSize = new Size(200, XObjects.AllAppListPanels.Where(panel => panel.Showing).Sum(panel => panel.IsLast ? panel.MinimumSize.Height : panel.Height) + this.Padding.Vertical + _actionregionheight);
            this.Size = Config.User.Window.Size.Height < this.MinimumSize.Height ? new Size(Config.User.Window.Size.Width, this.MinimumSize.Height + _actionregionheight) : Config.User.Window.Size;
        }


        /// <summary>
        /// Richtet sich nach der Auflösung des Bildschirms. Der GFATask kann bis maximal zur Taskleiste, abzüglich der GripSize vergrößert werden
        /// </summary>
        public void SetMaximumSize()
        {
            try
            {
                this.MaximumSize = new Size(currentscreen.WorkingArea.Width - (this.GripSize * 2), start_stop_y[1] + currentscreen.WorkingArea.Height - this.GripSize);
            }
            catch (Exception ex)
            {
                Log.EventLog.Write("Fehler beim skalieren der maximalen Größe", LogClassification.MediumError, ex);
            }
        }
            


        /// <summary>
        /// Darstellung des farbigen Elements, welches im unteren Bereich des GFATask dargestellt wird
        /// </summary>
        public void SetActionRegion()
        {
            // Erstellt das zu zeichnende farbige Element
            actionregion = new Rectangle(this.borderbounds.Left, this.borderbounds.Bottom - _actionregionheight + this.BorderWidth, this.borderbounds.Width + this.BorderWidth, _actionregionheight);
        }


        /// <summary>
        /// Führt das Ein- und Ausblenden des GFATask aus. In der Hook-Klasse wird die Methode angestoßen
        /// </summary>
        public void Delay_ValueChanged(object sender, DelayEventArgs e)
        {
            switch (e.Direction)
            {
                case Delay.Prevent.Increase:
                    this.Invoke(new MethodInvoker(delegate
                    {
                        if (this.DesktopLocation.Y < (int)XObjects.Delay.EndValue - XObjects.Delay.Steps)
                        {
                            this.DesktopLocation = new Point(this.DesktopLocation.X, this.DesktopLocation.Y + (int)Math.Ceiling(e.Step));
                            this.Opacity += opacitystep;
                        }
                        else
                        {
                            this.DesktopLocation = new Point(this.DesktopLocation.X, (int)XObjects.Delay.EndValue);
                            this.Opacity = Config.User.Window.Opacity;
                        }
                    }));
                    break;
                case Delay.Prevent.Decrease:
                    if (this.Created)
                    {
                        this.Invoke(new MethodInvoker(delegate
                        {
                            if (this.DesktopLocation.Y > (int)XObjects.Delay.StartValue + XObjects.Delay.Steps)
                            {
                                this.DesktopLocation = new Point(this.DesktopLocation.X, this.DesktopLocation.Y - (int)Math.Ceiling(e.Step));
                                this.Opacity -= opacitystep;
                            }
                            else
                            {
                                this.DesktopLocation = new Point(this.DesktopLocation.X, (int)XObjects.Delay.StartValue);
                                this.Opacity = .5;
                            }
                        }));
                    }
                    
                    break;
            }
            if (e.CurrentCount == XObjects.Delay.MaxCounts)
            {
                this.Resizable = true;
                this.DesktopLocation = new Point(this.DesktopLocation.X, (int)XObjects.Delay.EndValue);
            }
            else if (e.CurrentCount == 0)
            {
                this.Resizable = false;
                this.DesktopLocation = new Point(this.DesktopLocation.X, (int)XObjects.Delay.StartValue);
                this.Invalidate();
            }
        }

        
        /// <summary>
        /// Überprüft, ob für heute ein internationaler Welttag in den Neuigkeiten newsfeeds.json vorhanden ist
        /// </summary>
        /// <returns></returns>
        private Predicate<Models.NewsFeed> GetCurrentNewsFeed()
        {
            return new Predicate<Models.NewsFeed>(feed =>
            {
                if (feed.Begin.Day > DateTime.DaysInMonth(DateTime.Now.Year, feed.Begin.Month))
                {
                    feed.Begin.Day = DateTime.DaysInMonth(DateTime.Now.Year, feed.Begin.Month);
                    JSON.Save(JSONConfig.NewsFeeds);
                }
                if (feed.End.Day > DateTime.DaysInMonth(DateTime.Now.Year, feed.End.Month))
                {
                    feed.End.Day = DateTime.DaysInMonth(DateTime.Now.Year, feed.End.Month);
                    JSON.Save(JSONConfig.NewsFeeds);
                }
                return feed.Enable && Verifying.BetweenDate(new DateTime(DateTime.Now.Year, feed.Begin.Month, feed.Begin.Day), new DateTime(DateTime.Now.Year, feed.End.Month, feed.End.Day));
            });
        }


        /// <summary>
        /// Bei einem Drag'n Drop-Vorgang wird der GFA-Task sofort ausgeklappt
        /// </summary>
        /// <param name="drgevent"></param>
        protected override void OnDragEnter(DragEventArgs drgevent)
        {
            XObjects.Delay.Waiting = new Delay.DelayTime(0, Config.User.Delay.Hide);
            XObjects.Delay.Increase();
            base.OnDragEnter(drgevent);
            this.Invalidate();
        }


        protected override void OnSizeChanged(EventArgs e)
        {
            this.Update();
            if (this.Created)
                XObjects.AllAppListPanels.ForEach(applist => applist.FlowContent.Update());
            base.OnSizeChanged(e);
        }


        /// <summary>
        /// Beim Ändern der Schriftart, wird die neue minimale Höhe ermittelt
        /// </summary>
        /// <param name="e"></param>
        protected override void OnFontChanged(EventArgs e)
        {
            base.OnFontChanged(e);
            this.SetMinimumSize();
        }


        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            #region Startet die Ladeanimation
            try
            {
                // Animiert das Ladefenster zu Beginn der App. Schließt dieses, sobald in der AppListe all Apps geladen wurden
                XObjects.LoadingPanel.Location = new Point(this.Padding.Left, this.Padding.Top);
                XObjects.LoadingPanel.Size = new Size(this.Width - this.Padding.Horizontal, this.Height - this.Padding.Vertical - _actionregionheight);
                this.Controls.Add(XObjects.LoadingPanel);
            }
            catch (Exception ex)
            {
                Log.EventLog.Write("Kann Ladeanimation nicht starten", LogClassification.LowError, ex);
            }
            #endregion

            this.SetMinimumSize();
            this.SetStartValue();

            XObjects.FrontEndRefresh = new FrontEndRefresh<GFATaskStream>(Paths.FrontEndRefresh.FullName) { SelfUpdate = false };
            if(Config.Main.Administration.RemoteFrontEndUpdate)
                XObjects.FrontEndRefresh.Start();
            XObjects.FrontEndRefresh.Updated += FrontEndRefreshExecution.Updated;
            XObjects.FrontEndRefresh.Error += FrontEndRefreshExecution.OnError;
        }


        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            e.Graphics.FillPath(new SolidBrush(Config.Main.Colors.Window.Action), actionregion.ToRoundedRectangle(this.Radius, RectangleCorners.BottomLeft | RectangleCorners.BottomRight));

            //e.Graphics.FillRectangle(Brushes.AliceBlue, RegionBounds);
        }


        protected override void WndProc(ref Message m)
        {
            // Beginnt mit dem Vergrößerungsprozess des GFA-Task
            if (m.Msg == (int)WM.ENTERSIZEMOVE)
            {
                XObjects.AllAppListPanels.ForEach(applist => applist.DoubleBuffer(true));
                XObjects.Delay.Increase();

            }
            // Beendet den Vergrößerungsprozess des GFA-Task
            if (m.Msg == (int)WM.EXITSIZEMOVE)
            {
                XObjects.AllAppListPanels.ForEach(applist => applist.DoubleBuffer(false));
                this.DesktopLocation = new Point(Desktop.Anchor(this, currentscreen, DesktopAnchor.Top).X, start_stop_y[1]);
                //this.Invoke(new MethodInvoker(delegate { this.DesktopAnchor = new Point(Desktop.Anchor(this, DesktopAnchor.Top, -this.GripSize).X, start_stop_y[1]); }));
                Config.User.Window.Size = this.Size;
                JSON.Save(JSONConfig.User);

                Accessor.SetLastAppListPanel();
                this.SetMinimumSize();
                this.SetStartValue();
                this.Invalidate(true);
            }
            base.WndProc(ref m);
        }


        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing)
            {
                e.Cancel = true;
            }
            else
            {
                Environment.Exit(Environment.ExitCode);
            }
            base.OnFormClosing(e);
        }


        protected override CreateParams CreateParams
        {
            get
            {
                var cp = base.CreateParams;
                cp.ExStyle |= (int)WS_EX.WS_EX_TOOLWINDOW | (int)WS_EX.WS_EX_TOPMOST;
                return cp;
            }
        }
    }
}
