using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml.XPath;

namespace Quadarax.Foundation.QConsole.Configuration
{
    public class StartupConfiguration
    {
        #region *** Private Fields ***
        private bool _isConsoleDebug;
        private string[] _defaultCommands = {"CmdClear", "CmdExit", "CmdPrint", "CmdSelection"};

        private readonly IList<string> _disabledCommands = new List<string>();
        #endregion

        #region *** Properties ***
        /// <summary>
        /// Name of console application, If not defined uses default name from entryAssembly.
        /// </summary>
        public string ConsoleName { get; }
        /// <summary>
        /// Console application version. If not defined uses version of entryAssembly.
        /// </summary>
        public Version ConsoleVersion { get; }
        /// <summary>
        /// Defines if console is initialized from XML definition.
        /// </summary>
        public bool IsInitFromXml { get; }

        /// <summary>
        /// Left introducing of interactive mode character.
        /// </summary>
        public string CharacterLineIntroduce { get; set; }

        /// <summary>
        /// Separator between two ordinal arguments
        /// </summary>
        public string CharacterOrdinalArgumentSeparator { get; set; }

        /// <summary>
        /// Named argument prefix character.
        /// </summary>
        public string CharacterNamedArgumentSeparator { get; set; }
        /// <summary>
        /// Named argument postfix character {defines end of argument code and value)
        /// </summary>
        public string CharacterNamedArgumentValueSeparator { get; set; }
        /// <summary>
        /// Start end end string value character
        /// </summary>
        public string CharacterTextValueBraceSeparator { get; set; }

        /// <summary>
        /// Separator between two selection inputs
        /// </summary>
        public string CharacterSelectionInputValueSeparator { get; set; }

        /// <summary>
        /// Date input/output value format
        /// </summary>
        public string DateFormat { get; set; }
        /// <summary>
        /// Time input/output value format
        /// </summary>
        public string TimeFormat { get; set; }
        /// <summary>
        /// Defines if interactive mode is enabled
        /// </summary>
        public bool AllowInteractive { get; set; }
        /// <summary>
        /// Defines if initial variables is allowed for interactive mode.
        /// </summary>
        public bool AllowPreset { get; set; }

        /// <summary>
        /// Defines assembly list where custom commands are defined (in case explicit command definition).
        /// </summary>
        public Assembly[] CommandDefinitionAssebmly { get; set; }

        /// <summary>
        /// Returns name of command classes that will be disabled (hidden)
        /// </summary>
        public string[] DisabledCommands => _disabledCommands.ToArray();

        /// <summary>
        /// Defines if waits on key at the end of process in non-interactive mode (inline mode)
        /// </summary>
        public bool WaitOnKeyInNonInteractiveMode { get; set; }

        /// <summary>
        /// Defines if show status of engine and command context before every command executed.
        /// </summary>
        public bool ShowStatusOnEveryCommand { get; set; }

        public bool IsConsoleDebug {
            get
            {
                return _isConsoleDebug;
            }
            set 
            { 
                _isConsoleDebug = value;
                DebugConsoleWriter.IsWriteDebugEnabled = value;
            }
        }
        #endregion

        #region *** Constructor ***

        public StartupConfiguration(string consoleName, Version consoleVersion)
        {
            ConsoleName = consoleName;
            ConsoleVersion = consoleVersion;
            IsInitFromXml = false;
            InitDefaults();
        }

        public StartupConfiguration(string consoleXmlFileName)
        {
            IsInitFromXml = true;
            InitDefaults();
        }

        public StartupConfiguration(XPathNavigator configurationNavigator)
        {
            IsInitFromXml = true;
            InitDefaults();
        }
        #endregion

        #region *** Public Operations ***
        public StartupConfiguration EnableDebugMode()
        {
            IsConsoleDebug = true;
            return this;
        }
        public StartupConfiguration DisableDebugMode()
        {
            IsConsoleDebug = false;
            return this;
        }

        public StartupConfiguration DisableDefaultCommands()
        {
            return DisableCommands(_defaultCommands);
        }

        public StartupConfiguration EnableDefaultCommands()
        {
            return EnableCommands(_defaultCommands);
        }

        public StartupConfiguration EnableCommands(params string[] commandClassNames)
        {
            if (commandClassNames == null)
                return this;

            foreach (var className in commandClassNames)
            {
                if (_disabledCommands.Contains(className))
                    _disabledCommands.Remove(className);
            }
            return this;
        }

        public StartupConfiguration DisableCommands(params string[] commandClassNames)
        {
            if (commandClassNames == null)
                return this;
            foreach (var className in commandClassNames)
            {
                if (!_disabledCommands.Contains(className))
                    _disabledCommands.Add(className);
            }

            return this;
        }

        #endregion

        #region *** Private Operations ***
        private void InitDefaults()
        {
            CharacterLineIntroduce = Defaults.RoleCharacters.ConsoleLineIntroduce;
            CharacterOrdinalArgumentSeparator = Defaults.RoleCharacters.OrdinalArgumentSeparator;
            CharacterNamedArgumentSeparator = Defaults.RoleCharacters.NamedArgumentSeparator;
            CharacterNamedArgumentValueSeparator = Defaults.RoleCharacters.NamedArgumentValueSeparator;
            CharacterTextValueBraceSeparator = Defaults.RoleCharacters.TextValueBraceSeparator;
            CharacterSelectionInputValueSeparator = Defaults.RoleCharacters.InputSelectionValueSeparator;

            DateFormat = Defaults.Formats.DateFormat;
            TimeFormat = Defaults.Formats.TimeFormat;

            AllowInteractive = Defaults.Console.InteractiveAllowed;
            AllowPreset = Defaults.Console.PresetAllowed;
            IsConsoleDebug = Defaults.Console.ConsoleDebugMode;
            WaitOnKeyInNonInteractiveMode = Defaults.Console.WaitOnKeyInNonInteractiveMode;
            ShowStatusOnEveryCommand = Defaults.Console.ShowStatusOnEveryCommand;

        }
        #endregion
    }
}
