//
        // Called during early stage toolset deinitialization.
        //

        virtual public void Unload(INWN2PluginHost Host)
        {
            ListView Lv;

            //
            // Early toolset teardown; deinitialize the script compiler hook so
            // that we may unload cleanly.
            //

            Lv = PluginUI.GetVerifyOutputListView();

            if (Lv != null)
            {
                Lv.ItemActivate -= this.OnVerifyOutputListViewItemActivated;
            }

            UnhookScriptCompiler();

            if (NWN2ToolsetMainForm.VersionControlManager.Preferences != null)
            {
                if (NWN2ToolsetMainForm.VersionControlManager.Preferences.ActiveProvider == this)
                {
                    NWN2ToolsetMainForm.VersionControlManager.Preferences.ActiveProvider = m_OriginalVCPlugin;
                }

                m_OriginalVCPlugin = null;
            }

            m_SettingsManager = null;
        }
        //
        // Standard INWN2Plugin methods.
        //

        //
        // Called during late stage toolset initialization.
        //

        virtual public void Load(INWN2PluginHost Host)
        {
            ListView Lv;

            m_SettingsManager = new SettingsManager();
            m_SettingsManager.NeedSettingsLoad = true;

            //
            // By the time Load is invoked, the compiler is present.  Install
            // the compiler hook now.
            //

            m_CompilerField = GetMainFormCompilerField();

            m_ResourceAccessor = new ResourceAccessor(this);

            HookScriptCompiler();

            //
            // Hook the version control system for resource change notification
            // distribution if preferences were available at this point.
            //
            // Otherwise, wait for a change notification to install the hook.
            //
            //

            if (NWN2ToolsetMainForm.VersionControlManager.Preferences != null)
            {
                m_OriginalVCPlugin = NWN2ToolsetMainForm.VersionControlManager.Preferences.ActiveProvider;

                if (m_OriginalVCPlugin == this)
                {
                    m_OriginalVCPlugin = null;
                }

                NWN2ToolsetMainForm.VersionControlManager.Preferences.ActiveProvider = this;
            }
            else
            {
                NWN2Toolset.Plugins.NWN2VersionControlManagerPreferences.PreferencesChanged += this.OnVersionControlManagerPrefsChanged;
            }

            Lv = PluginUI.GetVerifyOutputListView();

            if (Lv != null)
            {
                Lv.ItemActivate += this.OnVerifyOutputListViewItemActivated;
            }
        }
        ///////////////////////////////////////////////////////////////////////

        //
        // Display compilation messages.
        //

        void ShowCompilerMessages(string Script, string Message)
        {
            bool First = false;

            if (Message.IndexOf('\n') != 0)
            {
                Message += "\n";
            }

            PluginUI.AddVerifyResult(
                NWN2Toolset.Plugins.NWN2VerifyOutputType.Information,
                "Compiler diagnostics for script " + Script + ":");

            foreach (string Msg in Message.Split('\n'))
            {
                bool NonWhitespaceFound = false;
                NWN2Toolset.Plugins.NWN2VerifyOutputType MessageType;

                for (int i = 0; i < Msg.Length; i += 1)
                {
                    if (!Char.IsWhiteSpace(Msg, i))
                    {
                        NonWhitespaceFound = true;
                        break;
                    }
                }

                if (!NonWhitespaceFound)
                {
                    continue;
                }

                if (Msg.IndexOf("Warning: ") != -1)
                {
                    MessageType = NWN2Toolset.Plugins.NWN2VerifyOutputType.Warning;
                }
                else
                {
                    MessageType = NWN2Toolset.Plugins.NWN2VerifyOutputType.Error;
                }

                PluginUI.AddVerifyResult(
                    MessageType,
                    Msg,
                    First);

                First = false;
            }
        }
 public void OnResourceIndexingFinish(ResourceAccessor Accessor)
 {
     PluginUI.AddVerifyResult(
         NWN2VerifyOutputType.Information,
         "Advanced script compiler: Completed resource indexing (" + Accessor.GetEncapsulatedFileCount().ToString() + " resources in resource system).");
 }
        //
        // Compile a source file.
        //

        public virtual string CompileFile(string Name, string OutputDirectory)
        {
            //
            // Make sure that the resource index is up to date, then attempt
            // the compilation.
            //

            m_ResourceAccessor.EnsureIndexValid();

            try
            {
                string Warnings;
                string Errors;

                m_SettingsManager.LoadSettings();

                Errors = m_NscCompiler.CompileScript(
                    Name,
                    OutputDirectory,
                    m_StandardCompiler.GenerateDebugInfo,
                    out Warnings);

                if (Warnings.Length != 0)
                {
                    ShowCompilerMessages(Name, Warnings);
                }
                else if (Errors.Length != 0)
                {
                    ShowCompilerMessages(Name, Errors);
                }

                //
                // If we have errors, find the first error and make it the
                // one reported as the output control only shows one line
                // anyway.  The rest are dumped to the verify window.
                //

                if (Errors.Length != 0)
                {
                    foreach (string Msg in Errors.Split('\n'))
                    {
                        if (Msg.IndexOf("Error: ") == -1)
                        {
                            continue;
                        }

                        Errors  = Msg;
                        Errors += " (see verify window for full context)";
                        break;
                    }
                }
                else
                {
                    //
                    // GUI scripts must compile with the stock compiler, as
                    // they are parsed at runtime.  Not all of the quirks of
                    // the stock compiler throw errors with the new compiler,
                    // so verify that these are no errors with the stock
                    // compiler (too).  Since this is a performance hit and is
                    // only necessary for GUI scripts, don't do it for other
                    // ones.
                    //

                    if (m_NscCompiler.LastCompiledScriptNeedsRuntimeCompilation(Name) &&
                        !m_SettingsManager.EnableExtensions)
                    {
                        System.IO.Directory.CreateDirectory(OutputDirectory + "\\__tempscript__");

                        Errors = m_StandardCompiler.CompileFile(Name, OutputDirectory + "\\__tempscript__");

                        if (Errors.Length != 0)
                        {
                            Errors += "Error: Script " + Name + " requires runtime compilation and errors were detected with the standard compiler.\n";
                            ShowCompilerMessages(Name, Errors);
                        }

                        System.IO.File.Delete(OutputDirectory + "\\__tempscript__\\" + Name + ".ncs");
                        System.IO.File.Delete(OutputDirectory + "\\__tempscript__\\" + Name + ".ndb");
                        System.IO.Directory.Delete(OutputDirectory + "\\__tempscript__", false);
                    }
                }

                return(Errors);
            }
            catch (Exception e)
            {
                //
                // If calling the native compiler failed, i.e. the support DLL
                // wasn't found, then just fall back to the built-in compiler.
                //

                PluginUI.AddVerifyResult(
                    NWN2Toolset.Plugins.NWN2VerifyOutputType.Warning,
                    "Advanced script compiler: NscCompileScript failed to execute, falling back to standard script compiler - exception: " + e.ToString());

                return(m_StandardCompiler.CompileFile(Name, OutputDirectory));
            }
        }
        //
        // Index the OEI resource system into the internal table.
        //

        private void DiscoverResources()
        {
            List <IResourceRepository> Repositories;
            ResourceManager            ResMan = ResourceManager.Instance;

            if (m_Plugin != null)
            {
                m_Plugin.OnResourceIndexingStart(this);
            }

            //
            // Create the canonical ordering of resource repositories.
            //

            Repositories = GetResourceRepositories();

            //
            // Index the entire toolset resource system now.
            //
            // The repository list is sorted in most precedent order, that is,
            // the first entry was the most recently added.  However, the
            // resource list is sorted in least precedent order, that is, the
            // first entry was the last one added.
            //

            foreach (IResourceRepository ToolsetRepository in Repositories)
            {
                int MaxId;

                MaxId = ToolsetRepository.Resources.Count;

#if DBGRESOURCE
                PluginUI.AddVerifyResult(
                    NWN2Toolset.Plugins.NWN2VerifyOutputType.Information,
                    "Resource repository: " + ToolsetRepository.Name);
#endif

                //
                // Iterate over each file, creating file entries for each
                // resource type in turn.
                //
                // We search in reverse order, taking the last entry.  This
                // allows us to preserve the order of the most recent entry of
                // a particular tier winning, ensuring that we retrieve the
                // most precedent patched file for inbox datafiles.
                //

                for (int i = MaxId; i != 0; i -= 1)
                {
                    ResourceIndex  Index;
                    int            ExistingIndex;
                    ResourceKey    Key;
                    IResourceEntry ToolsetEntry;

                    ToolsetEntry = ToolsetRepository.Resources[i - 1];

                    Index.FileIndex = i - 1;
                    Index.Entry     = ToolsetEntry;

                    //
                    // Ensure that we have not already claimed this name yet.
                    // We allow only one mapping for a particular name (+type),
                    // and it is the most precedent one in the canonical search
                    // order.
                    //

                    Key.Name = ToolsetEntry.ResRef.Value;
                    Key.Type = ToolsetEntry.ResourceType;

                    //
                    // Skip duplicate entry, we've already found the most
                    // precedent version.
                    //

                    if (m_NameIdMap.TryGetValue(Key, out ExistingIndex))
                    {
                        continue;
                    }

                    //
                    // First one, add it as the most precedent.
                    //

                    m_ResourceEntries.Add(Index);

                    m_NameIdMap.Add(Key, m_ResourceEntries.Count - 1);
                }
            }

            m_IndexValid = true;

            if (m_Plugin != null)
            {
                m_Plugin.OnResourceIndexingFinish(this);
            }

#if DUMPRESLIST
            using (System.IO.StreamWriter sr = new System.IO.StreamWriter(Path.GetTempPath() + "\\reslist.txt"))
            {
                for (ulong FileId = GetEncapsulatedFileCount(); FileId != 0; FileId -= 1)
                {
                    string ResRef;
                    ushort ResType;

                    if (!GetEncapsulatedFileEntry(FileId - 1, out ResRef, out ResType))
                    {
                        sr.WriteLine("Exception getting file entry {0}", FileId - 1);
                    }
                    else
                    {
                        sr.WriteLine("Entry {0}: Accessor {1}, Name {2}, ResType {3}", FileId - 1, m_ResourceEntries[(int)FileId - 1].Entry.Repository.Name, ResRef, ResType);
                    }
                }
            }
#endif
        }