/// <summary>
 /// The serialize.
 /// </summary>
 /// <param name="mod">
 /// The mod.
 /// </param>
 /// <returns>
 /// The <see cref="string"/>.
 /// </returns>
 public static string Serialize(BackupEntry entry)
 {
     return JsonConvert.SerializeObject(entry);
 }
        /// <summary>
        /// The apply changes.
        /// </summary>
        public void ApplyChanges(BundleMod[] toAddModsList, bool method)
        {
            this.Done = false;
            using (this.Zip = new ZipFile(this._zipPath))
            {
                bool wasSuccessful = false;
                this._mod.ItemQueue.RemoveWhere(i => i.BundleExtension == 0xAB2664BF82E646UL);
                this._mod.ItemQueue.RemoveWhere(i => i.BundleExtension == 0xAB2664BF82E6460C);
                this._mod.ItemQueue.RemoveWhere(i => i.BundleExtension == 0x29104BC4AC649965);

                if (!this.LocateChangeIds())
                    return;

                var toRemove = this._mod.ItemQueue.Where(p => p.toRemove);
                //var toReinstall = this._mod.ItemQueue.Where(p => p.toReinstall);
                var toInstall = this._mod.ItemQueue.Where(p => !p.toRemove);

                if (this._overrideFolder)
                {
                    this.SetTotalProgress("Utilizing Override Folder", -1);

                    HashSet<BundleEntryPath> toSharedFolder = new HashSet<BundleEntryPath>();
                    HashSet<BundleEntryPath> overrideApplied = new HashSet<BundleEntryPath>();
                    Dictionary<BundleEntryPath, HashSet<BundleRewriteItem>> bep_sorted = new Dictionary<BundleEntryPath, HashSet<BundleRewriteItem>>();

                    foreach (BundleRewriteItem bri in this._mod.ItemQueue)
                    {
                        if (bri.toRemove)
                            continue;

                        if (bep_sorted.ContainsKey(bri.getBundleEntryPath()))
                        {
                            if (this._overrideFolderShared && !toSharedFolder.Contains(bri.getBundleEntryPath()))
                                toSharedFolder.Add(bri.getBundleEntryPath());
                            bep_sorted[bri.getBundleEntryPath()].Add(bri);
                        }
                        else
                        {
                            HashSet<BundleRewriteItem> newbrihs = new HashSet<BundleRewriteItem>();
                            newbrihs.Add(bri);
                            bep_sorted.Add(bri.getBundleEntryPath(), newbrihs);
                        }
                    }

                    HashSet<BundleRewriteItem> reducedItemQueue = new HashSet<BundleRewriteItem>();
                    int override_count = 1;
                    foreach (BundleRewriteItem bri in this._mod.ItemQueue)
                    {
                        this.SetBundleProgress(
                            string.Format("Processing {0}/{1}", override_count, this._mod.ItemQueue.Count),
                            (int)((override_count / (float)this._mod.ItemQueue.Count) * 100.0f));

                        if (bri.isOverrideable()
                            //&& !bri.ReplacementFile.EndsWith(".script")
                            )
                        {

                            if (!string.IsNullOrEmpty(StaticStorage.Known_Index.GetPath(bri.BundlePath)) &&
                                !string.IsNullOrEmpty(StaticStorage.Known_Index.GetExtension(bri.BundleExtension))
                                )
                            {
                                string extrname = "";
                                extrname += StaticStorage.Known_Index.GetPath(bri.BundlePath);
                                extrname += "." + StaticStorage.Known_Index.GetExtension(bri.BundleExtension);

                                string modName = bri.getEscapedName();

                                if (bri.toRemove)
                                {
                                    if (!toSharedFolder.Contains(bri.getBundleEntryPath()) && File.Exists(Path.Combine(this._assetFolder, "mod_overrides", "Bundle_Modder_Shared", extrname)))
                                        File.Delete(Path.Combine(this._assetFolder, "mod_overrides", "Bundle_Modder_Shared", extrname));
                                    else if (File.Exists(Path.Combine(this._assetFolder, "mod_overrides", modName, extrname)))
                                        File.Delete(Path.Combine(this._assetFolder, "mod_overrides", modName, extrname));

                                    DeleteEmptyDirs(Path.Combine(this._assetFolder, "mod_overrides", modName));
                                }
                                else
                                {
                                    if (bri.toReinstall)
                                    {
                                        if (File.Exists(Path.Combine(this._assetFolder, "mod_overrides", modName, extrname)))
                                            File.Delete(Path.Combine(this._assetFolder, "mod_overrides", modName, extrname));
                                    }

                                    String path;
                                    if (this._overrideFolderShared && toSharedFolder.Contains(bri.getBundleEntryPath()))
                                        path = Path.Combine(this._assetFolder, "mod_overrides", "Bundle_Modder_Shared", extrname);
                                    else
                                        path = Path.Combine(this._assetFolder, "mod_overrides", modName, extrname);

                                    if (!Directory.Exists(Path.GetDirectoryName(path)))
                                        Directory.CreateDirectory(Path.GetDirectoryName(path));

                                    HashSet<BundleRewriteItem> bep_items = new HashSet<BundleRewriteItem>();
                                    if (bep_sorted.ContainsKey(bri.getBundleEntryPath()))
                                        bep_items = bep_sorted[bri.getBundleEntryPath()];

                                    var outOverride = new FileStream(
                                                    path,
                                                    FileMode.Create,
                                                    FileAccess.ReadWrite);

                                    int runningcount = 0;
                                    foreach (var item in bep_items)
                                    {
                                        if (item.SourceFile != null)
                                        {
                                            if(this.Zip == null)
                                                this.Zip = new ZipFile(item.SourceFile);

                                            if (!this.Zip.Name.Equals(item.SourceFile))
                                            {
                                                this.Zip.Dispose();
                                                this.Zip = new ZipFile(item.SourceFile);
                                            }
                                        }
                                        else
                                            continue;

                                        ZipEntry zip_entry = this.Zip[item.ReplacementFile];
                                        if (zip_entry != null)
                                        {
                                            if (zip_entry.UsesEncryption)
                                            {
                                                zip_entry.Password = "******";
                                                //zip_entry.Encryption = EncryptionAlgorithm.WinZipAes256;
                                            }

                                            MemoryStream zipEntryData = new MemoryStream();

                                            if (item.ReplacementFile.EndsWith(".script"))
                                            {
                                                MemoryStream scriptData = new MemoryStream();
                                                zip_entry.Extract(scriptData);
                                                scriptData.Seek(0, SeekOrigin.Begin);
                                                MemoryStream bundleData = new MemoryStream();

                                                if (RetrieveFile(item, out bundleData))
                                                {
                                                    if (runningcount > 0)
                                                    {
                                                        bundleData.SetLength(0);
                                                        outOverride.Seek(0, SeekOrigin.Begin);
                                                        outOverride.CopyTo(bundleData);
                                                    }

                                                    StreamReader scriptStream = new StreamReader(scriptData);

                                                    List<BundleRewriteScriptAction> scriptActions = ParseScriptActions(ref scriptStream, zip_entry.FileName);
                                                    scriptData.Close();
                                                    scriptStream.Close();

                                                    //apply script functions here
                                                    bundleData.Seek(0, SeekOrigin.Begin);

                                                    List<byte> entryBytes = bundleData.ToArray().ToList();

                                                    outOverride.Seek(0, SeekOrigin.Begin);
                                                    ApplyScriptActions(ref entryBytes, ref scriptActions);

                                                    foreach (byte b in entryBytes)
                                                        outOverride.WriteByte(b);

                                                }
                                                else
                                                {
                                                    reducedItemQueue.Add(item);
                                                }
                                            }
                                            else
                                            {
                                                outOverride.Position = 0L;
                                                zipEntryData.Position = 0L;
                                                zip_entry.Extract(zipEntryData);
                                                zipEntryData.Position = 0L;
                                                zipEntryData.CopyTo(outOverride, this.bufferSize);
                                                //foreach (byte b in zipEntryData.ToArray().ToList())
                                                //    outOverride.WriteByte(b);
                                            }

                                            outOverride.Flush();

                                        }
                                        runningcount++;
                                    }

                                    outOverride.Close();
                                }
                            }
                            else
                            {
                                reducedItemQueue.Add(bri);
                            }

                        }
                        else
                        {
                            if (this._overrideFolderDummies)
                            {
                                string modName = bri.ModName;
                                modName = Path.GetInvalidFileNameChars().Aggregate(modName, (current, c) => current.Replace(c.ToString(), "_"));

                                if (bri.toRemove)
                                {
                                    if (Directory.Exists(Path.Combine(this._assetFolder, "mod_overrides", modName)))
                                    {
                                        //Directory.Delete(Path.Combine(this._assetFolder, "mod_overrides", modName), true);
                                        DeleteDirectory(Path.Combine(this._assetFolder, "mod_overrides", modName));
                                    }
                                }
                                else
                                {
                                    if (!Directory.Exists(Path.Combine(this._assetFolder, "mod_overrides", modName)))
                                        Directory.CreateDirectory(Path.Combine(this._assetFolder, "mod_overrides", modName));
                                }
                            }

                            reducedItemQueue.Add(bri);
                        }
                        override_count++;
                    }

                    this.SetBundleProgress("Done", 100);
                    this._mod.ItemQueue = reducedItemQueue;
                }

                HashSet<string> bundles = this.LocateBundlesToRewrite(out wasSuccessful);
                if (!wasSuccessful)
                    return;

                if (!this._patchAllBundles)
                    bundles.RemoveWhere(i => i.StartsWith("all_"));

                if (bundles.Count <= 0 && !this._overrideFolder)
                {
                    this.Error = "Unable to locate any bundles with the requested items in them.\n"
                                 + "If the changed file(s) only exists within an all_x.bundle file you will need to enable the option to patch all_x.bundle files.\n"
                                 + "Refer to the patch description for if this is required.";
                    return;
                }

                this.SetTotalProgress("Backing up Bundles", -1);
                this.CurrentBundlesCount = 1;
                this.TotalBundlesCount = bundles.Count;
                foreach (var bundle in bundles)
                {

                    this.SetBundleProgress(
                        string.Format("Backing up Bundle {0}/{1}", this.CurrentBundlesCount, this.TotalBundlesCount),
                        (int)((this.CurrentBundlesCount / (float)this.TotalBundlesCount) * 100.0f));

                    if (this._backupType == 1)
                    {
                        this.BackupEntries(this._mod, Path.Combine(this._assetFolder, bundle));
                    }
                    else
                    {
                        this.BackupFile(Path.Combine(this._assetFolder, bundle + "_h.bundle"));
                        this.BackupFile(Path.Combine(this._assetFolder, bundle + ".bundle"));
                    }
                    this.CurrentBundlesCount += 1;

                }

                foreach (BundleMod bm in toAddModsList)
                {
                    BackupEntry multibackupEntry = new BackupEntry();
                    multibackupEntry.Name = bm.Name;
                    multibackupEntry.Author = bm.Author;
                    multibackupEntry.Description = bm.Description;
                    multibackupEntry.BackupType = (this._backupType == 0) ? "Bundles" : "Bundle Entries";
                    multibackupEntry.InstallDate = DateTime.Now;
                    multibackupEntry.RewriteAll = this._patchAllBundles;
                    HashSet<BundleRewriteItem> backupQueue = new HashSet<BundleRewriteItem>();

                    foreach (BundleRewriteItem bri in bm.ItemQueue)
                    {
                        BundleRewriteItem newbri = new BundleRewriteItem();
                        newbri.BundleExtension = bri.BundleExtension;
                        newbri.BundleLanguage = bri.BundleLanguage;
                        newbri.BundlePath = bri.BundlePath;
                        newbri.Ids = bri.Ids;
                        newbri.IsLanguageSpecific = bri.IsLanguageSpecific;
                        if (this._backupType == 0)
                            newbri.ReplacementFile = bri.ReplacementFile;
                        else
                            newbri.ReplacementFile = bri.BundlePath.ToString("x") + '.' + bri.BundleLanguage.ToString("x") + '.' + bri.BundleExtension.ToString("x");
                        newbri.SourceFile = bri.SourceFile;

                        backupQueue.Add(newbri);
                    }
                    multibackupEntry.ItemQueue = backupQueue;
                    backupEntries.Add(multibackupEntry);
                }
                allowBackup = true;

                foreach (var rewriteItem in this._mod.ItemQueue)
                {
                    foreach (var id in rewriteItem.Ids)
                    {
                        if (this._rewriteItems.ContainsKey(id))
                        {
                            if (rewriteItem.toRemove)
                                this._rewriteItems[id].toRestore = true;

                            if (rewriteItem.ReplacementFile.EndsWith(".script"))
                            {
                                this._rewriteItems[id].BundleRewriteItem_queue.Add(rewriteItem);
                            }
                            else
                            {
                                if (rewriteItem.priority)
                                {
                                    this._rewriteItems[id].priorityBundleRewriteItem = rewriteItem;
                                }
                                else
                                {
                                    //Don't add... it's not part of priority
                                    this._rewriteItems[id].BundleRewriteItem_queue.Add(rewriteItem);
                                }
                            }
                        }
                        else
                        {
                            BundleRewriteEntryID breid = new BundleRewriteEntryID();

                            if (rewriteItem.toRemove)
                                breid.toRestore = true;

                            if (rewriteItem.ReplacementFile.EndsWith(".script"))
                            {
                                breid.BundleRewriteItem_queue.Add(rewriteItem);
                            }
                            else
                            {
                                if (rewriteItem.priority)
                                {
                                    breid.priorityBundleRewriteItem = rewriteItem;
                                }
                                else
                                {
                                    //Don't add, it's not part of priority
                                    breid.BundleRewriteItem_queue.Add(rewriteItem);
                                }
                            }

                            this._rewriteItems.Add(id, breid);
                        }
                    }
                }

                this.CurrentBundlesCount = 1;
                TotalElapsedTime.Start();
                SpeedElapsedTime.Start();

                foreach (var bundle in bundles)
                {
                    CurrentBundle = bundle;
                    this.SetTotalProgress(
                        string.Format("Patching Bundle {0}/{1}", this.CurrentBundlesCount, this.TotalBundlesCount),
                        (int)((this.CurrentBundlesCount / (float)this.TotalBundlesCount) * 100.0f));
                    if (!this.PatchBundle(bundle))
                        return;

                    this.CurrentBundlesCount += 1;
                }
                TotalElapsedTime.Stop();
                SpeedElapsedTime.Stop();
            }
            this.Zip.Dispose();
            this.SetTotalProgress("Done", 100);
            this.Done = true;
        }
 /// <summary>
 /// The serialize.
 /// </summary>
 /// <param name="mod">
 /// The mod.
 /// </param>
 /// <returns>
 /// The <see cref="string"/>.
 /// </returns>
 public static string Serialize(BackupEntry entry)
 {
     return(JsonConvert.SerializeObject(entry));
 }
        /// <summary>
        /// The apply mods.
        /// </summary>
        public void ApplyMods(BundleMod[] toAddModsList)
        {
            this.Done = false;
            using (this.Zip = new ZipFile(this._zipPath))
            {
                bool wasSuccessful = false;
                this._mod.ItemQueue.RemoveWhere(i => i.BundleExtension == 0xAB2664BF82E646UL);
                this._mod.ItemQueue.RemoveWhere(i => i.BundleExtension == 0xAB2664BF82E6460C);
                this._mod.ItemQueue.RemoveWhere(i => i.BundleExtension == 0x29104BC4AC649965);

                if (!this.LocateChangeIds())
                    return;

                HashSet<string> bundles = this.LocateBundlesToRewrite(out wasSuccessful);
                if (!wasSuccessful)
                    return;

                if (!this._patchAllBundles)
                    bundles.RemoveWhere(i => i.StartsWith("all_"));

                if (bundles.Count <= 0)
                {
                    this.Error = "Unable to locate any bundles with the requested items in them.\n"
                                 + "If the changed file(s) only exists within an all_x.bundle file you will need to enable the option to patch all_x.bundle files.\n"
                                 + "Refer to the patch description for if this is required.";
                    return;
                }

                this.SetTotalProgress("Backing up Bundles", -1);
                this.CurrentBundlesCount = 1;
                this.TotalBundlesCount = bundles.Count;
                foreach (var bundle in bundles)
                {

                    this.SetBundleProgress(
                        string.Format("Backing up Bundle {0}/{1}", CurrentBundlesCount, TotalBundlesCount),
                        (int)((CurrentBundlesCount / (float)TotalBundlesCount) * 100.0f));

                    if (this._backupType == 1)
                    {
                        this.BackupEntries(this._mod, Path.Combine(this._assetFolder, bundle));
                    }
                    else
                    {
                        this.BackupFile(Path.Combine(this._assetFolder, bundle + "_h.bundle"));
                        this.BackupFile(Path.Combine(this._assetFolder, bundle + ".bundle"));
                    }
                    CurrentBundlesCount += 1;

                }

                foreach (BundleMod bm in toAddModsList)
                {
                    BackupEntry multibackupEntry = new BackupEntry();
                    multibackupEntry.Name = bm.Name;
                    multibackupEntry.Author = bm.Author;
                    multibackupEntry.Description = bm.Description;
                    multibackupEntry.BackupType = (this._backupType == 0) ? "Bundles" : "Bundle Entries";
                    multibackupEntry.InstallDate = DateTime.Now;
                    multibackupEntry.RewriteAll = this._patchAllBundles;
                    HashSet<BundleRewriteItem> backupQueue = new HashSet<BundleRewriteItem>();

                    foreach (BundleRewriteItem bri in bm.ItemQueue)
                    {
                        BundleRewriteItem newbri = new BundleRewriteItem();
                        newbri.BundleExtension = bri.BundleExtension;
                        newbri.BundleLanguage = bri.BundleLanguage;
                        newbri.BundlePath = bri.BundlePath;
                        newbri.Ids = bri.Ids;
                        newbri.IsLanguageSpecific = bri.IsLanguageSpecific;
                        if (this._backupType == 0)
                            newbri.ReplacementFile = bri.ReplacementFile;
                        else
                            newbri.ReplacementFile = bri.BundlePath.ToString("x") + '.' + bri.BundleLanguage.ToString("x") + '.' + bri.BundleExtension.ToString("x");
                        newbri.SourceFile = bri.SourceFile;

                        backupQueue.Add(newbri);
                    }
                    multibackupEntry.ItemQueue = backupQueue;
                    backupEntries.Add(multibackupEntry);
                }
                allowBackup = true;

                CurrentBundlesCount = 1;
                TotalElapsedTime.Start();
                foreach (var bundle in bundles)
                {
                    this.SetTotalProgress(
                        string.Format("Patching Bundle {0}/{1}", CurrentBundlesCount, TotalBundlesCount),
                        (int)((CurrentBundlesCount / (float)TotalBundlesCount) * 100.0f));
                    if (!this.PatchBundle(bundle))
                        return;

                    CurrentBundlesCount += 1;
                }
                TotalElapsedTime.Stop();
            }
            this.SetTotalProgress("Done", 100);
            this.Done = true;
        }