using System;
using System.Collections.Generic;
using System.Text;

namespace Hydra.Framework.CommandLine
{
    /// <summary>
    /// Command Line Parser
    /// </summary>
    public class CommandLineParser
    {
        #region Member Variables
        /// <summary>
        /// Collection of Command line Arguments
        /// </summary>
        private readonly Dictionary<string, IArgumentParsingInstructions> commandCollection = new Dictionary<string, IArgumentParsingInstructions>();

        /// <summary>
        /// The Naming policy implemented
        /// </summary>
        private readonly IArgumentCommandNameConvention namePolicy = new ArgumentType();

        /// <summary>
        /// the Argument policy implemented
        /// </summary>
        private readonly IArgumentOrderPolicy argumentPolicy = new PositionalArgument();
        #endregion

        #region Public Methods
        /// <summary>
        /// Parses the specified command line.
        /// </summary>
        /// <param name="commandLine">The command line.</param>
        /// <returns></returns>
        public ParsedCommandLineOutput Parse(List<string> commandLine)
        {
            string commandName = commandLine.Head();
            List<string> remainder = commandLine.Tail();

            argumentPolicy.Verify(remainder);
            object args = commandCollection[commandName].Build(remainder);

            return new ParsedCommandLineOutput() { CommandName = commandName, ParsedArguments = args };
        }


        /// <summary>
        /// Registers the argumentCollection.
        /// </summary>
        /// <typeparam name="ArgsType">The type of the RGS type.</typeparam>
        public void RegisterArguments<ArgsType>() where ArgsType : new()
        {
            RegisterArgumentsForCommand<ArgsType>(namePolicy.GetName<ArgsType>());
        }

        /// <summary>
        /// Registers the argumentCollection for command.
        /// </summary>
        /// <typeparam name="ArgsType">The type of the RGS type.</typeparam>
        /// <param name="commandName">StateName of the command.</param>
        public void RegisterArgumentsForCommand<ArgsType>(string commandName) where ArgsType : new()
        {
            var argType = typeof(ArgsType);
            IArgumentParsingInstructions api = new ArgumentParsingInstructions(argType);
            commandCollection.Add(commandName, api);
        }

        /// <summary>
        /// Whatses the registered.
        /// </summary>
        /// <returns></returns>
        public string WhatsRegistered()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("Commands:");

            foreach (var pair in commandCollection)
            {
                sb.AppendFormat("{0}{1}", pair.Key, Environment.NewLine);
                sb.AppendFormat(pair.Value.WhatAreTheOptions());
                sb.AppendLine();
            }

            return sb.ToString();
        }
        #endregion
    }
}