private void ExtractFile(string srcPath, string destDir)
 {
     // only works for zip files
     ShowCurrentOperation("Extracting: " + srcPath);
     AssemblyCaller.Call(Path.Combine(tempToolkitDir, APP_CSZIPLIB), "ICSharpCode.SharpZipLib.Zip.FastZip", "ExtractZip", new Type[] { typeof(string), typeof(string), typeof(string) }, new object[] { srcPath, destDir, null });
 }
        /// <summary>
        /// AutoUpdater with command line args for localToolkitDir and tempToolkitDir
        /// </summary>
        public AutoUpdaterForm(string[] args)
        {
            InitializeComponent();

            // force showing autoupdater and progress bar on startup
            this.Show();
            this.Location = new Point(100, 100);
            this.BringToFront();
            ShowCurrentOperation("Starting the AutoUpdater Engine ...");
            pbUpdate.Style = ProgressBarStyle.Marquee;
            pbUpdate.Refresh();
            this.Refresh();

            // catch if there are no cmd line arguments
            if (args.GetLength(0) == 0)
            {
                args = new string[1] {
                    "?"
                }
            }
            ;
            if (args[0].Equals("?"))
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine("Song Creator Toolkit for Rocksmith");
                sb.AppendLine("- commonly known as, 'the toolkit'");
                sb.AppendLine("");
                sb.AppendLine("You are probably seeing this informative message");
                sb.AppendLine("because you started the RocksmithToolkitUpdater.exe");
                sb.AppendLine("application by double clicking on it directly.");
                sb.AppendLine("");
                sb.AppendLine("- Normal Usage:");
                sb.AppendLine("  AutoUpdater is normally run programmatically by the");
                sb.AppendLine("  toolkit to automatically update the toolkit files.");
                sb.AppendLine("");
                sb.AppendLine("- Alternate Usage:");
                sb.AppendLine("  AutoUpdater can be run by double clicking on the");
                sb.AppendLine("  application.  This will force the toolkit to be");
                sb.AppendLine("  updated to the latest available online revision.");
                sb.AppendLine("");
                //sb.AppendLine("- WARNING:");
                //sb.AppendLine("  All user customized toolkit settings are overwritten");
                //sb.AppendLine("  if AutoUpdater is run in the Alternate Usage mode.");
                //sb.AppendLine("  A warning will popup during update to remind you.");
                //sb.AppendLine("");
                sb.AppendLine("Continue running AutoUpdater in Alternate Usage mode?   ");

                if (DialogResult.Yes != MessageBox.Show(sb.ToString(), "AutoUpdater", MessageBoxButtons.YesNo, MessageBoxIcon.Information))
                {
                    Environment.Exit(0);
                }

                // confirm toolkit process is not running before continuing
                Thread.Sleep(500);
                Process[] processesByName = Process.GetProcessesByName("RocksmithToolkitGUI");
                if (processesByName.Length != 0)
                {
                    MessageBox.Show("<ERROR> Detected that RocksmithToolkitGUI is running ..." + Environment.NewLine +
                                    "The toolkit must be closed before running the AutoUpdater.  ", "RocksmithToolkit AutoUpdater", MessageBoxButtons.OK, MessageBoxIcon.Error);

                    Environment.Exit(2);
                }
            }

            // turn on/off debugging MessageBox displays
            isDebugMe      = false;
            isInDesignMode = Helpers.IsInDesignMode;
            appExecPath    = Application.ExecutablePath;
            appExecDir     = Path.GetDirectoryName(appExecPath);
            appExecFile    = Path.GetFileName(appExecPath);
            // if (isInDesignMode) debugMe = true; // overrides initiation

            // running RocksmithToolkitUpdating.exe programatically (Primary Usage Mode)
            if (args.Length == 2 && appExecFile.Equals(APP_UPDATING, StringComparison.InvariantCultureIgnoreCase) || appExecFile.Equals(APP_RSGUI, StringComparison.InvariantCultureIgnoreCase))
            {
                if (isDebugMe)
                {
                    MessageBox.Show("Starting Auto Update ... Primary Usage", "DPDM");
                }

                localToolkitDir = args[0];
                tempToolkitDir  = args[1];
            }
            // running RocksmithToolkitUpdater.exe (Alternate Usage Mode) or developer running project in VS IDE Debug mode
            else if (appExecFile.Equals(APP_UPDATER, StringComparison.InvariantCultureIgnoreCase))
            {
                // the user double clicked on RocksmithToolkitUpdater.exe (w/o cmd line args)
                localToolkitDir = appExecDir;
                tempToolkitDir  = Path.Combine(Path.GetTempPath(), "RocksmithToolkit");

                if (Directory.Exists(tempToolkitDir))
                {
                    Directory.Delete(tempToolkitDir, true);
                }

                Directory.CreateDirectory(tempToolkitDir);

                // copy required files for debugging the AutoUpdater as a standalone project in VS IDE Debug mode
                if (isInDesignMode)
                {
                    if (isDebugMe)
                    {
                        MessageBox.Show("Starting Alternate Usage In Design Mode ...", "DPDM");
                    }

                    try
                    {
                        var rootBinDebugDir = Path.Combine(Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.FullName, "RocksmithTookitGUI\\bin\\Debug");
                        File.Copy(Path.Combine(rootBinDebugDir, APP_CSZIPLIB), Path.Combine(appExecDir, APP_CSZIPLIB), true);
                        File.Copy(Path.Combine(rootBinDebugDir, APP_RSLIB), Path.Combine(appExecDir, APP_RSLIB), true);
                        File.Copy(Path.Combine(rootBinDebugDir, APP_RSGUI), Path.Combine(appExecDir, APP_RSGUI), true);
                        File.Copy(Path.Combine(rootBinDebugDir, REPO_CONFIG), Path.Combine(appExecDir, REPO_CONFIG), true);
                        File.Copy(Path.Combine(rootBinDebugDir, REPO_SONGAPPID), Path.Combine(appExecDir, REPO_SONGAPPID), true);
                        File.Copy(Path.Combine(rootBinDebugDir, REPO_TUNINGDEF), Path.Combine(appExecDir, REPO_TUNINGDEF), true);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("<ERROR> Can not find required file(s) to run AutoUpdater project in VS IDE Debug mode.  " + Environment.NewLine + "Make sure the RocksmithToolkitGUI project has been run in VS IDE Debug mode first. " + Environment.NewLine + Environment.NewLine + ex.Message, "DPDM");

                        Environment.Exit(1);
                    }
                }
                else
                {
                    // use some whacky, hacky, trickery
                    // make a copy of AutoUpdater to prevent locking the process during update
                    var updaterAppPath  = Path.Combine(localToolkitDir, APP_UPDATER);
                    var updatingAppPath = Path.Combine(tempToolkitDir, APP_UPDATING);
                    File.Copy(updaterAppPath, updatingAppPath, true);
                    var cmdArgs = String.Format("\"{0}\" \"{1}\"", localToolkitDir, tempToolkitDir);

                    if (isDebugMe)
                    {
                        MessageBox.Show("Starting Auto Update ... Alternate Usage Release Mode" + Environment.NewLine + "cmdArgs = " + cmdArgs, "DPDM");
                    }

                    var startInfo = new ProcessStartInfo
                    {
                        FileName        = updatingAppPath,
                        Arguments       = cmdArgs,
                        UseShellExecute = false,
                        CreateNoWindow  = true, // hide command window
                    };

                    using (var updater = new Process())
                    {
                        updater.StartInfo = startInfo;
                        updater.Start();
                    }

                    Thread.Sleep(500);
                    // Kill current process (RocksmithToolkitUpdater.exe) now
                    // that new process (RocksmithToolkitUpdating.exe) is started
                    Environment.Exit(0);
                }
            }
            else
            {
                MessageBox.Show("<ERROR> Unexpected updater usage ..." + Environment.NewLine + "appExecFile = " + appExecFile, "RocksmithToolkit AutoUpdater", MessageBoxButtons.OK, MessageBoxIcon.Error);

                Environment.Exit(1);
            }

            localToolkitDirRoot = Path.GetDirectoryName(localToolkitDir);
            // toolkit archive directory/file structure effects newLocalToolkitDir path
            newLocalToolkitDir = Path.Combine(localToolkitDirRoot, "RocksmithToolkit");

            if (isDebugMe)
            {
                MessageBox.Show("IsDesignMode = " + isInDesignMode.ToString() + Environment.NewLine + "Currently running: " + Application.ExecutablePath + Environment.NewLine + "localToolkitDir = " + localToolkitDir + Environment.NewLine + "newlocalToolkitDir = " + newLocalToolkitDir + Environment.NewLine + "localToolkitDirRoot = " + localToolkitDirRoot + Environment.NewLine + "tempToolkitDir = " + tempToolkitDir + Environment.NewLine + "args[0] = " + args[0] + Environment.NewLine + "args[1] = " + args[1], "DPDM");
            }

            // switch progress bar style
            pbUpdate.Style = ProgressBarStyle.Continuous;
            pbUpdate.Value = 0;

            try
            {
                // backup the local process
                BackupProcessDir(localToolkitDir, tempToolkitDir);
            }
            catch (Exception ex)
            {
                MessageBox.Show("<ERROR> Process backup failure ..." + Environment.NewLine + "Please manually download and install the latest toolkit revision." + Environment.NewLine + ex.Message, "RocksmithToolkit AutoUpdater", MessageBoxButtons.OK, MessageBoxIcon.Error);

                Environment.Exit(1);
            }

            try
            {
                // www.rscustom.net/builds/latest.zip or *.tar.gz
                // www.rscustom.net/builds/latest_test.zip or *.tar.gz
                // get latest zip url
                latestZipUrl = (string)AssemblyCaller.Call(Path.Combine(appExecDir, APP_RSLIB), "RocksmithToolkitLib.ToolkitVersionOnline", "GetFileUrl", null, true);

                if (String.IsNullOrEmpty(latestZipUrl))
                {
                    throw new Exception("latestZipUrl is null/empty");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("<ERROR> latestZipUrl AssemblyCaller failure ..." + Environment.NewLine + ex.InnerException.Message, "RocksmithToolkit AutoUpdater", MessageBoxButtons.OK, MessageBoxIcon.Error);

                Environment.Exit(1);
            }

            var latestZipUri = new Uri(latestZipUrl);

            latestZipPath = Path.Combine(tempToolkitDir, Path.GetFileName(latestZipUri.LocalPath));
            DownloadFile(latestZipUri, latestZipPath);

            if (isDebugMe)
            {
                MessageBox.Show("Check backup files: " + tempToolkitDir + Environment.NewLine + "latestZipUri dlStatus: " + dlStatus.ToString() + Environment.NewLine + "latestZipPath: " + latestZipPath, "DPDM");
                //ExtractFile(latestZipPath, localToolkitDirRoot);
                //MessageBox.Show("Check ExtractFile destination: " + localToolkitDirRoot, "DPDM");
                //MergeXmlRepository(tempToolkitDir, newLocalToolkitDir);
                //MessageBox.Show("Check MergeXmlRepository destination: " + newLocalToolkitDir, "DPDM");
            }

            if (dlStatus == DownloadStatus.SUCCESS && File.Exists(latestZipPath))
            {
                // bulldoze the local process directory
                if (args.Length == 2 && appExecFile.Equals(APP_UPDATING, StringComparison.InvariantCultureIgnoreCase))
                {
                    var lockedLocalFiles = DeleteDirectory(localToolkitDir);
                    if (lockedLocalFiles.Any())
                    {
                        ShowCurrentOperation("<WARNING> localToolkitDir cleanup failed ...");
                        if (!ShowLockedFilesAndContinue(lockedLocalFiles))
                        {
                            Environment.Exit(1);
                        }
                    }
                }

                try
                {
                    // extract latest toolkit revision to the localToolkitDirRoot
                    // revised archive directory structure to be more like an installer
                    ExtractFile(latestZipPath, localToolkitDirRoot);

                    if (isDebugMe)
                    {
                        MessageBox.Show("Check unzipped files in: " + localToolkitDirRoot, "DPDM");
                    }
                }
                catch (Exception ex)
                {
                    if (DialogResult.No == MessageBox.Show("<ERROR> Could not unzip file: " + Path.GetFileName(latestZipPath) + Environment.NewLine +
                                                           "The AutoUpdater can not continue." + Environment.NewLine +
                                                           "Do you want to roll back the installation process?" + Environment.NewLine +
                                                           ex.Message, "RocksmithToolkit AutoUpdater", MessageBoxButtons.YesNo, MessageBoxIcon.Error))
                    {
                        Environment.Exit(1);
                    }

                    // rollback the process to its original state
                    DeleteDirectory(newLocalToolkitDir);
                    if (!Directory.Exists(localToolkitDir))
                    {
                        Directory.CreateDirectory(localToolkitDir);
                    }

                    RollBack(tempToolkitDir, localToolkitDir);
                    RestartToolkitGUI(localToolkitDir);
                }

                try
                {
                    // merge xml repo files
                    MergeXmlRepository(tempToolkitDir, newLocalToolkitDir);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("<ERROR> Could not merge repositories ... " + Environment.NewLine + ex.Message, "RocksmithToolkit AutoUpdater", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

                // merge cgm inlay files
                var cgmFiles = Directory.EnumerateFiles(Path.Combine(tempToolkitDir, "cgm"), "*", SearchOption.AllDirectories);
                foreach (var cgmFile in cgmFiles)
                {
                    try
                    {
                        File.Copy(cgmFile, cgmFile.Replace(tempToolkitDir, newLocalToolkitDir));
                    }
                    catch { /* Do nothing */ }
                }

                // TODO: merge custom/user dds xml/cfg files

                // cleanup tempToolkitDir
                var lockedTempFiles = DeleteDirectory(tempToolkitDir);
                if (lockedTempFiles.Any())
                {
                    ShowCurrentOperation("<WARNING> tempToolkitDir cleanup failed ...");
                    if (!ShowLockedFilesAndContinue(lockedTempFiles))
                    {
                        Environment.Exit(1);
                    }
                }
            }

            if (File.Exists(latestZipPath))
            {
                File.Delete(latestZipPath);
            }

            if (localToolkitDir != newLocalToolkitDir)
            {
                // find open localToolkitDir and attempt to close it so it can be deleted
                var shellWindows = new SHDocVw.ShellWindows();
                foreach (SHDocVw.InternetExplorer shellWindow in shellWindows)
                {
                    var processType      = Path.GetFileNameWithoutExtension(shellWindow.FullName).ToLower();
                    var cleanLocationUrl = shellWindow.LocationURL.ToLower().Replace(@"/", @"\");
                    if (processType.Equals("explorer") && cleanLocationUrl.Contains(localToolkitDir.ToLower()))
                    {
                        shellWindow.Quit();
                        Thread.Sleep(100);
                        shellWindow.Quit();
                        Thread.Sleep(100);

                        MessageBox.Show("The old local toolkit directory should now be closed: " + Environment.NewLine +
                                        localToolkitDir + Environment.NewLine + Environment.NewLine +
                                        "Manually close the directory if it is still open" + Environment.NewLine +
                                        "before pressing 'OK' to continue.  The old toolkit" + Environment.NewLine +
                                        "may be deleted after the update finishes ...", "Close Toolkit Directory ...", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                        break;
                    }
                }

                // attempt to delete the closed directory
                DeleteDirectory(localToolkitDir);
            }

            if (isDebugMe)
            {
                MessageBox.Show("Before Restart: " + Environment.NewLine +
                                "Check localToolkitDir deleted: " + localToolkitDir + Environment.NewLine +
                                "Check tempToolkitDir deleted: " + tempToolkitDir + Environment.NewLine +
                                "Check latestZipPath deleted: " + latestZipPath, "DPDM");
            }

            ShowCurrentOperation("Please wait ... Restarting ToolkitGUI ...");
            Thread.Sleep(1000); // settle down before restart
            RestartToolkitGUI(newLocalToolkitDir);
        }
 public void ExtractFile(string output)   //works only for ZIP files.
 {
     AssemblyCaller.Call(Path.Combine(workDir, APP_CSZIP), "ICSharpCode.SharpZipLib.Zip.FastZip", "ExtractZip", new Type[] { typeof(string), typeof(string), typeof(string) }, new object[] { localFile, output, null });
 }