public static void Install(string filePath, SetPercentHandler SetPercent = null)
        {
            if (!File.Exists(filePath))
            {
                throw new Exception("File not found!");
            }

            SetPercent?.Invoke(0);

            // Do aiv folder backup
            string        dir       = Path.Combine(Path.GetDirectoryName(filePath), "aiv", BackupIdent);
            DirectoryInfo backupDir = new DirectoryInfo(dir);
            DirectoryInfo aivDir    = backupDir.Parent;

            if (backupDir.Exists)
            {
                // restore originals
                foreach (FileInfo fi in backupDir.EnumerateFiles("*.aiv"))
                {
                    fi.CopyTo(Path.Combine(aivDir.FullName, fi.Name), true);
                }
            }
            else
            {
                // create backup
                backupDir.Create();
                foreach (FileInfo fi in aivDir.EnumerateFiles("*.aiv"))
                {
                    fi.CopyTo(Path.Combine(backupDir.FullName, fi.Name));
                }
            }

            DoChanges(filePath, aivDir, SetPercent);
            SetPercent?.Invoke(1);
        }
        static void DoChanges(string filePath, DirectoryInfo aivFolder, SetPercentHandler SetPercent)
        {
            // count binary changes
            List <BinaryChange> binTodo = new List <BinaryChange>(Version.Changes.Count());

            foreach (Change change in Version.Changes)
            {
                if (change.IsChecked && change is BinaryChange bc)
                {
                    binTodo.Add(bc);
                }
            }

            int    index = 0;
            double count = 1 + binTodo.Count; // +1 for version edit

            // aiv changes
            AIVChange aivChange = (AIVChange)Version.Changes.FirstOrDefault(c => c.IsChecked && c is AIVChange);

            if (aivChange != null)
            {
                count++;
                aivChange.Activate(aivFolder);
                SetPercent?.Invoke(++index / count);
            }

            // read original data
            byte[] oriData = File.ReadAllBytes(filePath);
            byte[] data    = (byte[])oriData.Clone();

            // change version display in main menu
            var displayResult = Version.MenuChange.Edit(data, oriData);

            if (displayResult != BinaryEdit.Result.NoErrors)
            {
                throw new Exception("Menu display edit failed: " + displayResult);
            }

            // change other stuff
            foreach (BinaryChange change in binTodo)
            {
                change.Edit(data, oriData);
                SetPercent?.Invoke(++index / count);
            }

            if (filePath.EndsWith(BackupFileEnding))
            {
                filePath = filePath.Remove(filePath.Length - BackupFileEnding.Length);
            }
            else
            {
                // create backup
                File.WriteAllBytes(filePath + BackupFileEnding, oriData);
            }

            File.WriteAllBytes(filePath, data);
        }
        static void DoChanges(string filePath, DirectoryInfo aivFolder, SetPercentHandler SetPercent)
        {
            List <Change> todo = new List <Change>(Version.Changes.Where(c => c.IsChecked));

            int    index = 0;
            double count = 4 + todo.Count; // +1 from folder backup above, +1 for read, +1 for version edit, +1 for writing data

            SetPercent?.Invoke(++index / count);


            // read original data & section preparation
            byte[] oriData = File.ReadAllBytes(filePath);
            byte[] data    = (byte[])oriData.Clone();
            SectionEditor.Init(data);

            ChangeArgs args = new ChangeArgs(data, oriData, aivFolder);

            SetPercent?.Invoke(++index / count);



            // change version display in main menu
            try
            {
                Version.MenuChange.Activate(args);
            }
            catch (Exception e)
            {
                Debug.Error(e);
            }
            SetPercent?.Invoke(++index / count);



            // change stuff
            foreach (Change change in todo)
            {
                change.Activate(args);
                SetPercent?.Invoke(++index / count);
            }

            data = SectionEditor.AttachSection(data);

            if (filePath.EndsWith(BackupFileEnding))
            {
                filePath = filePath.Remove(filePath.Length - BackupFileEnding.Length);
            }
            else
            {
                // create backup
                File.WriteAllBytes(filePath + BackupFileEnding, oriData);
            }

            File.WriteAllBytes(filePath, data);
        }
        static void DoChanges(string filePath, DirectoryInfo aivFolder, SetPercentHandler SetPercent)
        {
            List <Change> todo = new List <Change>(Version.Changes.Where(c => c.IsChecked));

            int    index = 0;
            double count = 4 + todo.Count; // +1 from folder backup above, +1 for read, +1 for version edit, +1 for writing data

            SetPercent?.Invoke(++index / count);



            // read original data & preparation
            byte[]     oriData = File.ReadAllBytes(filePath);
            byte[]     data    = (byte[])oriData.Clone();
            ChangeArgs args    = new ChangeArgs(data, oriData, aivFolder);

            SetPercent?.Invoke(++index / count);



            // change version display in main menu
            var displayResult = Version.MenuChange.Activate(args);

            if (displayResult != EditResult.NoErrors)
            {
                const string str     = "Your version is currently unsupported: {0} in menu display edit.";
                string       message = string.Format(str, displayResult);
                throw new Exception(message);
            }
            SetPercent?.Invoke(++index / count);



            // change stuff
            foreach (Change change in todo)
            {
                change.Activate(args);
                SetPercent?.Invoke(++index / count);
            }



            if (filePath.EndsWith(BackupFileEnding))
            {
                filePath = filePath.Remove(filePath.Length - BackupFileEnding.Length);
            }
            else
            {
                // create backup
                File.WriteAllBytes(filePath + BackupFileEnding, oriData);
            }

            File.WriteAllBytes(filePath, data);
        }
        public static void Install(string filePath, SetPercentHandler SetPercent = null)
        {
            if (!File.Exists(filePath))
            {
                throw new Exception("File not found!");
            }

            SetPercent?.Invoke(0);

            // Do aiv folder backup
            string        dir       = Path.Combine(Path.GetDirectoryName(filePath), "aiv", BackupIdent);
            DirectoryInfo backupDir = new DirectoryInfo(dir);
            DirectoryInfo aivDir    = backupDir.Parent;

            if (backupDir.Exists)
            {
                // restore originals
                foreach (FileInfo fi in backupDir.EnumerateFiles("*.aiv"))
                {
                    fi.CopyTo(Path.Combine(aivDir.FullName, fi.Name), true);
                }

                backupDir.Delete(true);
            }

            DoChanges(filePath, aivDir, SetPercent);
            SetPercent?.Invoke(1);

            if (fails.Count > 0)
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine("The following changes could not be provided probably due to version differences:");
                foreach (var f in fails)
                {
                    sb.AppendLine(f.Value + " " + f.Key);
                }

                Debug.Show(sb.ToString());
            }
        }