/// <summary>
        /// This will simulate the mod installation and decide installation choices and files final paths.
        /// </summary>
        /// <param name="modArchiveFileList">The list of files inside the mod archive.</param>
        /// <param name="stopPatterns">patterns matching files or directories that should be at the top of the directory structure.</param>
        /// <param name="scriptPath">The path to the uncompressed install script file, if any.</param>
        /// <param name="progressDelegate">A delegate to provide progress feedback.</param>
        /// <param name="coreDelegate">A delegate for all the interactions with the js core.</param>
        public async override Task <Dictionary <string, object> > Install(List <string> modArchiveFileList,
                                                                          List <string> stopPatterns,
                                                                          string pluginPath,
                                                                          string scriptPath,
                                                                          ProgressDelegate progressDelegate,
                                                                          CoreDelegates coreDelegate)
        {
            IList <Instruction> Instructions  = new List <Instruction>();
            ModFormatManager    FormatManager = new ModFormatManager();
            string ScriptFilePath             = null;

            try
            {
                ScriptFilePath = new List <string>(await GetRequirements(modArchiveFileList, false)).FirstOrDefault();
            }
            catch (UnsupportedException)
            {
                // not an error, this can handle mods without an installer script (see BasicModInstall)
            }
            IScriptType ScriptType = await GetScriptType(modArchiveFileList);

            Mod modToInstall = new Mod(modArchiveFileList, stopPatterns, ScriptFilePath, scriptPath, ScriptType);
            await modToInstall.Initialize();

            progressDelegate(50);

            if (modToInstall.HasInstallScript)
            {
                Instructions = await ScriptedModInstall(modToInstall, progressDelegate, coreDelegate);

                if (Instructions == null)
                {
                    Instructions = new List <Instruction>();
                    Instructions.Add(Instruction.InstallError("Installer failed (it should have reported an error message)"));
                }
                else
                {
                    // f***ing ugly hack, but this is in NMM so...
                    if (pluginPath != null)
                    {
                        string pattern = pluginPath + Path.DirectorySeparatorChar;
                        Instructions = Instructions.Select(instruction =>
                        {
                            Instruction output = instruction;
                            if ((output.type == "copy") && output.destination.StartsWith(pattern, System.StringComparison.InvariantCultureIgnoreCase))
                            {
                                output.destination = output.destination.Substring(pattern.Length);
                            }
                            return(output);
                        }).ToList();
                    }
                }
            }
            else
            {
                Instructions = await BasicModInstall(modArchiveFileList, stopPatterns, progressDelegate, coreDelegate);
            }

            progressDelegate(100);

            return(new Dictionary <string, object>
            {
                { "message", "Installation successful" },
                { "instructions", Instructions }
            });
        }
        /// <summary>
        /// This function will return the list of files requirements to complete this mod's installation.
        /// <param name="modFiles">The list of files inside the mod archive.</param>
        /// <param name="includeAssets">If true, the result will also include all assets required by the
        ///   installer (i.e. screenshots). Otherwise the result should only be one file which is the
        ///   installer script</param>
        /// </summary>
        protected async Task <IList <string> > GetRequirements(IList <string> modFiles, bool includeAssets)
        {
            ModFormatManager FormatManager = new ModFormatManager();

            return(await FormatManager.GetRequirements(modFiles, includeAssets));
        }
        /// <summary>
        /// This function will return the list of files requirements to complete this mod's installation.
        /// <param name="modFiles">The list of files inside the mod archive.</param>
        /// </summary>
        protected async Task <IScriptType> GetScriptType(IList <string> modFiles)
        {
            ModFormatManager FormatManager = new ModFormatManager();

            return(await FormatManager.GetScriptType(modFiles));
        }
        /// <summary>
        /// This function will return the list of files requirements to complete this mod's installation.
        /// <param name="modFiles">The list of files inside the mod archive.</param>
        /// </summary>
        protected async Task <IScriptType> GetScriptType(IList <string> modFiles, string extractedFilePath = null)
        {
            ModFormatManager FormatManager = new ModFormatManager();

            return(await FormatManager.GetScriptType(modFiles, extractedFilePath));
        }