context: //
  // mdsetup.cs
  //
  // Author:
  //   Lluis Sanchez Gual
  //
  // Copyright (C) 2007 Novell, Inc (http://www.novell.com)
  //
  // Permission is hereby granted, free of charge, to any person obtaining
  // a copy of this software and associated documentation files (the
  // "Software"), to deal in the Software without restriction, including
  // without limitation the rights to use, copy, modify, merge, publish,
  // distribute, sublicense, and/or sell copies of the Software, and to
  // permit persons to whom the Software is furnished to do so, subject to
  // the following conditions:
  // 
  // The above copyright notice and this permission notice shall be
  // included in all copies or substantial portions of the Software.
  // 
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  //
  
  
  using System;
  using System.Collections;
  using Mono.Addins;
  using Mono.Addins.Setup.ProgressMonitoring;
  using Mono.Addins.Setup;
  using System.IO;
  using Mono.Addins.Description;
  
  namespace Mono.Addins.Setup
  {
  	public class SetupTool
  	{
  		Hashtable options = new Hashtable ();
  		string[] arguments;
  		string applicationName = "Mono";
  		SetupService service;
  		AddinRegistry registry;
  		ArrayList commands = new ArrayList ();
  		string setupAppName = "";
  		
  		bool verbose;
  		
  		public SetupTool (AddinRegistry registry)
  		{
  			this.registry = registry;
  			service = new SetupService (registry);
  			CreateCommands ();
  		}
  		
  		public string ApplicationName {
  			get { return applicationName; }
  			set { applicationName = value; }
  		}
  		
  		public bool VerboseOutput {
  			get { return verbose; }
  			set { verbose = value; }
  		}
  
  		public int Run (string[] args, int firstArgumentIndex)
  		{
  			string[] aa = new string [args.Length - firstArgumentIndex];
  			Array.Copy (args, firstArgumentIndex, aa, 0, aa.Length);
  			return Run (aa);
  		}
  		
  		public int Run (string[] args)
  		{
  			if (args.Length == 0) {
  				PrintHelp ();
  				return 0;
  			}
  			
  			string[] parms = new string [args.Length - 1];
  			Array.Copy (args, 1, parms, 0, args.Length - 1);
  			
  			try {
  				ReadOptions (parms);
  				verbose = verbose || HasOption ("v");
  				return RunCommand (args [0], parms);
  			} catch (InstallException ex) {
  				Console.WriteLine (ex.Message);
  				return -1;
  			}
  		}
  		
  		int RunCommand (string cmd, string[] parms)
  		{
  			SetupCommand cc = FindCommand (cmd);
  			if (cc != null) {
  				cc.Handler (parms);
  				return 0;
  			}
  			else {
  				Console.WriteLine ("Unknown command: " + cmd);
  				return 1;
  			}
  		}
  		
  		void Install (string[] args)
  		{
  			if (args.Length < 1) {
  				PrintHelp ("install");
  				return;
  			}
  			
  			PackageCollection packs = new PackageCollection ();
  			for (int n=0; n<args.Length; n++) {
  				if (File.Exists (args [n])) { 
  					packs.Add (AddinPackage.FromFile (args [n]));
  				} else {
  					string[] aname = args[n].Split ('/');
  					AddinRepositoryEntry[] ads = service.Repositories.GetAvailableAddin (aname[0], null);
  					if (ads.Length == 0)
  						throw new InstallException ("The addin '" + args[n] + "' is not available for install.");
  					if (ads.Length > 1) {
  						if (aname.Length < 2) {
  							Console.WriteLine (args[n] + ": the addin version is required because there are several versions of the same addin available.");
  							return;
  						}
  						ads = service.Repositories.GetAvailableAddin (aname[0], aname[1]);
  						if (ads.Length == 0)
  							throw new InstallException ("The addin " + aname[0] + " v" + aname[1] + " is not available.");
  					}
  				
  					packs.Add (AddinPackage.FromRepository (ads[0]));
  				}
  			}
  			Install (packs);
  		}
  		
  		void Install (PackageCollection packs)
  		{
  			PackageCollection toUninstall;
  			DependencyCollection unresolved;
  			
  			IProgressStatus m = new ConsoleProgressStatus (verbose);
  			int n = packs.Count;
  			if (!service.Store.ResolveDependencies (m, packs, out toUninstall, out unresolved))
  				throw new InstallException ("Not all dependencies could be resolved.");
  
  			bool ask = false;
  			if (packs.Count != n || toUninstall.Count != 0) {
  				Console.WriteLine ("The following packages will be installed:");
  				foreach (Package p in packs)
  					Console.WriteLine (" - " + p.Name);
  				ask = true;
  			}
  			if (toUninstall.Count != 0) {
  				Console.WriteLine ("The following packages need to be uninstalled:");
  				foreach (Package p in toUninstall)
  					Console.WriteLine (" - " + p.Name);
  				ask = true;
  			}
  			if (ask) {
  				Console.WriteLine ();
  				Console.Write ("Are you sure you want to continue? (y/N): ");
  				string res = Console.ReadLine ();
  				if (res != "y" && res != "Y")
  					return;
  			}
  			
  			if (!service.Store.Install (m, packs)) {
  				Console.WriteLine ("Install operation failed.");
  			}
  		}
  		
  		void Uninstall (string[] args)
  		{
  			if (args.Length < 1)
  				throw new InstallException ("The add-in id is required.");
  			
  			Addin ads = registry.GetAddin (args[0]);
  			if (ads == null)
  				throw new InstallException ("The add-in '" + args[0] + "' is not installed.");
  			
  			Console.WriteLine ("The following add-ins will be uninstalled:");
  			Console.WriteLine (" - " + ads.Description.Name);
  			foreach (Addin si in service.GetDependentAddins (args[0], true))
  				Console.WriteLine (" - " + si.Description.Name);
  			
  			Console.WriteLine ();
  			Console.Write ("Are you sure you want to continue? (y/N): ");
  			string res = Console.ReadLine ();
  			if (res == "y" || res == "Y")
  				service.Uninstall (new ConsoleProgressStatus (verbose), ads.Id);
  		}
  		
  		bool IsHidden (Addin ainfo)
  		{
  			return service.ApplicationNamespace != null && !(ainfo.Namespace + ".").StartsWith (service.ApplicationNamespace + ".");
  		}
  		
  		bool IsHidden (AddinHeader ainfo)
  		{
  			return service.ApplicationNamespace != null && !(ainfo.Namespace + ".").StartsWith (service.ApplicationNamespace + ".");
  		}
  		
  		void ListInstalled (string[] args)
  		{
  			bool showAll = args.Length > 0 && args [0] == "-a";
  			Console.WriteLine ("Installed add-ins:");
  			Addin[] addins = registry.GetAddins ();
  			foreach (Addin addin in addins) {
  
gt: 				if (!showAll && IsHidden (addin))