using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Collections;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.DirectoryServices.AccountManagement;
using System.Threading;
using static System.Windows.Forms.Control;
using System.Net.Mail;
using System.Net.Sockets;
using System.Security.Principal;
using System.Diagnostics;
using System.ComponentModel;

namespace GFATask
{
    /// <summary>
    /// Barrierefreier Zugriff zur Nutzung von Steuerelementen
    /// </summary>
    public static class Accessor
    {
        /// <summary>
        /// Überprüft, ob der Benutzer eine der berechtigten AD-Gruppen des entsprechenden AppListButtons enthält
        /// </summary>
        /// <param name="button">Überprüft den AppListButton auf Berechtigungen der AD-Gruppen</param>
        /// <returns></returns>
        public static bool IsMemberOfGroup(AppListButton button)
            => !Config.Main.UseActiveDirectoryGroups || (Config.Main.UseActiveDirectoryGroups && (button.ActiveDirectoryGroups == null ||
            (button.ActiveDirectoryGroups.Length > 0 && button.ActiveDirectoryGroups.All(group => group == string.Empty || group == " ")) ||
            button.ActiveDirectoryGroups.Intersect(AD.Groups.Select(group => group.Name)).Any()));


        /// <summary>
        /// Verschiebt beim Ändern der FormMain-Gegebenheiten die SearchBox immer an den entsprechenden Ort
        /// </summary>
        public static void MoveSearchBox()
        {
            AppListPanel panel = XObjects.AllAppListPanels.Find(applistpanel => applistpanel.AppType == AppType.Menu);
            //if(panel != null)
            //    XObjects.SearchBox.Location = new Point(panel.Padding.Left + panel.Location.X, Forms.Main.Padding.Top + Config.Main.Sizes.Window.Border);
        }


        /// <summary>
        /// Öffnet, oder erstellt eine Form aus der statischen Klasse Statics.Forms
        /// </summary>
        /// <param name="formname">Eigenschaft-Name der Form aus der statischen Klasse Statics.Forms</param>
        /// <param name="closeifopen">Ist das Form bereits geöffnet, wird dieses wieder geschlossen</param>
        /// <param name="owner">Gibt das Besitzer-Form des zu öffnenden Forms an</param>
        public static void OpenForm(string formname, Form owner = null, bool closeifopen = false)
        {
            try
            {
                //if (owner == null)
                //    owner = Forms.Main;
                if (typeof(Forms).GetProperty(formname).GetValue(typeof(Forms), null) != null)
                {
                    FormEx form = typeof(Forms).GetProperty(formname).GetValue(typeof(Forms), null) as FormEx;
                    if (form != null)
                    {
                        if (!closeifopen)
                        {
                            if (!form.Visible)
                            {
                                if(owner == null)
                                    form.Show();
                                else
                                    form.Show(owner);
                            }
                        }
                        else
                        {
                            if (!form.Visible)
                            {
                                form.Show(owner);
                            }
                            else if (form.Visible)
                            {
                                form.Visible = false;
                            }
                        }
                    }
                    else
                    {
                        if (form.GetType() == typeof(FormGroups))
                        {
                            form = new FormGroups();
                        }
                        if (form.GetType() == typeof(FormSettings))
                        {
                            form = new FormSettings();
                        }
                        if (form.GetType() == typeof(FormAdmin))
                        {
                            form = new FormAdmin();
                        }
                        form.Show(owner);
                    }
                    form.TopMost = true;
                    form.Focus();
                    form.BringToFront();
                    //form.TopMost = false;
                }
            }
            catch (Exception ex)
            {
                Log.EventLog.Write($"Kann Form \"{formname}\" nicht öffnen", LogClassification.Warning, ex);
            }
        }


        /// <summary>
        /// Liest, eine AppListe aus der statischen Klasse Statics.AppLists aus
        /// </summary>
        /// <param name="apptype">Der Apptyp der AppListe</param>
        /// <returns></returns>
        public static Models.AppList<Models.App> GetAppList(string apptype)
        {
            try
            {
                return (Models.AppList<Models.App>)typeof(AppLists).GetProperty(apptype).GetValue(typeof(Models.AppList<Models.App>));
            }
            catch (Exception ex)
            {
                Log.EventLog.Write($"AppList AppType.{apptype}", LogClassification.Crash, ex);
                return null;
            }
        }

        /// <summary>
        /// Liest, eine AppListe aus der statischen Klasse Statics.AppLists aus
        /// </summary>
        /// <param name="apptype">Der Apptyp der AppListe</param>
        /// <returns></returns>
        public static Models.AppList<Models.App> GetAppList(AppType apptype)
        {
            try
            {
                return (Models.AppList<Models.App>)typeof(AppLists).GetProperty(apptype.ToString()).GetValue(typeof(Models.AppList<Models.App>));
            }
            catch (Exception ex)
            {
                Log.EventLog.Write($"AppList AppType.{apptype} nicht gefunden", LogClassification.Crash, ex);
                return null;
            }
        }

        /// <summary>
        /// Liest die Eigenschaften einer bestimmten Liste aus der JSON User-Config Datei aus
        /// </summary>
        /// <param name="apptype">Der Listenname um die Eigenschaften abzuändern, oder zu erhalten</param>
        /// <returns></returns>
        public static Models.Config.User.ListProperties GetListProperties(AppType apptype)
        {
            try
            {
                return (Models.Config.User.ListProperties)Config.User.Lists.GetType().GetProperty(apptype.ToString()).GetValue(Config.User.Lists);
            }
            catch (Exception ex)
            {
                Log.EventLog.Write($"ListProperties für AppType.{apptype} nicht gefunden", LogClassification.Crash, ex);
                return null;
            }
        }

        /// <summary>
        /// Gibt das gewünschte AppListPanel anhand des Apptypen aus
        /// </summary>
        /// <param name="apptype">Der Apptyp des AppListPanels</param>
        /// <returns></returns>
        public static AppListPanel GetAppListPanel(string apptype)
        {
            try
            {
                return GetAppListPanel((AppType)Enum.Parse(typeof(AppType), apptype, true));
            }
            catch (Exception ex)
            {
                Log.EventLog.Write($"AppListPanel AppType.{apptype} nicht gefunden", LogClassification.Crash, ex);
                return null;
            }
        }

        /// <summary>
        /// Gibt das gewünschte AppListPanel anhand des Apptypen aus
        /// </summary>
        /// <param name="apptype">Der Apptyp des AppListPanels</param>
        /// <returns></returns>
        public static AppListPanel GetAppListPanel(AppType apptype)
        {
            try
            {
                return XObjects.AllAppListPanels.Find(panel => panel.AppType == apptype);
            }
            catch (Exception ex)
            {
                Log.EventLog.Write($"AppListPanel AppType.{apptype} nicht gefunden", LogClassification.Crash, ex);
                return null;
            }
        }

        /// <summary>
        /// Liest den Häufigkeitsfaktor aus der JSON-Prevalence Datei aus und weißt diese, dem AppButton zu
        /// </summary>
        /// <param name="id">Die ID des AppButtons</param>
        /// <returns></returns>
        public static Prevalencia GetPrevalencia(AppType apptype, int id)
        {
            List<Models.Prevalence.AppPrevalenceProperties> prevalenceapps = (List<Models.Prevalence.AppPrevalenceProperties>)Config.Prevalence.GetType().GetProperty(apptype.ToString()).GetValue(Config.Prevalence);
            
            if (!prevalenceapps.Select(prev => prev.ID).Contains(id))
            {
                prevalenceapps.Add(new Models.Prevalence.AppPrevalenceProperties() { ID = id, ClickCounts = 0 });
                JSON.Save(JSONConfig.Prevalence);
            }
            return new Prevalencia(id, apptype, prevalenceapps.Find(prev => prev.ID == id).ClickCounts);
        }

        /// <summary>
        /// Liest den AppCounter aus der JSON-AppClickCounter Datei aus
        /// </summary>
        /// <param name="apptype"></param>
        /// <param name="id"></param>
        public static Models.ClickCounter.AppCounter GetAppCounter(AppType apptype, int id)
        {
            return ((List<Models.ClickCounter.AppCounter>)Config.AppClickCounter.GetType().GetProperty(apptype.ToString()).GetValue(Config.AppClickCounter)).Find(clickcounter => clickcounter.ID == id);
                
        }

        /// <summary>
        /// Liest den AppCounter aus der JSON-AppClickCounter-Datei aus und wandelt diese in einen ClickCounter um
        /// </summary>
        /// <param name="id">Die ID des AppButtons</param>
        /// <returns></returns>
        public static void SetAppCounter(AppType apptype, int id)
        {
            Models.App app = GetAppList(apptype).Apps.Find(applistapp => applistapp.ID == id);
            List<Models.ClickCounter.AppCounter> clickcountereapps = (List<Models.ClickCounter.AppCounter>)Config.AppClickCounter.GetType().GetProperty(apptype.ToString()).GetValue(Config.AppClickCounter);
            if (!clickcountereapps.Select(prev => prev.ID).Contains(app.ID))
                clickcountereapps.Add(new Models.ClickCounter.AppCounter() { ID = app.ID, Name = app.Name, Counts = 0, LastClicked = DateTime.Now, FirstClicked = DateTime.Now  });
            var appcounter = clickcountereapps.Find(prev => prev.ID == app.ID);
            var clickcounter = new ClickCounter(app.ID, apptype, app.Name, appcounter.Counts, appcounter.FirstClicked);
            clickcounter.CountUp();

            Forms.Administration.UcAdminAppClickCounter.RefreshList(clickcounter);
            XObjects.FrontEndRefresh.Update(new GFATaskStream() { PipeType = NetPipeType.AppCounter_CountUp, ClickCounter = clickcounter });
        }

        /// <summary>
        /// Liest die Liste der JSON Prevalencia Datei anhand des Apptypen aus
        /// </summary>
        /// <param name="apptype"></param>
        /// <returns></returns>
        public static List<Models.Prevalence.AppPrevalenceProperties> GetPrevalenciaFileList(AppType apptype)
        {
            return (List<Models.Prevalence.AppPrevalenceProperties>)Config.Prevalence.GetType().GetProperty(apptype.ToString()).GetValue(Config.Prevalence);
        }

        /// <summary>
        /// Findet und definiert das AppListPanel als letztes Panel im Forms.Main
        /// </summary>
        public static void SetLastAppListPanel()
        {
            try
            {
                foreach (AppListPanel panel in XObjects.AllAppListPanels)
                {
                    if(Forms.Main.Controls.OfType<AppListPanel>().Count(alp => alp.Showing) > 0)
                        panel.IsLast = Forms.Main.Controls.IndexOf(panel) == Forms.Main.Controls.OfType<AppListPanel>().Where(alp => alp.Showing).Min(alp => Forms.Main.Controls.IndexOf(alp));
                }
            }
            catch (Exception ex)
            {
                Log.EventLog.Write("Fehler in SetLastAppListPanel", LogClassification.Crash, ex);
            }
        }
    }


    /// <summary>
    /// Barrierefreier Zugriff auf brauchbare Funktionen für das Active Directory
    /// </summary>
    public class AD
    {
        /// <summary>
        /// Gibt aus, ob das Suchen der Active Directory Gruppen beendet ist (synchrone Eigenschaft)
        /// </summary>
        public static bool GroupSearchingFinish { get; private set; } = false;

        /// <summary>
        /// Eine Auflistung aller Gruppenmitgliedschaften
        /// </summary>
        public static Collection<GroupPrincipal> Groups { get; } = new Collection<GroupPrincipal>();

        /// <summary>
        /// Führt eine Suche nach den Active Directory Gruppen aus, in denen der Benutzer Mitglied ist
        /// </summary>
        public static void GetGroups()
        {
            GroupSearchingFinish = false;
            Groups.Clear();
            try
            {
                var groups = System.DirectoryServices.ActiveDirectory.GetGroups(Environment.UserName, true, new PrincipalContext(ContextType.Domain, Config.Main.DomainName.ToLower()));
                foreach (var group in groups.OrderBy(group => group.Name))
                {
                    Groups.Add(group);
                    Forms.Groups.AddADGroup(group);
                    Thread.Sleep(1);
                }
                GroupSearchingFinish = true;
            }
            catch (Exception)
            {
                GroupSearchingFinish = true;
                Forms.Groups.Loading(true);
                return;
            }
        }
    }


    /// <summary>
    /// Barrierefreier Zugriff auf die Applisten
    /// </summary>
    public class AppLists
    {
        /// <summary>
        /// Auflistung aller Menü-Apps
        /// </summary>
        public static Models.AppList<Models.App> Menu { get; set; } = JSON.Read<Models.AppList<Models.App>>(Paths.Apps.Directory + @"\menu.json");

        /// <summary>
        /// Auflistung aller Administrations-Apps
        /// </summary>
        public static Models.AppList<Models.App> Admin { get; set; } = JSON.Read<Models.AppList<Models.App>>(Paths.Apps.Directory + @"\admin.json");

        /// <summary>
        /// Auflistung aller Benutzer-Apps
        /// </summary>
        public static Models.AppList<Models.App> User { get; set; } = JSON.Read<Models.AppList<Models.App>>(Paths.Apps.Directory + @"\user.json");

        /// <summary>
        /// Auflistung aller Favoriten-Apps
        /// </summary>
        public static Models.AppList<Models.App> Favorites { get; set; } = JSON.Read<Models.AppList<Models.App>>(Paths.Favorites.Apps.Directory + @"\favorites.json");

        /// <summary>
        /// Auflistung aller Citrix-Apps. Diese wird nicht in der gewöhnlichen [apps].json Datei gespeichert, sondern zur Laufzeit aus dem Citrix-Speicher ausgelesen
        /// </summary>
        public static Models.AppList<Models.App> Citrix { get; set; } = new Models.AppList<Models.App>() { Type = AppType.Citrix, Apps = new List<Models.App>() };
    }


    /// <summary>
    /// Barrierefreier Zugriff auf Umwandlungen von bestimmten Objekten in andere Typen
    /// </summary>
    public static class Cast
    {
        /// <summary>
        /// Wandelt einen App-Namen in einen Button-Namen um
        /// </summary>
        /// <param name="apptype">Der AppTyp</param>
        /// <param name="app">Die App</param>
        /// <returns></returns>
        public static string AppButtonName(AppType apptype, Models.App app)
        {
            return app.ID + "_" + apptype.ToString() + "_" + app.Name;
        }


        /// <summary>
        /// Wandelt einen App-Namen in einen Button-Namen um
        /// </summary>
        /// <param name="apptype">Der AppTyp</param>
        /// <param name="app">Die App</param>
        /// <returns></returns>
        public static string AppButtonName(string apptype, Models.App app)
        {
            return AppButtonName((AppType)Enum.Parse(typeof(AppType), apptype, true), app);
        }


        /// <summary>
        /// Wandelt einen GroupButton-Text in einen GroupButton-Namen um
        /// </summary>
        /// <param name="apptype">Der AppTyp des GroupButtons</param>
        /// <param name="grouptext">Der Dargestellste Text des GroupButtons</param>
        /// <returns></returns>
        public static string GroupButtonName(AppType apptype, string grouptext)
        {
            return grouptext + "_" + apptype.ToString();
        }


        /// <summary>
        /// Wandelt einen GroupButton-Text in einen GroupButton-Namen um
        /// </summary>
        /// <param name="apptype">Der AppTyp des GroupButtons</param>
        /// <param name="grouptext">Der Dargestellste Text des GroupButtons</param>
        /// <returns></returns>
        public static string GroupButtonName(string apptype, string grouptext)
        {
            return GroupButtonName((AppType)Enum.Parse(typeof(AppType), apptype, true), grouptext);
        }


        /// <summary>
        /// Wandelt das DateTime-Objekt in eine Zeichenkette mit europäische Zeitangabe um
        /// </summary>
        /// <param name="datetime"></param>
        /// <returns></returns>
        public static string ToEuropeDateCulture(this DateTime datetime)
        {
            return datetime.ToString("yyyy-MM-dd HH:mm:ss");
        }

        /// <summary>
        /// Wandelt einen AppCounter aus der JSON-Datei in ein ClickCounter-Objekt um
        /// </summary>
        /// <param name="appcounter"></param>
        /// <param name="apptype"></param>
        /// <returns></returns>
        public static ClickCounter ToClickCounter(this Models.ClickCounter.AppCounter appcounter, AppType apptype)
        {
            return new ClickCounter(appcounter.ID, apptype, appcounter.Name, appcounter.Counts, appcounter.FirstClicked) { LastClicked = appcounter.LastClicked };
        }


        /// <summary>
        /// Wandelt eine Models.App App in einen AppButton um
        /// </summary>
        /// <param name="app">Models.App App</param>
        /// <param name="imagepath">Pfad zum Symbol</param>
        /// <param name="margin">Abstand des AppButtons</param>
        /// <returns></returns>
        public static AppButton ToAppButton(this Models.App app, string imagepath, Padding margin)
        {
            AppButton button = new AppButton();
            
            button.ActualWidth = Config.User.Apps.Size.Width;
            button.ImageAlign = button.ImageOnly ? AnchorStyles.None : AnchorStyles.Left;

            button.Text = app.Name;

            button.Radius = Config.User.Apps.Radius.Button;
            button.Margin = margin;
            button.CreationTime = app.Created;
            button.LastModified = app.LastModified;
            button.Description = app.Description;

            if (File.Exists(imagepath))
            {
                using (FileStream fs = new FileStream(imagepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
                {
                    //int icosize = Config.User.Apps.Size.Height - button.ImageMargin - button.ImagePadding;
                    if (fs.Name.EndsWith("ico"))
                    {
                        button.Image = Bitmap.FromHicon( Icon.ExtractAssociatedIcon(fs.Name).Handle);
                    }
                    else
                    {
                        button.Image = Image.FromStream(fs);
                    }
                }
            }
            else
            {
                button.Image = new Bitmap(1, 1);
            }

            button.TextAlign = ContentAlignment.MiddleLeft;
            button.TextBoxAlign = AnchorStyles.Right;
            button.Tag = "group:" + app.Group == string.Empty ? "None" : app.Group + "|activedirectory_groups:" + (app.ActiveDirectoryGroups != null && app.ActiveDirectoryGroups.Length > 0 ? string.Join(",", app.ActiveDirectoryGroups) : "");
            button.ImageOnly = Config.User.Apps.ImageOnly;

            return button;
        }


        /// <summary>
        /// Wandelt eine Auflistung von Models.App Apps in einen GroupButton um
        /// </summary>
        /// <param name="apps">Auflistung von Models.App Apps</param>
        /// <param name="apptype">Zu welchem AppListPanel soll der GroupButton hinzugefügt werden</param>
        /// <param name="margin">bstand des GroupButtons</param>
        /// <returns></returns>
        public static GroupButton ToGroupButton(this Models.App[] apps, AppType apptype, Padding margin)
        {
            try
            {
                GroupButton groupbutton = new GroupButton();
                apps.ToList().ForEach(app =>
                {
                    AppButton appbutton = app.ToAppButton(IconPath(apptype, app.Icon), margin);
                    appbutton.Name = app.ID + "_" + apptype.ToString() + "_" + app.Name;
                    appbutton.GroupName = app.Group;
                    appbutton.ID = app.ID;
                    appbutton.Description = app.Description;
                    appbutton.Visible = Cast.AppVisibility(app);
                    appbutton.ActiveDirectoryGroups = app.ActiveDirectoryGroups;
                    appbutton.Prevalence = Accessor.GetPrevalencia(apptype, app.ID);
                    appbutton.WordWrap = false;
                    appbutton.Size = Config.User.Apps.Size;
                    appbutton.SetDefaultDesign();
                    appbutton.AppType = apptype;
                    appbutton.Execute = app.Execute;
                    groupbutton.ContainedApps.Add(app);
                    groupbutton.ContainedAppButtons.Add(appbutton);
                });
                groupbutton.ActualWidth = Config.User.Apps.Size.Width;
                groupbutton.Name = apps[0].Group + "_" + apptype.ToString();
                groupbutton.Text = apps[0].Group;
                groupbutton.Radius = Config.User.Apps.Radius.Button;
                AppButton prevalencedbutton = groupbutton.ContainedAppButtons.ToArray().ToList().Find(button => button.Prevalence.CountClicks == groupbutton.ContainedAppButtons.ToArray().ToList().Max(btn => btn.Prevalence.CountClicks));
                groupbutton.Prevalence = Accessor.GetPrevalencia(apptype, prevalencedbutton.ID);
                groupbutton.AppType = apptype;
                groupbutton.Margin = margin;

                groupbutton.ImageOnly = Config.User.Apps.ImageOnly;
                groupbutton.ImageAlign = groupbutton.ImageOnly ? AnchorStyles.None : AnchorStyles.Left;

                //groupbutton.ImageAlign = AnchorStyles.Left;
                groupbutton.TextAlign = ContentAlignment.MiddleLeft;
                groupbutton.Size = Config.User.Apps.Size;
                groupbutton.SetDefaultDesign();
                groupbutton.TextBoxAlign = AnchorStyles.Right;
                groupbutton.Tag = "group:" + apps[0].Group == string.Empty ? "None" : apps[0].Group + "|activedirectory_groups:" + (apps[0].ActiveDirectoryGroups != null && apps[0].ActiveDirectoryGroups.Length > 0 ? string.Join(",", apps[0].ActiveDirectoryGroups) : "");
                groupbutton.ContainedApps = apps.ToList();
                groupbutton.Visible = apps.Count(app => Cast.AppVisibility(app)) > 1;
                return groupbutton;
            }
            catch (Exception ex)
            {
                Log.EventLog.Write("Gruppe nicht erstellt", LogClassification.CriticalError, ex);
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public static AppLnk ToAppLink(this string command)
        {
            string[] applnk_array = command.Replace("APPLNK:", "").Split('|');
            AppType applnk_type = (AppType)int.Parse(applnk_array[0]);
            int applnk_id = int.Parse(applnk_array[1]);
            return new AppLnk() { AppType = applnk_type, ID = applnk_id };
        }

        /// <summary>
        /// Überprüft, ob die App in der Liste angezeigt werden kann
        /// </summary>
        /// <returns></returns>
        public static bool AppVisibility(Models.App app)
        {
            return !app.Prototype && 
                (Config.Main.UseActiveDirectoryGroups && 
                (app.ActiveDirectoryGroups == null || app.ActiveDirectoryGroups.Contains("") || app.ActiveDirectoryGroups.Length == 0 || app.ActiveDirectoryGroups.Intersect(AD.Groups.Select(grp => grp.Name).ToArray()).Any()) ||
                !Config.Main.UseActiveDirectoryGroups);
        }


        /// <summary>
        /// Wandelt eine IEnumerable Auflistung von Models.App Apps in einen GroupButton um
        /// </summary>
        /// <param name="apps">Auflistung von Models.App Apps</param>
        /// <param name="apptype">Zu welchem AppListPanel soll der GroupButton hinzugefügt werden</param>
        /// <param name="margin">bstand des GroupButtons</param>
        /// <returns></returns>
        public static GroupButton ToGroupButton(this IEnumerable<Models.App> apps, AppType apptype, Padding margin)
        {
            return ToGroupButton(apps.ToArray(), apptype, margin);
        }


        /// <summary>
        /// Fügt den Pfad der Symbole anhand des Apptypen und den Namen der Symboldatei zusammen
        /// </summary>
        /// <param name="apptype">Apptyp</param>
        /// <param name="iconname">Name der Symboldatei</param>
        /// <returns></returns>
        public static string IconPath(AppType apptype, string iconname)
        {
            return (apptype == AppType.Citrix ? Paths.Citrix.Icons.Directory :
                            apptype == AppType.Favorites ? Paths.Favorites.Icons.Directory :
                            Paths.Icons.Directory) + iconname;
        }
    }


    /// <summary>
    /// Barrierefreier Zugriff auf Vergleichsklassen zum sortieren von Auflistungen
    /// </summary>
    public class Comparer
    {
        /// <summary>
        /// Sortiert den AppButton oder GroupButton nach Beliebtheit, oder Namen
        /// </summary>
        /// <param name="controls"></param>
        /// <param name="item"></param>
        /// <param name="byprevalence"></param>
        /// <returns></returns>
        public static int SortButton(ControlCollection controls, AppListButton button, bool byprevalence)
        {
            if (byprevalence)
            {
                return controls.OfType<AppListButton>().OrderByDescending(btn => btn.Prevalence.CountClicks).ThenBy(btn => btn.Text).ToList().IndexOf(button);
            }
            else
            {
                return controls.OfType<AppListButton>().OrderByDescending(btn => button.Text).ToList().IndexOf(button);
            }
        }


        /// <summary>
        /// Sortiert alle AppButtons oder GroupButtons nach Beliebtheit, oder Namen
        /// </summary>
        /// <param name="controls"></param>
        /// <param name="item"></param>
        /// <param name="byprevalence"></param>
        /// <returns></returns>
        public static void SortAllButtons(ControlCollection controls, bool byprevalence)
        {
            var collection = byprevalence ?
                    controls.OfType<AnimationButton>().OrderByDescending(button => ((AppListButton)button).Prevalence.CountClicks) :
                    controls.OfType<AnimationButton>().OrderBy(button => button.Text);
            foreach (AnimationButton button in collection)
            {
                controls.SetChildIndex(button, collection.ToList().IndexOf(button));
            }
            //foreach (AnimationButton button in controls)
            //{
            //    controls.SetChildIndex(button, collection.ToList().IndexOf(button));
            //}
        }


        /// <summary>
        /// Vergleicht die AppButton Steuerelemente anhand ihres Namens und sortiert diese
        /// </summary>
        public class ButtonCompareByName : IComparer<AppListButton>
        {
            /// <summary>
            /// Vergleicht die Liste und sortiert die AppButtons nach dem Text
            /// </summary>
            /// <param name="x"></param>
            /// <param name="y"></param>
            /// <returns></returns>
            public int Compare(AppListButton x, AppListButton y)
            {
                return x.Text.CompareTo(y.Text);
            }
        }

        /// <summary>
        /// Vergleicht die AppButton Steuerelemente anhand ihrer Beliebtheit und sortiert diese
        /// </summary>
        public class ButtonCompareByPrevalence : IComparer<AppListButton>
        {
            /// <summary>
            /// Vergleicht die Liste und sortiert die AppButtons nach Beliebtheit
            /// </summary>
            /// <param name="x"></param>
            /// <param name="y"></param>
            /// <returns></returns>
            public int Compare(AppListButton x, AppListButton y)
            {
                return y.Prevalence.CountClicks.CompareTo(x.Prevalence.CountClicks);
            }
        }
    }


    /// <summary>
    /// Barrierefreier Zugriff auf die Konfigurationsdateien
    /// </summary>
    public class Config
    {
        /// <summary>
        /// JSON basierte allgemeine Konfigurationsdatei
        /// </summary>
        public static Models.Config.Main Main { get; set; } = JSON.Read<Models.Config.Main>(Paths.MainConfig.FullName);

        /// <summary>
        /// JSON basierte benutzerdefinierte Konfigurationsdatei
        /// </summary>
        public static Models.Config.User User { get; set; } = JSON.Read<Models.Config.User>(Paths.UserConfig.FullName);

        /// <summary>
        /// JSON basierte Beliebtheitsdatei für die Appsortierung
        /// </summary>
        public static Models.Prevalence Prevalence { get; set; } = JSON.Read<Models.Prevalence>(Paths.Prevalence.FullName);

        /// <summary>
        /// JSON basierte internationale Welttagedatei
        /// </summary>
        public static List<Models.NewsFeed> NewsFeeds { get; set; } = JSON.Read<List<Models.NewsFeed>>(Paths.NewsFeeds.Values.FullName, true);

        /// <summary>
        /// JSON basierte Häufigkeit von angeklickten Apps
        /// </summary>
        public static Models.ClickCounter AppClickCounter { get; set; } = JSON.Read<Models.ClickCounter>(Paths.AppClickCounter.FullName);
    }


    /// <summary>
    /// Barrierefreier Zugriff zum generieren und verändern von Steuerelemente
    /// </summary>
    public static class Creator
    {
        /// <summary>
        /// Fügt der AppListPanelCreationTasks-Liste den entsprechendne AppListPanelCreator hinzu, um die App- und GroupButtons zu erstellen
        /// </summary>
        /// <param name="applistpanel">Das AppListPanel</param>
        /// <param name="applist">Die Apps aus der die AppButtons generiert und in das AppListPanel eingelesen werden</param>
        public static void AppListPanel(AppListPanel applistpanel, Models.AppList<Models.App> applist)
        {
            var props = Accessor.GetListProperties(applist.Type);
            applistpanel.Showing = props.Show;
            applistpanel.Grouping = props.Grouping;
            if (applistpanel.IsLast)
                Accessor.SetLastAppListPanel();
            else
                applistpanel.Height = props.Height;
            applistpanel.CreateButtons(applist);
        }

        /// <summary>
        /// Erstellt eine neue App und fügt diese in der Admin-AppListe als ListViewItem, dem AppListPanel als AppButton und der AppList als Models.App hinzu
        /// </summary>
        public static void AddApp(AppType apptype, Models.App app)
        {
            app.LastModified = DateTime.Now;
            app.Created = DateTime.Now;
            Accessor.GetAppListPanel(apptype).AddAppButton(app);
            if (apptype == AppType.Admin || apptype == AppType.Menu || apptype == AppType.User)
            {
                Forms.Administration.UcAdminApps.AddAppToList(apptype, app);
            }
            Accessor.GetAppList(apptype).Apps.Add(app);
            Accessor.GetPrevalenciaFileList(apptype).Add(new Models.Prevalence.AppPrevalenceProperties() { ID = app.ID, ClickCounts = 0 });
            JSON.Save((JSONApp)Enum.Parse(typeof(JSONApp), apptype.ToString(), true));
            JSON.Save(JSONConfig.Prevalence);

            if (apptype != AppType.Favorites)
                XObjects.FrontEndRefresh.Update(new GFATaskStream() { PipeType = NetPipeType.Create, App = app, AppType = apptype });
        }

        /// <summary>
        /// Erstellt eine neue App und fügt diese in der Admin-AppListe als ListViewItem, dem AppListPanel als AppButton und der AppList als Models.App hinzu
        /// </summary>
        public static void AddApp(string apptype, Models.App app)
        {
            AddApp((AppType)Enum.Parse(typeof(AppType), apptype, true), app);
        }

        /// <summary>
        /// Wandelt einen Apptypen und eine App ID in einen APPLINK-Befehl für eine Favoriten-App um
        /// </summary>
        public static string AppLinkCommand(AppType apptype, int id)
        {
            return $"APPLNK:{(int)apptype}|{id}";
        }

        /// <summary>
        /// Entfernt eine App aus der Admin-AppListe als ListViewItem, dem AppListPanel als AppButton und der AppList als Models.App
        /// </summary>
        public static void RemoveApp(AppType apptype, Models.App app)
        {
            Accessor.GetAppListPanel(apptype).RemoveButton(app);
            if (apptype == AppType.Admin || apptype == AppType.Menu || apptype == AppType.User)
            {
                Forms.Administration.UcAdminApps.RemoveAppFromList(apptype, app);
            }
            var applist = Accessor.GetAppList(apptype);
            applist.Apps.Remove(app);
            Creator.RemoveIcon(apptype, app.Icon);

            Accessor.GetPrevalenciaFileList(apptype).RemoveAll(item => item.ID == app.ID);
            JSON.Save((JSONApp)Enum.Parse(typeof(JSONApp), apptype.ToString(), true));
            JSON.Save(JSONConfig.Prevalence);

            if (apptype != AppType.Favorites)
                XObjects.FrontEndRefresh.Update(new GFATaskStream() { PipeType = NetPipeType.Delete, App = app, AppType = apptype });
        }

        /// <summary>
        /// Entfernt die Symbole nur dann, wenn keine weitere App darauf zugreift (aufgeteilt auf Favoriten und alle anderen Apps [ausgenommen Citrix-Apps])
        /// </summary>
        public static void RemoveIcon(AppType apptype, string icon)
        {
            var applist = Accessor.GetAppList(apptype);
            if (apptype == AppType.Favorites)
            {
                if (!applist.Apps.Any(_app => _app.Icon == icon))
                {
                    try
                    {
                        if (File.Exists(Cast.IconPath(apptype, icon)))
                            File.Delete(Cast.IconPath(apptype, icon));
                    }
                    catch (Exception ex)
                    {
                        Log.EventLog.Write("Symbol in Favoriten nicht löschbar", LogClassification.LowError, ex);
                    }
                }
            }
            else if (apptype == AppType.Menu || apptype == AppType.User || apptype == AppType.Admin)
            {
                if (!AppLists.Admin.Apps.Union(AppLists.Menu.Apps.Union(AppLists.User.Apps)).Any(_app => _app.Icon == icon))
                {
                    if (File.Exists(Cast.IconPath(apptype, icon)))
                        File.Delete(Cast.IconPath(apptype, icon));
                }
            }
        }

        /// <summary>
        /// Entfernt eine App aus der Admin-AppListe als ListViewItem, dem AppListPanel als AppButton und der AppList als Models.App
        /// </summary>
        public static void RemoveApp(string apptype, Models.App app)
        {
            RemoveApp((AppType)Enum.Parse(typeof(AppType), apptype, true), app);
        }

        /// <summary>
        /// Ersetzt eine App in der Admin-AppListe als ListViewItem, dem AppListPanel als AppButton und der AppList als Models.App
        /// </summary>
        public static void ReplaceApp(AppType apptype, Models.App app)
        {
            app.LastModified = DateTime.Now;
                        
            Accessor.GetAppListPanel(apptype).ReplaceButton(app);
            if (apptype == AppType.Admin || apptype == AppType.Menu || apptype == AppType.User)
            {
                Forms.Administration.UcAdminApps.ReplaceAppInList(apptype, app);
            }
            var applist = Accessor.GetAppList(apptype).Apps;

            if(apptype != AppType.Favorites)
            {
                XObjects.FrontEndRefresh.Update(new GFATaskStream() { PipeType = NetPipeType.Edit, App = app, AppType = apptype });
            }
            string iconname = applist[applist.FindIndex(listapp => listapp.ID == app.ID)].Icon;
            applist[applist.FindIndex(listapp => listapp.ID == app.ID)] = app;
            Accessor.GetPrevalenciaFileList(apptype).RemoveAll(prevalencia => prevalencia.ID == app.ID);
            Accessor.GetPrevalenciaFileList(apptype).Add(new Models.Prevalence.AppPrevalenceProperties() { ID = app.ID, ClickCounts = 0 });
            JSON.Save((JSONApp)Enum.Parse(typeof(JSONApp), apptype.ToString(), true));
            JSON.Save(JSONConfig.Prevalence);
            Creator.RemoveIcon(apptype, iconname);
        }

        /// <summary>
        /// Ersetzt eine App in der Admin-AppListe als ListViewItem, dem AppListPanel als AppButton und der AppList als Models.App
        /// </summary>
        public static void ReplaceApp(string apptype, Models.App app)
        {
            ReplaceApp((AppType)Enum.Parse(typeof(AppType), apptype, true), app);
        }

        /// <summary>
        /// Liest eine Datei aus und erstellt sowohl Quell- als auch Ziel-Filestreams zum Kopieren, Freigeben und gemeinsamen Nutzen der Dateien
        /// </summary>
        /// <param name="source">Pfad zur Quelldatei</param>
        /// <param name="destination">Angabe des Zielpfades, ink. Dateiname</param>
        /// <param name="useDestinationStream">Führt Code nach dem Erstellen der Zieldatei aus</param>
        public static void StreamCopy(string source, string destination, Action<FileStream> useDestinationStream)
        {
            using (FileStream fssource = new FileStream(source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
            {
                using (FileStream fsdestination = new FileStream(destination, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete))
                {
                    fssource.CopyTo(fsdestination);
                    useDestinationStream?.Invoke(fsdestination);
                }
            }
        }
    }


    /// <summary>
    /// Barrierefreier Zugriff auf Designer-Elemente
    /// </summary>
    public static class Designer
    {
        /// <summary>
        /// Zeichnet ein Label als Überschrift
        /// </summary>
        public static void DrawHeaderLabel(object sender, PaintEventArgs e)
        {
            var _this = sender as Control;
            Font headerfont = new Font(_this.Font.FontFamily, _this.Font.Size + 3, FontStyle.Bold);
            Size textsize = new Size((int)Math.Floor(e.Graphics.MeasureString(_this.Text, headerfont).Width), e.ClipRectangle.Bottom - headerfont.Height);
            int textpadding = 5;
            int center = (_this.Width / 2) - (textsize.Width / 2);
            e.Graphics.Clear(_this.BackColor);
            e.Graphics.DrawLine(new Pen(_this.ForeColor), new Point(0, textsize.Height + (int)(textsize.Height / 2)), new Point(center - textpadding, textsize.Height + (int)(textsize.Height / 2)));
            e.Graphics.DrawLine(new Pen(_this.ForeColor), new Point(center + textsize.Width + textpadding, textsize.Height + (int)(textsize.Height / 2)), new Point(e.ClipRectangle.Width, textsize.Height + (int)(textsize.Height / 2)));
            e.Graphics.DrawString(_this.Text, headerfont, new SolidBrush(_this.ForeColor), new Point(center, textsize.Height));
        }


        /// <summary>
        /// Einheitliches Design für die AppListPanels
        /// </summary>
        public static void SetDefaultDesign(this AppListPanel panel)
        {
            panel.Border = Config.Main.Sizes.List.Border;
            panel.Font = new Font(Config.Main.FontFamily, Config.User.Window.FontSize);
            if (Config.User.DarkMode)
                panel.BorderColor = Color.White;
            else
                panel.BorderColor = Config.Main.Colors.List.Border;
        }


        /// <summary>
        /// Einheitliches Design für die Comboboxen
        /// </summary>
        public static void SetDefaultDesign(this ComboBox cb)
        {
            cb.FlatStyle = FlatStyle.Flat;
            cb.Font = new Font(Config.Main.FontFamily, Config.User.Window.FontSize);
            
            if (Config.User.DarkMode)
                cb.BackColor = DarkModeColors.BackColor.AddBirghtness(Coloring.GetReadableForeColor(Config.Main.Colors.Window.BackColor) == Color.White ? 200 : -30);
            else
                cb.BackColor = Config.Main.Colors.Window.BackColor.AddBirghtness(Coloring.GetReadableForeColor(Config.Main.Colors.Window.BackColor) == Color.White ? 200 : -30);
            
            cb.ForeColor = Coloring.GetReadableForeColor(cb.BackColor);
        }


        /// <summary>
        /// Einheitliches Design für jedes Kontextmenü im GFATask
        /// </summary>
        public static void SetDefaultDesign(this ContextMenuStrip cms)
        {
            cms.RenderMode = ToolStripRenderMode.Professional;
            //cms.RenderMode = ToolStripRenderMode.ManagerRenderMode;

            if (Config.User.DarkMode)
            {
                cms.BackColor = DarkModeColors.BackColor;
            }
            else
            {
                cms.BackColor = Config.Main.Colors.Window.BackColor;
            }
            cms.ForeColor = Coloring.GetReadableForeColor(cms.BackColor);
        }


        /// <summary>
        /// Einheitliches Design für jede ListView im GFATask
        /// </summary>
        public static void SetDefaultDesign(this ListViewEx lv)
        {
            if (Config.User.DarkMode)
            {
                lv.BackColor = DarkModeColors.BackColor;
                lv.SelectionBackColor = DarkModeColors.Apps.Hover.BackColor;
            }
            else
            {
                lv.BackColor = Color.White;
                lv.SelectionBackColor = Config.Main.Colors.Apps.Hover.BackColor;
            }

            lv.SelectionLine = false;
            lv.ForeColor = Coloring.GetReadableForeColor(lv.BackColor);
            lv.SelectionForeColor = Coloring.GetReadableForeColor(lv.SelectionBackColor);
            lv.Font = new Font(Config.Main.FontFamily, Config.User.Window.FontSize);
        }


        /// <summary>
        /// Einheitliches Design für jedes DataGridView im GFATask
        /// </summary>
        public static void SetDefaultDesign(this DataGridView dgv)
        {
            dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect;

            if (Config.User.DarkMode)
            {
                dgv.BackgroundColor = DarkModeColors.BackColor;
                dgv.DefaultCellStyle.BackColor = DarkModeColors.BackColor;
                dgv.DefaultCellStyle.SelectionBackColor = DarkModeColors.Apps.Hover.BackColor;
            }
            else
            {
                dgv.BackgroundColor = Color.White;
                dgv.DefaultCellStyle.BackColor = Color.White;
                dgv.DefaultCellStyle.SelectionBackColor = Config.Main.Colors.Apps.Hover.BackColor;
            }
                
            dgv.RowHeadersWidth = 30;
            dgv.DefaultCellStyle.ForeColor = Coloring.GetReadableForeColor(dgv.BackgroundColor);
            dgv.DefaultCellStyle.SelectionForeColor = Coloring.GetReadableForeColor(dgv.DefaultCellStyle.SelectionBackColor);
            dgv.Font = new Font(Config.Main.FontFamily, Config.User.Window.FontSize);
            dgv.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
        }


        /// <summary>
        /// Einheitliches Design für jede TextBox im GFATask
        /// </summary>
        public static void SetDefaultDesign(this TextBox tb)
        {
            if(tb.Parent != null && tb.Parent.GetType() != typeof(NumericEx))
                tb.BorderStyle = BorderStyle.FixedSingle;
            tb.BackColor = tb.Parent.BackColor;
            tb.ForeColor = Coloring.GetReadableForeColor(tb.BackColor);
            tb.Font = new Font(Config.Main.FontFamily, Config.User.Window.FontSize);
        }


        /// <summary>
        /// Einheitliches Design für jede RichTextBox im GFATask
        /// </summary>
        public static void SetDefaultDesign(this RichTextBox rtb)
        {
            rtb.BorderStyle = BorderStyle.FixedSingle;
            rtb.BackColor = rtb.Parent.BackColor;
            rtb.ForeColor = Coloring.GetReadableForeColor(rtb.BackColor);
            rtb.Font = new Font(Config.Main.FontFamily, Config.User.Window.FontSize);
        }


        /// <summary>
        /// Einheitliches Design für jeden AppListButton im GFATask
        /// </summary>
        public static AppListButton SetDefaultDesign(this AppListButton button)
        {
            SetDefaultDesign((AnimationButton)button);
            return button;
        }


        /// <summary>
        /// Einheitliches Design für jeden AnimationButton im GFATask
        /// </summary>
        public static AnimationButton SetDefaultDesign(this AnimationButton button)
        {
            button.DoubleBuffer(true);
            button.ImageRadius = Config.User.Apps.Radius.Image;
            button.Margin = new Padding(Config.User.Apps.Margin);
            button.ImageAlign = AnchorStyles.Left;
            button.Radius = Config.User.Apps.Radius.Button;
            button.BorderSize = button.GetType() == typeof(AnimationButton) ? 1 : Config.User.Apps.Border;
            button.BorderColor = Config.Main.Colors.Apps.Default.Border;

            #region Colors
            if (Config.User.DarkMode)
            {
                button.BackColor = DarkModeColors.Apps.Default.BackColor;
                button.AnimateColor = button.BorderSize == 0 ? DarkModeColors.Apps.Hover.BackColor : DarkModeColors.Apps.Hover.Border;

                button.ForeColor = DarkModeColors.Apps.Default.ForeColor;
                button.AnimateForeColor = DarkModeColors.Apps.Hover.ForeColor;

                button.ImageBackColor = DarkModeColors.Apps.Default.Image;
                button.AnimateImageBackColor = DarkModeColors.Apps.Hover.Image;
            }
            else
            {
                button.BackColor = Config.Main.Colors.Apps.Default.BackColor;
                button.AnimateColor = button.BorderSize == 0 ? Config.Main.Colors.Apps.Hover.BackColor : Config.Main.Colors.Apps.Hover.Border;

                button.ForeColor = Config.Main.Colors.Apps.Default.ForeColor;
                button.AnimateForeColor = Config.Main.Colors.Apps.Hover.ForeColor;

                button.ImageBackColor = Config.Main.Colors.Apps.Default.Image;
                button.AnimateImageBackColor = Config.Main.Colors.Apps.Hover.Image;
            }
            #endregion

            button.Font = new Font(Config.Main.FontFamily, Config.User.Window.FontSize);
            button.AnimationRegion = AnimationRgn.Border;
            button.ImagePadding = 3;
            button.ImageMargin = Config.User.Apps.ImageOnly ? 0 : 2;
            button.ImageAutoSize = ImageAutoSizeDirection.Height;
            button.ToolTip.SetDefaultDesign();
            return button;
        }


        /// <summary>
        /// Einheitliches Design für jede Form im GFATask
        /// </summary>
        public static void SetDefaultDesign(this FormEx form)
        {
            if (Config.User.DarkMode)
            {
                form.BackColor = DarkModeColors.BackColor;
                form.BorderColor = DarkModeColors.Border;
            }
            else
            {
                form.BackColor = Forms.AppButtonGroup != null && form.Name == Forms.AppButtonGroup.Name ? Config.Main.Colors.GroupWindow.BackColor : Config.Main.Colors.Window.BackColor;
                form.BorderColor = Forms.AppButtonGroup != null && form.Name == Forms.AppButtonGroup.Name ? Config.Main.Colors.GroupWindow.Border : Config.Main.Colors.Window.Border;
            }

            form.TitlebarBackColor = Forms.AppButtonGroup != null && form.Name == Forms.AppButtonGroup.Name ? Config.Main.Colors.GroupWindow.TitlebarBackColor : Config.Main.Colors.Window.TitlebarBackColor;
            form.TitlebarForeColor = Coloring.GetReadableForeColor(form.TitlebarBackColor);
            form.ForeColor = Coloring.GetReadableForeColor(form.BackColor);

            form.Font = new Font(Config.Main.FontFamily, Config.User.Window.FontSize);
            form.RoundedCorners = Config.Main.Sizes.Window.Radius == 0 ? 
                RectangleCorners.None : 
                form.Name == Forms.Main.Name ? RectangleCorners.BottomLeft | RectangleCorners.BottomRight : 
                RectangleCorners.All;
            form.Radius = Config.Main.Sizes.Window.Radius;
            form.BorderWidth = Config.Main.Sizes.Window.Border;

            Accumulations.Controls(form).OfType<UserControl>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
            if (!Accumulations.Controls(form).OfType<UserControl>().Any())
            {
                Accumulations.Controls(form).OfType<NumericEx>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
                Accumulations.Controls(form).OfType<FlowLayoutPanel>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
                Accumulations.Controls(form).OfType<AnimationButton>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
                Accumulations.Controls(form).OfType<ToolTipEx>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
                Accumulations.Controls(form).OfType<AppListButton>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
                Accumulations.Controls(form).OfType<SwitchButton>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
                Accumulations.Controls(form).OfType<AppListPanel>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
                Accumulations.Controls(form).OfType<ContextMenuStrip>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
                Accumulations.Controls(form).OfType<ListViewEx>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
                Accumulations.Controls(form).OfType<DataGridView>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
                Accumulations.Controls(form).OfType<ComboBox>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
                Accumulations.Controls(form).OfType<TextBox>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
                Accumulations.Controls(form).OfType<RichTextBox>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
            }
        }


        /// <summary>
        /// Einheitliches Design für jede Form im GFATask
        /// </summary>
        public static void SetDefaultDesign(this UserControl usercontrol)
        {
            if(Config.User.DarkMode)
                usercontrol.BackColor = DarkModeColors.BackColor;
            else
                usercontrol.BackColor = Config.Main.Colors.Window.BackColor;

            usercontrol.ForeColor = Coloring.GetReadableForeColor(usercontrol.BackColor);
            usercontrol.Font = new Font(Config.Main.FontFamily, Config.User.Window.FontSize);

            Accumulations.Controls(usercontrol).OfType<NumericEx>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
            Accumulations.Controls(usercontrol).OfType<FlowLayoutPanel>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
            Accumulations.Controls(usercontrol).OfType<AnimationButton>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
            Accumulations.Controls(usercontrol).OfType<AppListButton>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
            Accumulations.Controls(usercontrol).OfType<SwitchButton>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
            Accumulations.Controls(usercontrol).OfType<AppListPanel>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
            Accumulations.Controls(usercontrol).OfType<ContextMenuStrip>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
            Accumulations.Controls(usercontrol).OfType<ListViewEx>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
            Accumulations.Controls(usercontrol).OfType<DataGridView>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
            Accumulations.Controls(usercontrol).OfType<ToolTipEx>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
            Accumulations.Controls(usercontrol).OfType<TextBox>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
            Accumulations.Controls(usercontrol).OfType<RichTextBox>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
            if(Forms.Administration != null && usercontrol != Forms.Administration.UcAdminDesigns)
                Accumulations.Controls(usercontrol).OfType<ComboBox>().ToList().ForEach(ctl => ctl.SetDefaultDesign());
        }


        /// <summary>
        /// Einheitliches Design für jedes Numeric Steuerelement im GFATask
        /// </summary>
        public static void SetDefaultDesign(this NumericEx numeric)
        {
            if(Config.User.DarkMode)
                numeric.BackColor = DarkModeColors.BackColor;
            else
                numeric.BackColor = Config.Main.Colors.Window.BackColor;

            numeric.ForeColor = Coloring.GetReadableForeColor(numeric.BackColor);
            numeric.Font = new Font(Config.Main.FontFamily, Config.User.Window.FontSize);
            numeric.BorderStyle = BorderStyle.FixedSingle;
        }


        /// <summary>
        /// Einheitliches Design für jede Form im GFATask
        /// </summary>
        public static void SetDefaultDesign(this FlowLayoutPanel flowlayoutpanel)
        {
            if(Config.User.DarkMode)
                flowlayoutpanel.BackColor = DarkModeColors.BackColor;
            else
                flowlayoutpanel.BackColor = Config.Main.Colors.Window.BackColor;

            flowlayoutpanel.ForeColor = Coloring.GetReadableForeColor(flowlayoutpanel.BackColor);
            flowlayoutpanel.Font = new Font(Config.Main.FontFamily, Config.User.Window.FontSize);
        }


        /// <summary>
        /// Enheitliches Design für jeden ToolTip im GFATask
        /// </summary>
        public static void SetDefaultDesign(this ToolTipEx tooltip)
        {
            tooltip.TextFormatFlags = TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter;
            
            if (Config.User.DarkMode)
                tooltip.BackColor = DarkModeColors.BackColor;
            else
                tooltip.BackColor = Config.Main.Colors.Window.BackColor;

            tooltip.ForeColor = Coloring.GetReadableForeColor(tooltip.BackColor);
            tooltip.InitialDelay = 1000;
            tooltip.AutoPopDelay = 8000;
            tooltip.ReshowDelay = 1000;
            tooltip.ShowAlways = true;
        }

        /// <summary>
        /// Einheitliches Design für die Benachrichtigungsfenster
        /// </summary>
        public static NotifyDesigner Notify(int width = 0, int height = 0)
        {
            return new NotifyDesigner()
            {
                BackColor = Config.User.DarkMode ? DarkModeColors.BackColor : Config.Main.Colors.Window.BackColor,
                ForeColor = Config.User.DarkMode ? Coloring.GetReadableForeColor(DarkModeColors.BackColor) : Coloring.GetReadableForeColor(Config.Main.Colors.Window.BackColor),
                Size = width == 0 && height == 0 ? new Size(500, 400) : new Size(width, height),
                Font = new Font(Config.Main.FontFamily, Config.User.Window.FontSize),
                BorderColor = Config.User.DarkMode ? DarkModeColors.Border : Config.Main.Colors.Window.Border,
                Radius = Config.Main.Sizes.Window.Radius,
                BorderWidth = 1,
                Buttons = new NotifyDesigner.ButtonDesign()
                {
                    Size = new Size(Config.User.Apps.Size.Width / 2, Config.User.Apps.Size.Height),
                    Radius = Config.User.Apps.Radius.Button,
                    BorderColor = Config.User.DarkMode ? DarkModeColors.Apps.Default.Border : Config.Main.Colors.Apps.Default.Border,
                    BorderWidth = 1,
                    AnimationRegion =  AnimationRgn.Border
                },
                Titlebar = new NotifyDesigner.TitlebarDesign()
                {
                    BackColor = Config.Main.Colors.Window.TitlebarBackColor,
                    ForeColor = Coloring.GetReadableForeColor(Config.Main.Colors.Window.TitlebarBackColor)
                }
            };
        }

        /// <summary>
        /// Einheitliches Design für jeden SwitchButton im GFATask
        /// </summary>
        public static void SetDefaultDesign(this SwitchButton switchbutton)
        {
            switchbutton.CheckThreeState = false;
            switchbutton.RoundedButton = true;
            switchbutton.ButtonRadius = 5;
            switchbutton.Radius = 5;

            if (Config.User.DarkMode)
            {
                switchbutton.BackColor = DarkModeColors.BackColor.AddBirghtness(Coloring.GetReadableForeColor(DarkModeColors.BackColor) == Color.White ? 200 : -30);
                switchbutton.BorderColor = DarkModeColors.Border;
            }
            else
            {
                switchbutton.BackColor = Config.Main.Colors.Window.BackColor.AddBirghtness(Coloring.GetReadableForeColor(Config.Main.Colors.Window.BackColor) == Color.White ? 200 : -30);
                switchbutton.BorderColor = Config.Main.Colors.List.Border;
            }
            
            switchbutton.ButtonWidth = 35;
            switchbutton.ColorActive = Color.DarkSeaGreen;
            switchbutton.ColorInactive = Color.OrangeRed;
            switchbutton.Size = new Size(80, 25);
            switchbutton.Font = new Font(Config.Main.FontFamily, Config.User.Window.FontSize);
        }
    }


    /// <summary>
    /// Barrierefreier Zugriff auf die Fenster
    /// </summary>
    public class Forms
    {
        /// <summary>
        /// Gibt das Hauptfenster des GFATask aus
        /// </summary>
        public static FormMain Main { get; set; }

        /// <summary>
        /// Gibt das Hauptfenster des GFATask aus
        /// </summary>
        public static FormInfo Info { get; set; }

        /// <summary>
        /// Gibt das Active Directory-Gruppen Fenster aus
        /// </summary>
        public static FormGroups Groups { get; set; }

        /// <summary>
        /// Gibt das Einstellungsfenster aus
        /// </summary>
        public static FormSettings Settings { get; set; }

        /// <summary>
        /// Gibt das Administrationsfenster aus
        /// </summary>
        public static FormAdmin Administration { get; set; }

        /// <summary>
        /// Gibt das Fenster zur App-Erstellung aus
        /// </summary>
        public static FormAppCreator AppCreator { get; set; }

        /// <summary>
        /// Gibt das Fenster zur App-Erstellung aus
        /// </summary>
        public static FormAppButtonGroup AppButtonGroup { get; set; }
    }


    /// <summary>
    /// Barrierefreier Zugriff auf Low-Level Maus- und Tastaturfunktionen
    /// </summary>
    public partial class Hooks
    {
        /// <summary>
        /// Low-Level Mausereignisse, die auch außerhalb des Forms abgefangen werden
        /// </summary>
        public static MouseHook Mouse { get; } = new MouseHook();

        /// <summary>
        /// Barrierefreier Zugriff auf Low-Level Tastaturfunktionen
        /// </summary>
        public class KeyBoard
        {
            /// <summary>
            /// Low-Level Keyboardereignisse, die auch außerhalb des Forms ABGEFANGEN werden
            /// </summary>
            public static HotKeys Interceptor { get; } = new HotKeys();

            /// <summary>
            /// Keyboardereignisse, die auch außerhalb des Forms ABGEHÖRT werden
            /// </summary>
            public static GlobalKeyboardHook Listener { get; } = new GlobalKeyboardHook();
        }
    }


    /// <summary>
    /// Barrierefreier Zugriff auf den EventLogger
    /// </summary>
    public class Log
    {
        /// <summary>
        /// Protokollierungsklasse
        /// </summary>
        public static Logging EventLog { get; set; } = new Logging(Paths.Logs.Name, Paths.Logs.Directory) {  };
    }


    /// <summary>
    /// Barrierefreier Zugriff auf definierte Pfade
    /// </summary>
    public class Paths
    {
        /// <summary>
        /// Pfad zu den App Icons
        /// </summary>
        public static PathEx AppClickCounter { get; set; } = new PathEx(string.Format(@"{0}\Configs\", Application.StartupPath), "appclickcounter.json");

        /// <summary>
        /// Pfad zu den App Icons
        /// </summary>
        public static PathEx Icons { get; set; } = new PathEx(string.Format(@"{0}\Icons\", Application.StartupPath), "");

        /// <summary>
        /// Pfad zu den benutzerdefinierten Sicherungsdateien 
        /// </summary>
        public static PathEx Bak { get; set; } = new PathEx(string.Format(@"{0}\Bak\", Application.StartupPath), "");

        /// <summary>
        /// Pfad und Dateiname zur allgemeinen Konfigurationsdatei
        /// </summary>
        public static PathEx MainConfig { get; set; } = new PathEx(string.Format(@"{0}\Configs\", Application.StartupPath), "main.json");

        /// <summary>
        /// Pfad und Dateiname zur benutzerdefinierten Konfigurationsdatei
        /// </summary>
        public static PathEx UserConfig { get; set; } = new PathEx(string.Format(@"{0}\GFATask\", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)), "userconf.json");

        /// <summary>
        /// Pfad und Dateiname zur benutzerdefinierten Konfigurationsdatei
        /// </summary>
        public static PathEx FrontEndRefresh { get; set; } = new PathEx(Application.StartupPath, "Updates.dat");

        /// <summary>
        /// Pfad zu den Apps
        /// </summary>
        public static PathEx Apps { get; set; } = new PathEx(string.Format(@"{0}\Apps\", Application.StartupPath), "");

        /// <summary>
        /// Pfad zu den Ereignis-Logs
        /// </summary>
        public static PathEx Logs { get; set; } = new PathEx($@"{Application.StartupPath}\Logs\", $"{Environment.UserName.Replace(".","_")}");

        /// <summary>
        /// Barrierefreier Zugriff auf Pfade der Hilfedateien
        /// </summary>
        public class Help
        {
            /// <summary>
            /// Pfad zu den Administratoren Hilfethemen
            /// </summary>
            public static PathEx Administration { get; set; } = new PathEx($@"{Application.StartupPath}\Help\", "Administration.htm");
        }

        /// <summary>
        /// Barrierefreier Zugriff auf Pfade der internationalen Welttage
        /// </summary>
        public class NewsFeeds
        {
            /// <summary>
            /// Pfad zu den Symbolen der NewsFeeds
            /// </summary>
            public static PathEx Icons { get; set; } = new PathEx($@"{Application.StartupPath}\Icons\NewsFeeds\", "");

            /// <summary>
            /// Pfad zu der NewsFeeds-JSON datei
            /// </summary>
            public static PathEx Values { get; set; } = new PathEx($@"{Application.StartupPath}\Configs\", "newsfeeds.json");

        }

        /// <summary>
        /// Barrierefreier Zugriff auf Favoriten-Pfade
        /// </summary>
        public class Favorites
        {
            /// <summary>
            /// Barrierefreier Zugriff auf Favoriten Pfade 
            /// </summary>
            public static PathEx Apps { get; set; } = new PathEx(string.Format(@"{0}\GFATask\", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)), "favorites.json");

            /// <summary>
            /// Pfad und Dateiname zu den benutzerdefinierten Favoriten Symbolen
            /// </summary>
            public static PathEx Icons { get; set; } = new PathEx(string.Format(@"{0}\GFATask\Icons\", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)), "");
        }

        /// <summary>
        /// Pfad und Dateiname zu der benutzerdefinierten Sortierung der Apps
        /// </summary>
        public static PathEx Prevalence { get; set; } = new PathEx(string.Format(@"{0}\GFATask\", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)), "prevalence.json");

       
        /// <summary>
        /// Barrierefreier Zugriff auf Citrix-Pfade 
        /// </summary>
        public class Citrix
        {
            /// <summary>
            /// Pfad und Dateiname zur Apps-XML-Datei 
            /// </summary>
            public static PathEx Apps
            {
                get
                {
                    var mainconfig_appfilelocation = EnvironmentManager.VariableConverter(Config.Main.Citrix.AppsLocation, true);
                    if (!File.Exists(mainconfig_appfilelocation))
                    {
                        if(!Directory.Exists(Path.GetFullPath(mainconfig_appfilelocation)))
                            Directory.CreateDirectory(Path.GetFullPath(mainconfig_appfilelocation));
                        return new PathEx(Path.GetFullPath(mainconfig_appfilelocation), "");
                    }
                    var dirinfo = new DirectoryInfo(mainconfig_appfilelocation).GetFiles("*.xml", SearchOption.TopDirectoryOnly).First();
                    return new PathEx(Path.GetDirectoryName(dirinfo.FullName) + "\\", Path.GetFileName(dirinfo.FullName));
                }
            }

            /// <summary>
            /// Pfad zu den Citrix App Icons
            /// </summary>
            public static PathEx Icons
            {
                get
                {
                    var mainconfig_icon = EnvironmentManager.VariableConverter(Config.Main.Citrix.Icons, true);
                    return new PathEx(mainconfig_icon, ""); ;
                }
            }

            /// <summary>
            /// Pfad zum ICA Client zum Ausführen der Citrix Apps
            /// </summary>
            public static PathEx ICASelfService
            {
                get
                {
                    return new PathEx(EnvironmentManager.VariableConverter(Config.Main.Citrix.ICASelfService, true));
                }
            }
        }
    }


    /// <summary>
    /// Barrierefreier Zugriff auf verschiedene Klassenobjekte
    /// </summary>
    public class XObjects
    {
        /// <summary>
        /// Eine Auflistung aller installierten WebBrowser
        /// </summary>
        /// <returns></returns>
        public static List<Microsoft.Win32.Browser> WebBrowsers { get => Microsoft.Win32.RegistryEx.GetInstalledBrowsers().ToList(); }


        /// <summary>
        /// Sendet E-Mails über einen AD-Mail-Dienst-Account
        /// </summary>
        public static SendMail MailService { get; set; } = new SendMail(
                    Config.Main.Administration.Accounts.Mail.Host,
                    Config.Main.Administration.Accounts.Mail.SSLPort,
                   Config.Main.Administration.Accounts.Mail.UserName,
                    new string(Config.Main.Administration.Accounts.Mail.SecurePassword.Select(ascii => (char)ascii).ToArray()));

        /// <summary>
        /// Lädt Systemweite Ereignisse zum Verändern diverser Eigenschaften des GFATask, zur Laufzeit
        /// </summary>
        public static SystemChanges SystemChanges { get; set; } = new SystemChanges();

        /// <summary>
        /// Stellt ein Panel-Steuerelement dar, das die Ladeanimation darstellt
        /// </summary>
        public static LoadingPanel LoadingPanel { get; set; } = new LoadingPanel()
        {
            BackColor = Config.User.DarkMode ? DarkModeColors.BackColor : Config.Main.Colors.Window.BackColor,
            MovingPoints =
            new List<MovingPoint>() {
                new MovingPoint(new Size(10, 10), new Point(-20, -10), new Point(-5, 5), Config.Main.Colors.LoadingAnimation.Dot1),
                new MovingPoint(new Size(10, 10), new Point(10, 5), new Point(-15, -10), Config.Main.Colors.LoadingAnimation.Dot2),
                new MovingPoint(new Size(10, 10), new Point(15, 15), new Point(5, -15), Config.Main.Colors.LoadingAnimation.Dot3),
                new MovingPoint(new Size(10, 10), new Point(5, -10), new Point(15, -5), Config.Main.Colors.LoadingAnimation.Dot4),
            }
        };

        /// <summary>
        /// Prüft, ob es sich beim Befehl um eine verknüpfte App handelt
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public static bool IsAppLnk(string command)
        {
            return command != null && command.StartsWith("APPLNK:");
        }

        /// <summary>
        /// Asynchrone Abfrage, ob das Suchen nach der speziellen Admin-Gruppen im Active Directory beendet ist (Nutzung: Task.Run(async () => await XObjects.IsAdmin))
        /// </summary>
        public static Task<bool> IsAdmin
        {
            get
            {
                return Task.Run(async () =>
                 {
                     while (!AD.GroupSearchingFinish)
                     {
                         await Task.Delay(100);
                     }
                     return (!Config.Main.UseActiveDirectoryGroups && Win32API.IsUserAnAdmin()) || AD.Groups.Cast<GroupPrincipal>().Select(group => group.Name).Contains(Config.Main.Administration.ActiveDirectoryGroup);
                 });
            }
        }

        /// <summary>
        /// Asynchrone Abfrage, ob das Suchen nach Gruppen im Active Directory beendet ist (Nutzung: Task.Run(async () => await XObjects.IsADGroupFinish))
        /// </summary>
        public static Task<bool> IsADGroupFinish
        {
            get
            {
                return Task.Run(async () =>
                 {
                     while (!AD.GroupSearchingFinish)
                     {
                         await Task.Delay(100);
                     }
                     return true;
                 });
            }
        }

        /// <summary>
        /// Ein Kontextmenü für die Schnelleinträge der Steuerelemente
        /// </summary>
        public static ContextMenuStrip ContextMenuStrip { get; set; } = new ContextMenuStrip() { Visible = false };

        /// <summary>
        /// Hört einen Netzwerk-Port dauerhaft auf Änderungen ab
        /// </summary>
        //public static NetPipe<GFATaskStream> NetPipe { get; set; } 
        public static FrontEndRefresh<GFATaskStream> FrontEndRefresh { get; set; }


        /// <summary>
        /// Erstellt eine Klasse zum zwischenspeichern von Einstellungen
        /// </summary>
        public static PreChanging PreChanging { get; } = new PreChanging();

        /// <summary>
        /// Pausiert den Ein- und Ausblendeprozess des GFATask, solange die Eigenschaft wahr ist
        /// </summary>
        public static bool PausedDelay { get; set; } = false;

        /// <summary>
        /// Ein Verzögerungsprozess für das Ein- und Ausblenden des GFATask 
        /// </summary>
        public static Delay Delay { get; set; } = new Delay();

        /// <summary>
        /// Eine Auflistung aller Applisten im GFATask
        /// </summary>
        public static List<AppListPanel> AllAppListPanels { get; } = new List<AppListPanel>();

        /// <summary>
        /// Erstellt anhand mehrerer Suchparameter, eine Auflistung von Dateien
        /// </summary>
        /// <param name="path">Der zu durchsuchende Pfad</param>
        /// <param name="searchPattern">*.[fileextension]| *.[another_fileextension]</param>
        /// <param name="searchOption">Gibt an ob das aktuelle, oder das aktuelle und alle Unterverzeichnisse durchsucht werden sollen</param>
        /// <returns></returns>
        public static IEnumerable<string> GetFiles(string path, string searchPattern, SearchOption searchOption = SearchOption.TopDirectoryOnly)
        {
            string[] searchPatterns = searchPattern.Split('|');
            foreach (string sp in searchPatterns)
                foreach (string file in Directory.GetFiles(path, sp, searchOption))
                    yield return file;
        }

        /// <summary>
        /// Definiert die Parameter eines Benachrichtigungsfensters.
        /// </summary>
        /// <param name="message">Bestimmt den anzuzeigenden Informationstext</param>
        /// <param name="title">Bestimmt den Titel in der Titelleiste</param>
        /// <param name="type">Bestimmt, welche Auswahlmöglichkeiten zum Ausgeben von Informationen an das Programm, das Fenster erhalten soll</param>
        /// <param name="buttons">Welche Schaltflächen sollen angezeigt werden</param>
        /// <param name="source">Gibt es ein vordefiniertes Objekt für eine Auswahlmöglichkeit</param>
        /// <param name="size">Bestimmt die Größe des Fensters</param>
        /// <returns></returns>
        public static NotifyResult MessageBox(string message, NotifyButtons buttons, NotifyType type, Size size, string title, object source = null)
        {
            PausedDelay = true;
            var notify = Notify.Show(message, title, buttons, type, source, null, Designer.Notify(size.Width, size.Height) );
            if (notify.Result != DialogResult.None) 
            {
                PausedDelay = false;
                return notify;
            };
            return notify;
        }

        /// <summary>
        /// Startet den GFATask neu
        /// </summary>
        public static void Restart(string args)
        {
            var startInfo = Process.GetCurrentProcess().StartInfo;
            startInfo.FileName = Application.ExecutablePath;
            var exit = typeof(Application).GetMethod("ExitInternal", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
            startInfo.Arguments = args;
            Process.Start(startInfo);
            exit.Invoke(null, null);
        }

    }


    #region Structs
    /// <summary>
    /// Bestimmt, oder gibt die Farben des Dark Modes an
    /// </summary>
    internal struct DarkModeColors
    {
        /// <summary>
        /// Hintergrundfarbe des Dark Modes
        /// </summary>
        public static Color BackColor { get; } = Color.FromArgb(45, 45, 45);

        /// <summary>
        /// Schriftfarbe des Dark Modes
        /// </summary>
        public static Color ForeColor { get; } = Coloring.GetReadableForeColor(BackColor);

        /// <summary>
        /// Rahmenfarbe des Dark Modes
        /// </summary>
        public static Color Border { get; } = Color.FromArgb(255, 255, 255);

        /// <summary>
        /// Beinhaltet die Farben der Apps im Dark Mode
        /// </summary>
        public struct Apps
        {
            /// <summary>
            /// Die Farben einer App im Dark Mode
            /// </summary>
            public static AppColors Default { get; } = new AppColors()
            {
                BackColor = Color.FromArgb(45, 45, 45),
                Border = Color.White,
                ForeColor = Color.White,
                Image = Color.CornflowerBlue
            };

            /// <summary>
            /// Die Farben einer App im Dark Mode, sobald der Mauszeiger eintritt
            /// </summary>
            public static AppColors Hover { get; } = new AppColors()
            {
                BackColor = Color.FromArgb(98, 98, 98),
                Border = Color.FromArgb(29, 98, 145),
                ForeColor = Color.White,
                Image = Color.FromArgb(128, 167, 240)
            };

            /// <summary>
            /// Farben einer App im Dark Mode
            /// </summary>
            public class AppColors
            {
                /// <summary>
                /// Hintergrundfarbe einer App im Dark Mode
                /// </summary>
                public Color BackColor { get; set; }

                /// <summary>
                /// Schriftfarbe einer App im Dark Mode
                /// </summary>
                public Color ForeColor { get; set; }

                /// <summary>
                /// Rahmenfarbe einer App im Dark Mode
                /// </summary>
                public Color Border { get; set; }

                /// <summary>
                /// Symbol-Hintergrundfarbe einer App im Dark Mode
                /// </summary>
                public Color Image { get; set; }
            }
        }
    }


    /// <summary>
    /// Gibt das Objekt und den Datentyp des Objekts bei einem Drag'n Drop Vorgang aus
    /// </summary>
    /// <param name="drgevent">Das Drag'n Drop Ereignis aus dem das Objekt und der Datentyp ausgelesen wird</param>
    /// <returns></returns>
    public struct DragDropDataType
    {
        public object Data { get; set; }
        public DragType DragAs { get; set; }
        public DragEventArgs DragEvt { get; set; }

        public DragDropDataType(DragEventArgs dragevt)
        {
            string[] formats = dragevt.Data.GetFormats();
            DragType dragas = DragType.None;
            IDataObject idata = dragevt.Data;
            object data = idata.GetData(formats[0]);


            if (data is AppButton)
                dragas = (data as AppButton).AppType == AppType.Favorites ? DragType.FavoriteApp : DragType.AppButton;
            else if (data is GroupButton)
                dragas = (data as GroupButton).AppType == AppType.Favorites ? DragType.FavoriteGroup : DragType.GroupButton;
            else if (formats.Contains(DataFormats.FileDrop))
            {
                dragas = File.GetAttributes(((string[])dragevt.Data.GetData(DataFormats.FileDrop))[0]).HasFlag(FileAttributes.Directory) ? DragType.Directory : DragType.File;
                data = idata.GetData(DataFormats.FileDrop);
            }
            else if (formats.Contains(DataFormats.StringFormat)) //Für den FireFox
            {
                dragas = DragType.Text;
                data = idata.GetData(DataFormats.StringFormat);
            }
            else if (formats.Contains(DataFormats.Html))
            {
                dragas = DragType.Html;
                data = idata.GetData(DataFormats.Html);
            }
            else if (formats.Contains(DataFormats.Text))
            {
                dragas = DragType.Text;
                data = idata.GetData(DataFormats.Text);
            }

            DragAs = dragas;
            Data = data;
            DragEvt = dragevt;
        }

        /// <summary>
        /// EXPERIMENTAL!!!
        /// </summary>
        /// <param name="clipboard"></param>
        public DragDropDataType(string clipboard)
        {
            string[] formats = Clipboard.GetDataObject().GetFormats();
            DragType dragas = DragType.None;
            IDataObject idata = Clipboard.GetDataObject();
            object data = idata.GetData(formats[0]);

            if (formats.Contains(DataFormats.FileDrop))
            {
                dragas = File.GetAttributes(((string[])idata.GetData(DataFormats.FileDrop))[0]).HasFlag(FileAttributes.Directory) ? DragType.Directory : DragType.File;
                data = idata.GetData(DataFormats.FileDrop);
            }
            else if (formats.Contains(DataFormats.StringFormat)) //Für den FireFox
            {
                dragas = DragType.Text;
                data = idata.GetData(DataFormats.StringFormat);
            }
            else if (formats.Contains(DataFormats.Html))
            {
                dragas = DragType.Html;
                data = idata.GetData(DataFormats.Html);
            }
            else if (formats.Contains(DataFormats.Text))
            {
                dragas = DragType.Text;
                data = idata.GetData(DataFormats.Text);
            }

            DragAs = dragas;
            Data = data;
            DragEvt = new DragEventArgs(Clipboard.GetDataObject(), 0, 0, 0, DragDropEffects.All, DragDropEffects.Copy);
        }
    }
    #endregion


    #region Enums
    /// <summary>
    /// Definiert den Datentyp des Objekts bei einem Drag'n Drop Vorgang
    /// </summary>
    public enum DragType
    {
        /// <summary>
        /// Kein Typ definiert
        /// </summary>
        None = 0,

        /// <summary>
        /// Definiert einen Favoriten AppButton
        /// </summary>
        FavoriteApp,

        /// <summary>
        /// Definiert einen Favoriten GroupButton
        /// </summary>
        FavoriteGroup,

        /// <summary>
        /// Definiert einen gewöhnlichen AppButton
        /// </summary>
        AppButton,

        /// <summary>
        /// Definiert einen AppGroupButton mit den darin enthaltenen AppButtons
        /// </summary>
        GroupButton,

        /// <summary>
        /// Definiert einen Dateiordner
        /// </summary>
        Directory,

        /// <summary>
        /// Definiert eine Datei aus dem Dateisystem
        /// </summary>
        File,

        /// <summary>
        /// Definiert eine Webseite
        /// </summary>
        Html,

        /// <summary>
        /// Definiert einen Text
        /// </summary>
        Text
    }


    /// <summary>
    /// Definiert den Typen des NetPipeStreams
    /// </summary>
    public enum NetPipeType
    {
        /// <summary>
        /// Definiert die Veränderung einer App
        /// </summary>
        Edit = 0,

        /// <summary>
        /// Definiert das Erstellen einer App
        /// </summary>
        Create = 1,

        /// <summary>
        /// Definiert das Entfernen einer App
        /// </summary>
        Delete = 2,

        /// <summary>
        /// Definiert das allgemeine Ändern der Hauptkonfiguration
        /// </summary>
        MainConfig = 3,

        /// <summary>
        /// Definiert das Ausführen und Hochzählen einer App
        /// </summary>
        AppCounter_CountUp = 4,

        /// <summary>
        /// Definiert das Löschen der AppClickCounter-Datei
        /// </summary>
        ClickCounter_Clear = 5,

        /// <summary>
        /// Definiert das Zurücksetzen eines AppCounters auf 0
        /// </summary>
        AppCounter_Reset = 6,

        /// <summary>
        /// Definiert Änderungen in der Hauptkonfiguration, die die Citrix-Eigenschaften betreffen
        /// </summary>
        Citrix = 7,

        /// <summary>
        /// Definiert Änderungen in der Hauptkonfiguration, die die Active Directory-Eigenschaften betreffen
        /// </summary>
        ActiveDirectory = 8,

        /// <summary>
        /// Definiert Änderungen in der Hauptkonfiguration, die die MailAccount-Eigenschaften betreffen
        /// </summary>
        MailAccount = 9,

        /// <summary>
        /// Definiert Änderungen in der Hauptkonfiguration, die die Remote-FrontEnd-Update-Eigenschaften betreffen
        /// </summary>
        FrontEndUpdate = 10,

        /// <summary>
        /// Fängt eine nicht lesbare Änderung in der Update-Datei ab
        /// </summary>
        ErrorHandle = 11
    }


    /// <summary>
    /// Definiert den Backup-Konfigurationssatz
    /// </summary>
    public enum ConfigRecoveryType
    {
        /// <summary>
        /// Definiert die Sicherung als benutzerdefinierte Einstellungen
        /// </summary>
        [Description("Benutzereinstellungen")]
        UserConfig = 0,

        /// <summary>
        /// Definiert die Sicherung als Favoriten
        /// </summary>
        [Description("Favoriten")]
        Favorites = 1,

        /// <summary>
        /// Definiert die Sicherung als Beliebtheitskonfigurationsdatei
        /// </summary>
        [Description("App-Beliebtheit")]
        Prevalences = 2
    }
    #endregion
}
