/*
 * Copyright (c) Contributors, http://opensimulator.org/
 * See CONTRIBUTORS.TXT for a full list of copyright holders.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSimulator Project nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


using System;
using System.Text;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Mono.Addins.Setup;
using Mono.Addins;
using Mono.Addins.Description;
using OpenSim.Framework;

namespace OpenSim.Server.Base
{
    /// <summary>
    /// Command manager -
    /// Wrapper for OpenSim.Framework.PluginManager to allow 
    /// us to add commands to the console to perform operations
    /// on our repos and plugins
    /// </summary>
	public class CommandManager
	{
		public AddinRegistry PluginRegistry;
		protected PluginManager PluginManager;

		public CommandManager(AddinRegistry registry)
        {
			PluginRegistry = registry;
			PluginManager = new PluginManager(PluginRegistry);
			AddManagementCommands();
		}

		private void AddManagementCommands()
		{
			// add plugin
			MainConsole.Instance.Commands.AddCommand("Plugin", true,
                                                     "plugin add", "plugin add \"plugin index\"",
			                                         "Install plugin from repository.",
                                                     HandleConsoleInstallPlugin);

			// remove plugin
            MainConsole.Instance.Commands.AddCommand("Plugin", true,
                                                     "plugin remove", "plugin remove \"plugin index\"",
			                                         "Remove plugin from repository",
                                                     HandleConsoleUnInstallPlugin);

			// list installed plugins
            MainConsole.Instance.Commands.AddCommand("Plugin", true,
                                                     "plugin list installed", 
			                                         "plugin list installed","List install plugins",
                                                     HandleConsoleListInstalledPlugin);

			// list plugins available from registered repositories
            MainConsole.Instance.Commands.AddCommand("Plugin", true,
                                                     "plugin list available",
			                                         "plugin list available","List available plugins",
                                                     HandleConsoleListAvailablePlugin);
			// List available updates
            MainConsole.Instance.Commands.AddCommand("Plugin", true,
                                                     "plugin updates", "plugin updates","List availble updates",
                                                     HandleConsoleListUpdates);

			// Update plugin
            MainConsole.Instance.Commands.AddCommand("Plugin", true,
                                                     "plugin update", "plugin update \"plugin index\"","Update the plugin",
                                                     HandleConsoleUpdatePlugin);

			// Add repository
            MainConsole.Instance.Commands.AddCommand("Repository", true,
                                                     "repo add", "repo add \"url\"","Add repository",
                                                     HandleConsoleAddRepo);

			// Refresh repo
            MainConsole.Instance.Commands.AddCommand("Repository", true,
                                                     "repo refresh", "repo refresh \"url\"", "Sync with a registered repository",
                                                     HandleConsoleGetRepo);

			// Remove repository from registry
            MainConsole.Instance.Commands.AddCommand("Repository", true,
                                                     "repo remove",
			                                         "repo remove \"[url | index]\"",
			                                         "Remove repository from registry",
                                                     HandleConsoleRemoveRepo);

			// Enable repo
            MainConsole.Instance.Commands.AddCommand("Repository", true,
                                                     "repo enable", "repo enable \"[url | index]\"",
			                                         "Enable registered repository",
                                                     HandleConsoleEnableRepo);

			// Disable repo
            MainConsole.Instance.Commands.AddCommand("Repository", true,
                                                     "repo disable", "repo disable\"[url | index]\"",
			                                         "Disable registered repository",
                                                     HandleConsoleDisableRepo);

			// List registered repositories
            MainConsole.Instance.Commands.AddCommand("Repository", true,
                                                     "repo list", "repo list",
			                                         "List registered repositories",
                                                     HandleConsoleListRepos);

			// *
            MainConsole.Instance.Commands.AddCommand("Plugin", true,
                                                     "plugin info", "plugin info \"plugin index\"","Show detailed information for plugin",
                                                     HandleConsoleShowAddinInfo);

			// Plugin disable
            MainConsole.Instance.Commands.AddCommand("Plugin", true,
                                                     "plugin disable", "plugin disable \"plugin index\"",
			                                         "Disable a plugin",
                                                     HandleConsoleDisablePlugin);

			// Enable plugin
            MainConsole.Instance.Commands.AddCommand("Plugin", true,
                                                     "plugin enable", "plugin enable \"plugin index\"",
			                                         "Enable the selected plugin plugin",
                                                     HandleConsoleEnablePlugin);
        }
		
        #region console handlers
        // Handle our console commands
        //
        // Install plugin from registered repository
        /// <summary>
        /// Handles the console install plugin command. Attempts to install the selected plugin
        /// and 
        /// </summary>
        /// <param name='module'>
        /// Module.
        /// </param>
        /// <param name='cmd'>
        /// Cmd.
        /// </param>
        private void HandleConsoleInstallPlugin(string module, string[] cmd)
        {
            Dictionary<string, object> result = new Dictionary<string, object>();

            if (cmd.Length == 3)
            {
                int ndx = Convert.ToInt16(cmd[2]);
                if (PluginManager.InstallPlugin(ndx, out result) == true)
                {
                    ArrayList s = new ArrayList();
                    s.AddRange(result.Keys);
                    s.Sort();

                    var list = result.Keys.ToList();
                    list.Sort();
                    foreach (var k in list)
                    {
                        Dictionary<string, object> plugin = (Dictionary<string, object>)result[k];
                        bool enabled = (bool)plugin["enabled"];
                        MainConsole.Instance.OutputFormat("{0}) {1} {2} rev. {3}",
                                                  k,
                                                  enabled == true ? "[ ]" : "[X]",
                                                  plugin["name"], plugin["version"]);
                    }
                }
            }
            return;
        }

        // Remove installed plugin
        private void HandleConsoleUnInstallPlugin(string module, string[] cmd)
        {
            if (cmd.Length == 3)
            {
                int ndx = Convert.ToInt16(cmd[2]);
                PluginManager.UnInstall(ndx);
            }
            return;
        }

        // List installed plugins
        private void HandleConsoleListInstalledPlugin(string module, string[] cmd)
        {
            Dictionary<string, object> result = new Dictionary<string, object>();
            PluginManager.ListInstalledAddins(out result);

            ArrayList s = new ArrayList();
            s.AddRange(result.Keys);
            s.Sort();

            var list = result.Keys.ToList();
            list.Sort();
            foreach (var k in list)
            {
                Dictionary<string, object> plugin = (Dictionary<string, object>)result[k];
                bool enabled = (bool)plugin["enabled"];
                MainConsole.Instance.OutputFormat("{0}) {1} {2} rev. {3}",
                                                  k,
                                                  enabled == true ? "[ ]" : "[X]",
                                                  plugin["name"], plugin["version"]);
            }
            return;
        }

        // List available plugins on registered repositories
        private void HandleConsoleListAvailablePlugin(string module, string[] cmd)
        {
            Dictionary<string, object> result = new Dictionary<string, object>();
            PluginManager.ListAvailable(out result);

            var list = result.Keys.ToList();
            list.Sort();
            foreach (var k in list)
            {
                // name, version, repository
                Dictionary<string, object> plugin = (Dictionary<string, object>)result[k];
                MainConsole.Instance.OutputFormat("{0}) {1} rev. {2} {3}",
                                                  k,
                                                  plugin["name"],
                                                  plugin["version"],
                                                  plugin["repository"]);
            }
            return;
        }

        // List available updates **not ready
        private void HandleConsoleListUpdates(string module, string[] cmd)
        {
            PluginManager.ListUpdates();
            return;
        }

        // Update plugin **not ready
        private void HandleConsoleUpdatePlugin(string module, string[] cmd)
        {
            MainConsole.Instance.Output(PluginManager.Update());
            return;
        }

        // Register repository
        private void HandleConsoleAddRepo(string module, string[] cmd)
        {
            if ( cmd.Length == 3)
            {
                PluginManager.AddRepository(cmd[2]);
            }
            return;
        }

        // Get repository status **not working
        private void HandleConsoleGetRepo(string module, string[] cmd)
        {
            PluginManager.GetRepository();
            return;
        }

        // Remove registered repository
        private void HandleConsoleRemoveRepo(string module, string[] cmd)
        {
            if (cmd.Length == 3)
                PluginManager.RemoveRepository(cmd);
            return;
        }

        // Enable repository
        private void HandleConsoleEnableRepo(string module, string[] cmd)
        {
            PluginManager.EnableRepository(cmd);
            return;
        }

        // Disable repository
        private void HandleConsoleDisableRepo(string module, string[] cmd)
        {
            PluginManager.DisableRepository(cmd);
            return;
        }

        // List repositories
        private void HandleConsoleListRepos(string module, string[] cmd)
        {
            Dictionary<string, object> result = new Dictionary<string, object>();
            PluginManager.ListRepositories(out result);

            var list = result.Keys.ToList();
            list.Sort();
            foreach (var k in list)
            {
                Dictionary<string, object> repo = (Dictionary<string, object>)result[k];
                bool enabled = (bool)repo["enabled"];
                MainConsole.Instance.OutputFormat("{0}) {1} {2}",
                                                  k,
                                                  enabled == true ? "[ ]" : "[X]",
                                                  repo["name"], repo["url"]);
            }

            return;
        }

        // Show description information
        private void HandleConsoleShowAddinInfo(string module, string[] cmd)
        {
            if (cmd.Length >= 3)
            {
                
                Dictionary<string, object> result = new Dictionary<string, object>();

                int ndx = Convert.ToInt16(cmd[2]);
                PluginManager.AddinInfo(ndx, out result);

                MainConsole.Instance.OutputFormat("Name: {0}\nURL: {1}\nFile: {2}\nAuthor: {3}\nCategory: {4}\nDesc: {5}",
                                                  result["name"],
                                                  result["url"],
                                                  result["file_name"],
                                                  result["author"],
                                                  result["category"],
                                                  result["description"]);

                return;
            }
        }

        // Disable plugin
        private void HandleConsoleDisablePlugin(string module, string[] cmd)
        {
            PluginManager.DisablePlugin(cmd);
            return;
        }

        // Enable plugin
        private void HandleConsoleEnablePlugin(string module, string[] cmd)
        {
            PluginManager.EnablePlugin(cmd);
            return;
        }
        #endregion
	}
}