/// <summary>
        /// Reloads the specified plugin. Does not initialize it.
        /// </summary>
        /// <param name="pluginFilePath"></param>
        public T ReloadPlugin(string pluginFilePath)
        {
            // If we're trying to reload an active backend plugin, stop
            foreach (var pair in this.pluginRegistry)
            {
                T plugin = pair.Value;
                if (PathOp.ArePathsEqual(plugin.FilePath, pluginFilePath))
                {
                    foreach (Assembly lockedAssembly in this.lockedPlugins)
                    {
                        if (plugin.PluginAssembly == lockedAssembly)
                        {
                            this.pluginLog.WriteError(
                                "Can't reload plugin {0}, because it has been locked by the runtime. " +
                                "This usually happens for plugins that implement a currently active backend.",
                                LogFormat.Assembly(lockedAssembly));
                            return(null);
                        }
                    }
                    break;
                }
            }

            // Load the updated plugin Assembly
            Assembly pluginAssembly = null;

            try
            {
                pluginAssembly = this.assemblyLoader.LoadAssembly(pluginFilePath);
            }
            catch (Exception e)
            {
                this.pluginLog.WriteError("Error loading plugin Assembly: {0}", LogFormat.Exception(e));
                return(null);
            }

            // If we're overwriting an old plugin here, add the old version to the "disposed" blacklist
            string assemblyName = pluginAssembly.GetShortAssemblyName();
            T      oldPlugin;

            if (this.pluginRegistry.TryGetValue(assemblyName, out oldPlugin))
            {
                this.pluginRegistry.Remove(assemblyName);
                this.disposedPlugins.Add(oldPlugin.PluginAssembly);
                this.OnPluginsRemoving(new[] { oldPlugin });
                oldPlugin.Dispose();
            }

            // Load the new plugin from the updated Assembly
            T updatedPlugin = this.LoadPlugin(pluginAssembly, pluginFilePath);

            // Discard temporary plugin-related data (cached Types, etc.)
            this.OnPluginsRemoved(new[] { oldPlugin });

            return(updatedPlugin);
        }
        /// <summary>
        /// Initializes this CoheeApp. Should be called before performing any operations within Cohee.
        /// </summary>
        /// <param name="context">The <see cref="ExecutionContext"/> in which Duality runs.</param>
        /// <param name="commandLineArgs">
        /// Command line arguments to run this CoheeApp with.
        /// Usually these are just the ones from the host application, passed on.
        /// </param>
        public static void Init(ExecutionEnvironment env, ExecutionContext context, IAssemblyLoader assemLoader, string[] commandLineArgs)
        {
            if (initialized)
            {
                return;
            }

            // Process command line options
            if (commandLineArgs != null)
            {
                // Enter debug mode
                if (commandLineArgs.Contains(CmdArgDebug))
                {
                    System.Diagnostics.Debugger.Launch();
                }
                // Run from editor
                if (commandLineArgs.Contains(CmdArgEditor))
                {
                    runFromEditor = true;
                }
            }

            // If the core was compiled in debug mode and a debugger is attached, log
            // to the Debug channel, so we can put the VS output window to good use.
            #if DEBUG
            bool isDebugging = System.Diagnostics.Debugger.IsAttached;
            if (isDebugging)
            {
                // Only add a new Debug output if we don't already have one, and don't
                // log to a Console channel either. VS will automatically redirect Console
                // output to the Output window when debugging a non-Console application,
                // and we don't want to end up with double log entries.
                bool hasDebugOut   = Logs.GlobalOutput.OfType <DebugLogOutput>().Any();
                bool hasConsoleOut = Logs.GlobalOutput.OfType <TextWriterLogOutput>().Any(w => w.GetType().Name.Contains("Console"));
                if (!hasDebugOut && !hasConsoleOut)
                {
                    Logs.AddGlobalOutput(new DebugLogOutput());
                }
            }
            #endif

            environment = env;
            execContext = context;

            // Initialize the plugin manager
            {
                assemblyLoader = assemLoader ?? new Cohee.Backend.Dummy.DummyAssemblyLoader();
                Logs.Core.Write("Using '{0}' to load plugins.", assemblyLoader.GetType().Name);

                assemblyLoader.Init();

                // Log assembly loading data for diagnostic purposes
                {
                    Logs.Core.Write("Currently Loaded Assemblies:" + Environment.NewLine + "{0}",
                                    assemblyLoader.LoadedAssemblies.ToString(
                                        assembly => "  " + LogFormat.Assembly(assembly),
                                        Environment.NewLine));
                    Logs.Core.Write("Plugin Base Directories:" + Environment.NewLine + "{0}",
                                    assemblyLoader.BaseDirectories.ToString(
                                        path => "  " + path,
                                        Environment.NewLine));
                    Logs.Core.Write("Available Assembly Paths:" + Environment.NewLine + "{0}",
                                    assemblyLoader.AvailableAssemblyPaths.ToString(
                                        path => "  " + path,
                                        Environment.NewLine));
                }

                corePluginManager.Init(assemblyLoader);
                corePluginManager.PluginsRemoving += pluginManager_PluginsRemoving;
                corePluginManager.PluginsRemoved  += pluginManager_PluginsRemoved;
            }

            // Load all plugins. This needs to be done first, so backends and Types can be located.
            corePluginManager.LoadPlugins();

            // Initialize the system backend for system info and file system access
            InitBackend(out systemBackend);

            // Load application and user data and submit a change event, so all settings are applied
            LoadAppData();
            LoadUserData();
            OnAppDataChanged();
            OnUserDataChanged();

            // Initialize the graphics backend
            InitBackend(out graphicsBackend);

            // Initialize the audio backend
            InitBackend(out audioBackend);
            //sound = new SoundDevice();

            // Initialize all core plugins, this may allocate Resources or establish references between plugins
            corePluginManager.InitPlugins();

            initialized = true;

            // Write environment specs as a debug log
            Logs.Core.Write(
                "DualityApp initialized" + Environment.NewLine +
                "Debug Mode: {0}" + Environment.NewLine +
                "Command line arguments: {1}",
                System.Diagnostics.Debugger.IsAttached,
                commandLineArgs != null ? commandLineArgs.ToString(", ") : "null");
        }