/*
 * Ensemble.cs --
 *
 * Copyright (c) 2007-2012 by Joe Mistachkin.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: $
 */

using System;
using Eagle._Attributes;
using Eagle._Components.Private;
using Eagle._Components.Public;
using Eagle._Containers.Public;
using Eagle._Interfaces.Public;

namespace Eagle._Commands
{
    [ObjectId("310a4c0c-135d-4ded-b2b9-ed2d2182f2ef")]
    [ObjectGroup("ensemble")]
    public class Ensemble : Default, IEnsembleData
    {
        #region Public Constructors
        public Ensemble(
            ICommandData commandData
            )
            : base(commandData)
        {
            //
            // NOTE: This is not a strictly vanilla "command", it is a wrapped
            //       ensemble.
            //
            this.Kind |= IdentifierKind.Ensemble;

            //
            // NOTE: Normally, this flags assignment is performed by
            //       _Commands.Core for all commands residing in the core
            //       library; however, this class does not inherit from
            //       _Commands.Core.
            //
            this.Flags |= AttributeOps.GetCommandFlags(GetType().BaseType) |
                AttributeOps.GetCommandFlags(this);
        }

        ///////////////////////////////////////////////////////////////////////

        public Ensemble(
            ICommandData commandData,
            IEnsembleData ensembleData
            )
            : this(commandData)
        {
            if (ensembleData != null)
            {
                this.subCommandExecute = ensembleData.SubCommandExecute;
            }
        }
        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region IEnsemble Members
        private static readonly EnsembleDictionary subCommands =
            new EnsembleDictionary(new string[] {
            "about", "options"
        });

        ///////////////////////////////////////////////////////////////////////

        public override EnsembleDictionary SubCommands
        {
            get { return subCommands; }
        }
        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region IEnsembleData Members
        private IExecute subCommandExecute;
        public virtual IExecute SubCommandExecute
        {
            get { return subCommandExecute; }
            set { subCommandExecute = value; }
        }
        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region IExecute Members
        public override ReturnCode Execute(
            Interpreter interpreter,
            IClientData clientData,
            ArgumentList arguments,
            ref Result result
            )
        {
            if (interpreter == null)
            {
                result = "invalid interpreter";
                return ReturnCode.Error;
            }

            if (arguments == null)
            {
                result = "invalid argument list";
                return ReturnCode.Error;
            }

            if (arguments.Count < 2)
            {
                result = String.Format(
                    "wrong # args: should be \"{0} option ?arg ...?\"",
                    this.Name);

                return ReturnCode.Error;
            }

            ReturnCode code = ReturnCode.Ok;
            string subCommand = arguments[1];
            bool tried = false;

            code = ScriptOps.TryExecuteSubCommandFromEnsemble(
                this, interpreter, clientData, arguments, true,
                false, ref subCommand, ref tried, ref result);

            if ((code == ReturnCode.Ok) && !tried)
            {
                switch (subCommand)
                {
                    case "about":
                        {
                            if (arguments.Count == 2)
                            {
                                IPlugin plugin = this.Plugin;

                                if (plugin != null)
                                {
                                    code = plugin.About(
                                        interpreter, ref result);
                                }
                                else
                                {
                                    result = "invalid command plugin";
                                    code = ReturnCode.Error;
                                }
                            }
                            else
                            {
                                result = String.Format(
                                    "wrong # args: should be \"{0} {1}\"",
                                    this.Name, subCommand);

                                code = ReturnCode.Error;
                            }
                            break;
                        }
                    case "options":
                        {
                            if (arguments.Count == 2)
                            {
                                IPlugin plugin = this.Plugin;

                                if (plugin != null)
                                {
                                    code = plugin.Options(
                                        interpreter, ref result);
                                }
                                else
                                {
                                    result = "invalid command plugin";
                                    code = ReturnCode.Error;
                                }
                            }
                            else
                            {
                                result = String.Format(
                                    "wrong # args: should be \"{0} {1}\"",
                                    this.Name, subCommand);

                                code = ReturnCode.Error;
                            }
                            break;
                        }
                    default:
                        {
                            //
                            // NOTE: We cannot handle the sub-command locally.
                            //       Therefore, we can either attempt to use
                            //       the provided [sub-]command -OR- return a
                            //       reasonable default error message.
                            //
                            IExecute execute = this.SubCommandExecute;

                            if (execute != null)
                            {
                                code = execute.Execute(
                                    interpreter, clientData, arguments,
                                    ref result);
                            }
                            else
                            {
                                result = ScriptOps.BadSubCommand(
                                    null, null, subCommand, this, null, null);

                                code = ReturnCode.Error;
                            }
                            break;
                        }
                }
            }

            return code;
        }
        #endregion
    }
}
