/// <summary>
		/// Parse the specified input string to a text command with arguments etc.
		/// </summary>
		/// <param name="input">Input string</param>
		static public TextCommand Parse (string input)
		{
			TextCommand result = new TextCommand ();
			string[] commandParts = CommandSplitter.Split (input);
			for (int i = 0; i < commandParts.Length; i++) {
				if (commandParts [i].Equals (string.Empty))
					continue;
					
				string param, arg;
				if (result.Keyword == null) {
					result.Keyword = GetParam (commandParts [i], out arg);
					if (arg != string.Empty)
						result.Params.Add ("subject", arg);
				} else {
					param = GetParam (commandParts [i], out arg);
					if (string.IsNullOrEmpty (param))
						continue;
					if (string.IsNullOrEmpty (arg))
						result.Flags.Add (param);
					else {
						result.Params.Add (param, arg);
					}
				}
			}
			return result;
		}
		public override string Execute (TextCommand cmd)
		{
			var res = new StringBuilder ();

			List<Card> results = service.SearchCard (cmd.Params);

			if (results.Count == 0)
				return "Couldn't find that card.";
			else if (results.Count == 1 || cmd.Flags.Contains ("F") || cmd.Flags.Contains ("First")) {
				Card card = results [0];
				if (card.ImageUrl == null || cmd.Flags.Contains ("T") || cmd.Flags.Contains ("Text")) {
					res.AppendLine (card.ToString ());
				} else {
					res.AppendLine (card.ImageUrl);
				}
				if (cmd.Flags.Contains ("L") || cmd.Flags.Contains ("Legal")) {
					res.AppendLine ("Legal in:");
					foreach (var l in card.Legalities) {
						res.AppendLine (l.ToString ());
					}
				}
				if (cmd.Flags.Contains ("R") || cmd.Flags.Contains ("Rules")) {
					if (card.Rulings == null)
						res.AppendLine ("No special rulings.");
					else {
						res.AppendLine ("Rulings:");
						foreach (var r in card.Rulings) {
							res.AppendLine (r.ToString ());
						}
					}
				}
			} else {
				res.AppendFormat ("Found {0} results:\n", results.Count);
				for (int i = 0; i < results.Count; i++) {
					res.AppendFormat ("{0}. {1} ({2})\n", i + 1, results [i].Name, results [i].Set);
				}
			}
			return res.ToString ();
		}
		public override string Execute (TextCommand cmd)
		{
			var res = new StringBuilder ();

			List<Product> results = service.SearchProduct (cmd.Params);
			List<Product> filteredResults = new List<Product> ();
			List<Product> activeList = results;

			if (cmd.Flags.Contains ("s") || cmd.Flags.Contains ("single")) {
				filteredResults.AddRange (results.Where (p => p.Category.Equals ("Magic Single")));
				activeList = filteredResults;
			}
			if (cmd.Flags.Contains ("b") || cmd.Flags.Contains ("booster")) {
				filteredResults.AddRange (results.Where (p => (p.Category.Equals ("Magic Booster"))));
				activeList = filteredResults;
			}
			if (cmd.Flags.Contains ("d") || cmd.Flags.Contains ("display")) {
				filteredResults.AddRange (results.Where (p => p.Category.Equals ("Magic Display")));
				activeList = filteredResults;
			}

			if (activeList.Count == 0) {
				return "Couldn't find that product.";
			} else if (activeList.Count < 10) {
				foreach (var product in activeList) {
					res.AppendLine (product.Name + ":");
					res.AppendLine (product.Link);
					res.AppendLine (product.Pricing.ToString ());
				}
			} else {
				res.AppendLine ("Found " + activeList.Count + " results:");
				for (int i = 0; i < activeList.Count; i++) {
					res.AppendFormat ("{0}. {1}\n", i + 1, results [i].Name);
				}
			}

			return res.ToString ();
		}
		public void Init ()
		{
			cmd = new TextCommand ();
		}
		public abstract string Execute (TextCommand cmd);
		public override string Execute (TextCommand cmd)
		{
			return helpText;
		}
		public override string Execute (TextCommand cmd)
		{
			return "Fresh & ready for the pickin'";
		}