/*
 * Interp.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 System.Text;
using Eagle._Attributes;
using Eagle._Components.Private;
using Eagle._Components.Public;
using Eagle._Constants;
using Eagle._Containers.Public;
using Eagle._Interfaces.Public;

namespace Eagle._Commands
{
    [ObjectId("f83b2063-cf1f-428f-9cb9-7a1862a69960")]
    //
    // TODO: Make this command "safe".  The main thing that needs to be done is
    //       to audit the code for security and make sure any state changes are
    //       isolated to the current interpreter or one of its slaves.
    //
    [CommandFlags(CommandFlags.Unsafe | CommandFlags.Standard)]
    [ObjectGroup("scriptEnvironment")]
    internal sealed class Interp : Core
    {
        public Interp(
            ICommandData commandData
            )
            : base(commandData)
        {
            // do nothing.
        }

        #region IEnsemble Members
        private static readonly EnsembleDictionary subCommands = new EnsembleDictionary(new string[] {
            "alias", "aliases", "bgerror", "cancel", "create",
            "delete", "enabled", "eval", "exists", "expose", "expr",
            "finallytimeout", "hide", "hidden", "immutable", "invokehidden",
            "issafe", "isstandard", "makesafe", "makestandard", "marktrusted",
            "nopolicy", "policy", "queue", "readonly", "readorgetscriptfile",
            "readylimit", "recursionlimit", "resetcancel", "service", "set",
            "slaves", "sleeptime", "subst", "target", "timeout", "unset",
            "watchdog"
        });

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

        #region IExecute Members
        public override ReturnCode Execute(
            Interpreter interpreter,
            IClientData clientData,
            ArgumentList arguments,
            ref Result result
            )
        {
            ReturnCode code = ReturnCode.Ok;

            if (interpreter != null)
            {
                if (arguments != null)
                {
                    if (arguments.Count >= 2)
                    {
                        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 "alias":
                                    {
                                        if (arguments.Count >= 4)
                                        {
                                            Interpreter sourceInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                arguments[2], LookupFlags.Interpreter, false,
                                                ref sourceInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                string sourceName = arguments[3];

                                                if (arguments.Count == 4)
                                                {
                                                    //
                                                    // NOTE: Return the alias definition.
                                                    //
                                                    IAlias alias = null;

                                                    code = sourceInterpreter.GetAlias(
                                                        sourceName, LookupFlags.Default,
                                                        ref alias, ref result);

                                                    if (code == ReturnCode.Ok)
                                                        result = alias.ToString();
                                                }
                                                else if ((arguments.Count == 5) &&
                                                    String.IsNullOrEmpty(arguments[4]))
                                                {
                                                    //
                                                    // NOTE: Delete the alias definition.
                                                    //
                                                    code = sourceInterpreter.RemoveAliasAndCommand(
                                                        sourceName, clientData, false, ref result);

                                                    if (code == ReturnCode.Ok)
                                                        result = String.Empty;
                                                }
                                                else if (arguments.Count > 5)
                                                {
                                                    Interpreter targetInterpreter = null;

                                                    code = interpreter.GetNestedSlaveInterpreter(
                                                        arguments[4], LookupFlags.Interpreter, false,
                                                        ref targetInterpreter, ref result);

                                                    if (code == ReturnCode.Ok)
                                                    {
                                                        string targetName = arguments[5];

                                                        if ((arguments.Count == 6) &&
                                                            String.IsNullOrEmpty(targetName))
                                                        {
                                                            //
                                                            // NOTE: Delete the alias definition.
                                                            //
                                                            code = sourceInterpreter.RemoveAliasAndCommand(
                                                                sourceName, clientData, false, ref result);

                                                            if (code == ReturnCode.Ok)
                                                                result = String.Empty;
                                                        }
                                                        else
                                                        {
                                                            //
                                                            // NOTE: Create the alias definition.
                                                            //
                                                            if ((sourceInterpreter.DoesIExecuteExist(sourceName) != ReturnCode.Ok) ||
                                                                (sourceInterpreter.RemoveIExecute(sourceName, clientData, ref result) == ReturnCode.Ok))
                                                            {
                                                                if ((sourceInterpreter.DoesProcedureExist(sourceName) != ReturnCode.Ok) ||
                                                                    (sourceInterpreter.RemoveProcedure(sourceName, clientData, ref result) == ReturnCode.Ok))
                                                                {
                                                                    if ((sourceInterpreter.DoesCommandExist(sourceName) != ReturnCode.Ok) ||
                                                                        (sourceInterpreter.RemoveCommand(sourceName, clientData, ref result) == ReturnCode.Ok))
                                                                    {
                                                                        ArgumentList targetArguments = new ArgumentList(targetName);

                                                                        if (arguments.Count > 6)
                                                                            targetArguments.AddRange(ArgumentList.GetRange(arguments, 6));

                                                                        IAlias alias = null;

                                                                        code = sourceInterpreter.AddAlias(
                                                                            sourceName, CommandFlags.None, AliasFlags.SkipSourceName | AliasFlags.InterpreterAlias,
                                                                            clientData, targetInterpreter, null, targetArguments, null, 0, ref alias, ref result);
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                                else
                                                {
                                                    goto aliasArgs;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            goto aliasArgs;
                                        }
                                        break;

                                    aliasArgs:
                                        result = "wrong # args: should be \"interp alias slavePath slaveCmd ?masterPath masterCmd? ?arg ...?\"";
                                        code = ReturnCode.Error;
                                        break;
                                    }
                                case "aliases":
                                    {
                                        if ((arguments.Count >= 2) && (arguments.Count <= 5))
                                        {
                                            string path = (arguments.Count >= 3) ?
                                                (string)arguments[2] : String.Empty;

                                            string pattern = (arguments.Count >= 4) ?
                                                (string)arguments[3] : null;

                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                bool all = false; /* TODO: Good default? */

                                                if (arguments.Count >= 5)
                                                {
                                                    code = Value.GetBoolean2(
                                                        arguments[4], ValueFlags.AnyBoolean,
                                                        slaveInterpreter.CultureInfo, ref all,
                                                        ref result);
                                                }

                                                if (code == ReturnCode.Ok)
                                                {
                                                    StringList list = null;

                                                    code = slaveInterpreter.ListAliases(
                                                        pattern, false, all, ref list, ref result);

                                                    if (code == ReturnCode.Ok)
                                                        result = list;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp aliases ?path? ?pattern? ?all?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "bgerror":
                                    {
                                        if ((arguments.Count == 3) || (arguments.Count == 4))
                                        {
                                            string path = arguments[2];
                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                lock (slaveInterpreter.SyncRoot) /* TRANSACTIONAL */
                                                {
                                                    if (arguments.Count == 4)
                                                    {
                                                        StringList list = null;

                                                        code = Parser.SplitList(
                                                            slaveInterpreter, arguments[3], 0,
                                                            Length.Invalid, true, ref list,
                                                            ref result);

                                                        if (code == ReturnCode.Ok)
                                                            slaveInterpreter.BackgroundError = list.ToString();
                                                    }

                                                    if (code == ReturnCode.Ok)
                                                        result = slaveInterpreter.BackgroundError;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp bgerror path ?cmdPrefix?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "cancel":
                                    {
                                        OptionDictionary options = new OptionDictionary(
                                            new Option[] {
                                            new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-unwind", null),
                                            new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, Option.EndOfOptions, null)
                                        });

                                        int argumentIndex = Index.Invalid;

                                        if (arguments.Count > 2)
                                            code = interpreter.GetOptions(options, arguments, 0, 2, Index.Invalid, false, ref argumentIndex, ref result);
                                        else
                                            code = ReturnCode.Ok;

                                        if (code == ReturnCode.Ok)
                                        {
                                            string path = null;
                                            Result cancelResult = null;

                                            if (argumentIndex != Index.Invalid)
                                            {
                                                if ((argumentIndex + 2) >= arguments.Count)
                                                {
                                                    //
                                                    // NOTE: Grab the name of the interpreter.
                                                    //
                                                    path = arguments[argumentIndex];

                                                    //
                                                    // NOTE: The cancel result is just after the interpreter.
                                                    //
                                                    if ((argumentIndex + 1) < arguments.Count)
                                                        cancelResult = arguments[argumentIndex + 1];
                                                }
                                                else
                                                {
                                                    if (Option.LooksLikeOption(arguments[argumentIndex]))
                                                    {
                                                        result = OptionDictionary.BadOption(options, arguments[argumentIndex]);
                                                    }
                                                    else
                                                    {
                                                        result = "wrong # args: should be \"interp cancel ?-unwind? ?--? ?path? ?result?\"";
                                                    }

                                                    code = ReturnCode.Error;
                                                }
                                            }
                                            else
                                            {
                                                path = String.Empty;
                                            }

                                            if (code == ReturnCode.Ok)
                                            {
                                                Interpreter slaveInterpreter = null;

                                                code = interpreter.GetNestedSlaveInterpreter(
                                                    path, LookupFlags.Interpreter, false,
                                                    ref slaveInterpreter, ref result);

                                                if (code == ReturnCode.Ok)
                                                {
                                                    bool unwind = false;

                                                    if (options.IsPresent("-unwind"))
                                                        unwind = true;

                                                    code = Engine.CancelEvaluate(slaveInterpreter, unwind, cancelResult, ref result);
                                                }
                                            }
                                        }
                                        break;
                                    }
                                case "create":
                                    {
                                        OptionDictionary options = new OptionDictionary(
                                            new Option[] {
                                            new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-namespaces", null),
                                            new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-nonamespaces", null),
                                            new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-novariables", null),
                                            new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-noinitialize", null),
                                            new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-safe", null),
                                            new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-standard", null),
#if APPDOMAINS && ISOLATED_INTERPRETERS
                                            new Option(null, OptionFlags.NoCase, Index.Invalid, Index.Invalid, "-isolated", null),
#else
                                            new Option(null, OptionFlags.NoCase | OptionFlags.Unsupported, Index.Invalid,
                                                Index.Invalid, "-isolated", null),
#endif
#if DEBUGGER
                                            new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-debug", null),
#else
                                            new Option(null, OptionFlags.Unsupported, Index.Invalid, Index.Invalid, "-debug", null),
#endif
                                            new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, Option.EndOfOptions, null)
                                        });

                                        int argumentIndex = Index.Invalid;

                                        if (arguments.Count > 2)
                                            code = interpreter.GetOptions(options, arguments, 0, 2, Index.Invalid, true, ref argumentIndex, ref result);
                                        else
                                            code = ReturnCode.Ok;

                                        if (code == ReturnCode.Ok)
                                        {
                                            if ((argumentIndex == Index.Invalid) || ((argumentIndex + 1) == arguments.Count))
                                            {
                                                if (interpreter.HasSlaveInterpreters(ref result))
                                                {
                                                    string path = null;
                                                    string name = null;

                                                    if (argumentIndex != Index.Invalid)
                                                        path = arguments[argumentIndex];

                                                    if ((path != null) &&
                                                        (interpreter.DoesSlaveInterpreterExist(path, true, ref name) == ReturnCode.Ok))
                                                    {
                                                        result = String.Format(
                                                            "interpreter named \"{0}\" already exists, cannot create",
                                                            name);

                                                        code = ReturnCode.Error;
                                                    }

                                                    if (code == ReturnCode.Ok)
                                                    {
                                                        //
                                                        // HACK: Inherit the default "use namespaces" setting
                                                        //       from the master interpreter.
                                                        //
                                                        bool namespaces = interpreter.AreNamespacesEnabled();

                                                        if (options.IsPresent("-namespaces"))
                                                            namespaces = true;

                                                        if (options.IsPresent("-nonamespaces"))
                                                            namespaces = false;

                                                        bool initialize = true;

                                                        if (options.IsPresent("-noinitialize"))
                                                            initialize = false;

                                                        bool variables = true;

                                                        if (options.IsPresent("-novariables"))
                                                            variables = false;

                                                        bool safe = interpreter.IsSafe();

                                                        if (options.IsPresent("-safe"))
                                                            safe = true;

                                                        bool standard = false;

                                                        if (options.IsPresent("-standard"))
                                                            standard = true;

                                                        bool isolated = false;

#if APPDOMAINS && ISOLATED_INTERPRETERS
                                                        if (options.IsPresent("-isolated"))
                                                            isolated = true;
#endif

#if DEBUGGER
                                                        bool debug = false;

                                                        if (options.IsPresent("-debug"))
                                                            debug = true;
#endif

                                                        //
                                                        // NOTE: Start with default shell flags.
                                                        //
                                                        CreateFlags createFlags = CreateFlags.NestedUse;

                                                        //
                                                        // NOTE: Enable full namespace support?
                                                        //
                                                        if (namespaces)
                                                            createFlags |= CreateFlags.UseNamespaces;
                                                        else
                                                            createFlags &= ~CreateFlags.UseNamespaces;

                                                        //
                                                        // NOTE: Set the built-in variables?
                                                        //
                                                        if (variables)
                                                            createFlags &= ~CreateFlags.NoVariables;
                                                        else
                                                            createFlags |= CreateFlags.NoVariables;

                                                        //
                                                        // NOTE: Initialize the script library?
                                                        //
                                                        if (initialize)
                                                            createFlags |= CreateFlags.Initialize;
                                                        else
                                                            createFlags &= ~CreateFlags.Initialize;

                                                        //
                                                        // NOTE: Are we creating a safe interpreter?
                                                        //
                                                        if (safe)
                                                            createFlags |= CreateFlags.SafeAndHideUnsafe;

                                                        if (standard)
                                                            createFlags |= CreateFlags.StandardAndHideNonStandard;

#if DEBUGGER
                                                        //
                                                        // NOTE: Do we want a script debugger?
                                                        //
                                                        if (debug)
                                                            createFlags |= CreateFlags.DebuggerUse;
#endif

                                                        code = interpreter.CreateSlaveInterpreter(
                                                            path, clientData, createFlags, isolated, ref result);
                                                    }
                                                }
                                                else
                                                {
                                                    code = ReturnCode.Error;
                                                }
                                            }
                                            else
                                            {
                                                result = "wrong # args: should be \"interp create ?-safe? ?--? ?path?\"";
                                                code = ReturnCode.Error;
                                            }
                                        }
                                        break;
                                    }
                                case "delete":
                                    {
                                        if (arguments.Count >= 2)
                                        {
                                            if (interpreter.HasSlaveInterpreters(ref result))
                                            {
                                                for (int argumentIndex = 2; argumentIndex < arguments.Count; argumentIndex++)
                                                {
                                                    code = interpreter.DeleteSlaveInterpreter(
                                                        arguments[argumentIndex], clientData, true, ref result);

                                                    if (code != ReturnCode.Ok)
                                                        break;
                                                }

                                                if (code == ReturnCode.Ok)
                                                    result = String.Empty;
                                            }
                                            else
                                            {
                                                code = ReturnCode.Error;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp delete ?path ...?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "enabled":
                                    {
                                        if ((arguments.Count >= 2) && (arguments.Count <= 4))
                                        {
                                            string path = (arguments.Count >= 3) ?
                                                (string)arguments[2] : String.Empty;

                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                bool enabled = false;

                                                if (arguments.Count >= 4)
                                                {
                                                    code = Value.GetBoolean2(
                                                        arguments[3], ValueFlags.AnyBoolean,
                                                        slaveInterpreter.CultureInfo, ref enabled,
                                                        ref result);

                                                    if (code == ReturnCode.Ok)
                                                        slaveInterpreter.Enabled = enabled;
                                                }

                                                if (code == ReturnCode.Ok)
                                                    result = slaveInterpreter.Enabled;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp enabled ?path? ?enabled?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "eval":
                                    {
                                        if (arguments.Count >= 4)
                                        {
                                            if (interpreter.HasSlaveInterpreters(ref result))
                                            {
                                                string path = arguments[2];
                                                Interpreter slaveInterpreter = null;

                                                code = interpreter.GetNestedSlaveInterpreter(
                                                    path, LookupFlags.Interpreter, false,
                                                    ref slaveInterpreter, ref result);

                                                if (code == ReturnCode.Ok)
                                                {
                                                    string name = StringList.MakeList("interp eval", path);

                                                    ICallFrame frame = interpreter.NewTrackingCallFrame(name,
                                                        CallFrameFlags.Evaluate);

                                                    interpreter.PushAutomaticCallFrame(frame);

                                                    if (arguments.Count == 4)
                                                        code = slaveInterpreter.EvaluateScript(arguments[3], ref result);
                                                    else
                                                        code = slaveInterpreter.EvaluateScript(arguments, 3, ref result);

                                                    if (code == ReturnCode.Error)
                                                        Engine.AddErrorInformation(interpreter, result,
                                                            String.Format("{0}    (in interp eval \"{1}\" script line {2})",
                                                                Environment.NewLine, path, Interpreter.GetErrorLine(slaveInterpreter)));

                                                    //
                                                    // NOTE: Pop the original call frame that we pushed above and 
                                                    //       any intervening scope call frames that may be leftover 
                                                    //       (i.e. they were not explicitly closed).
                                                    //
                                                    /* IGNORED */
                                                    interpreter.PopCallFrame(CallFrameFlags.Scope, true);
                                                }
                                            }
                                            else
                                            {
                                                code = ReturnCode.Error;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp eval path arg ?arg ...?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "exists":
                                    {
                                        if ((arguments.Count == 2) || (arguments.Count == 3))
                                        {
                                            string path = (arguments.Count == 3) ?
                                                (string)arguments[2] : String.Empty;

                                            result = (interpreter.DoesSlaveInterpreterExist(path) == ReturnCode.Ok);
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp exists ?path?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "expose":
                                    {
                                        if ((arguments.Count == 4) || (arguments.Count == 5))
                                        {
                                            string path = arguments[2];
                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                if (!interpreter.IsSafe())
                                                {
                                                    code = slaveInterpreter.ExposeCommand(arguments[3], ref result);

                                                    if (code == ReturnCode.Ok)
                                                        result = String.Empty;
                                                }
                                                else
                                                {
                                                    result = "permission denied: safe interpreter cannot expose commands";
                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp expose path hiddenCmdName ?cmdName?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "expr":
                                    {
                                        if (arguments.Count >= 4)
                                        {
                                            if (interpreter.HasSlaveInterpreters(ref result))
                                            {
                                                string path = arguments[2];
                                                Interpreter slaveInterpreter = null;

                                                code = interpreter.GetNestedSlaveInterpreter(
                                                    path, LookupFlags.Interpreter, false,
                                                    ref slaveInterpreter, ref result);

                                                if (code == ReturnCode.Ok)
                                                {
                                                    string name = StringList.MakeList("interp expr", path);

                                                    ICallFrame frame = interpreter.NewTrackingCallFrame(name,
                                                        CallFrameFlags.Expression);

                                                    interpreter.PushAutomaticCallFrame(frame);

                                                    //
                                                    // FIXME: The expression parser does not know the line where
                                                    //        the error happened unless it evaluates a command
                                                    //        contained within the expression.
                                                    //
                                                    Interpreter.SetErrorLine(slaveInterpreter, 0);

                                                    if (arguments.Count == 4)
                                                        code = slaveInterpreter.EvaluateExpression(arguments[3], ref result);
                                                    else
                                                        code = slaveInterpreter.EvaluateExpression(arguments, 3, ref result);

                                                    if (code == ReturnCode.Error)
                                                        Engine.AddErrorInformation(interpreter, result,
                                                            String.Format("{0}    (in interp expr \"{1}\" script line {2})",
                                                                Environment.NewLine, path, Interpreter.GetErrorLine(slaveInterpreter)));

                                                    //
                                                    // NOTE: Pop the original call frame that we pushed above and 
                                                    //       any intervening scope call frames that may be leftover 
                                                    //       (i.e. they were not explicitly closed).
                                                    //
                                                    /* IGNORED */
                                                    interpreter.PopCallFrame(CallFrameFlags.Scope, true);
                                                }
                                            }
                                            else
                                            {
                                                code = ReturnCode.Error;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp expr path arg ?arg ...?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "finallytimeout":
                                    {
                                        if ((arguments.Count >= 2) && (arguments.Count <= 4))
                                        {
                                            string path = (arguments.Count >= 3) ?
                                                (string)arguments[2] : String.Empty;

                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                if (arguments.Count >= 4)
                                                {
                                                    int timeout = _Timeout.None;

                                                    code = Value.GetInteger2(
                                                        (IGetValue)arguments[3], ValueFlags.AnyInteger,
                                                        slaveInterpreter.CultureInfo, ref timeout,
                                                        ref result);

                                                    if (code == ReturnCode.Ok)
                                                        slaveInterpreter.FinallyTimeout = timeout;
                                                }

                                                if (code == ReturnCode.Ok)
                                                    result = slaveInterpreter.FinallyTimeout;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp finallytimeout ?path? ?newValue?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "hide":
                                    {
                                        if ((arguments.Count == 4) || (arguments.Count == 5))
                                        {
                                            string path = arguments[2];
                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                if (!interpreter.IsSafe())
                                                {
                                                    code = slaveInterpreter.HideCommand(arguments[3], ref result);

                                                    if (code == ReturnCode.Ok)
                                                        result = String.Empty;
                                                }
                                                else
                                                {
                                                    result = "permission denied: safe interpreter cannot hide commands";
                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp hide path cmdName ?hiddenCmdName?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "hidden":
                                    {
                                        if (arguments.Count == 3)
                                        {
                                            string path = arguments[2];
                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                StringList list = null;

                                                code = slaveInterpreter.HiddenCommandsToList(
                                                    CommandFlags.Hidden, CommandFlags.None, false,
                                                    false, null, false, ref list, ref result);

                                                if (code == ReturnCode.Ok)
                                                    code = slaveInterpreter.HiddenProceduresToList(
                                                        ProcedureFlags.Hidden, ProcedureFlags.None, false,
                                                        false, null, false, ref list, ref result);

                                                if (code == ReturnCode.Ok)
                                                    result = list;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp hidden path\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "immutable":
                                    {
                                        if ((arguments.Count >= 2) && (arguments.Count <= 4))
                                        {
                                            string path = (arguments.Count >= 3) ?
                                                (string)arguments[2] : String.Empty;

                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                bool immutable = false;

                                                if (arguments.Count >= 4)
                                                {
                                                    code = Value.GetBoolean2(
                                                        arguments[3], ValueFlags.AnyBoolean,
                                                        slaveInterpreter.CultureInfo, ref immutable, ref result);

                                                    if (code == ReturnCode.Ok)
                                                        slaveInterpreter.Immutable = immutable;
                                                }

                                                if (code == ReturnCode.Ok)
                                                    result = slaveInterpreter.Immutable;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp immutable ?path? ?immutable?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "invokehidden":
                                    {
                                        if (arguments.Count >= 4)
                                        {
                                            string path = arguments[2];
                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                OptionDictionary options = new OptionDictionary(
                                                    new Option[] {
                                                    new Option(null, OptionFlags.None, Index.Invalid,
                                                        Index.Invalid, "-global", null),
                                                    new Option(null, OptionFlags.MustHaveAbsoluteNamespaceValue,
                                                        Index.Invalid, Index.Invalid, "-namespace", null),
                                                    new Option(null, OptionFlags.None, Index.Invalid,
                                                        Index.Invalid, Option.EndOfOptions, null)
                                                });

                                                int argumentIndex = Index.Invalid;

                                                code = slaveInterpreter.GetOptions(
                                                    options, arguments, 0, 3, Index.Invalid, true,
                                                    ref argumentIndex, ref result);

                                                if (code == ReturnCode.Ok)
                                                {
                                                    if (argumentIndex != Index.Invalid)
                                                    {
                                                        bool global = false;

                                                        if (options.IsPresent("-global"))
                                                            global = true;

                                                        Variant value = null;
                                                        INamespace @namespace = null;

                                                        if (options.IsPresent("-namespace", ref value))
                                                            @namespace = (INamespace)value.Value;

                                                        string executeName = arguments[argumentIndex];
                                                        IExecute execute = null;

                                                        code = slaveInterpreter.GetIExecuteViaResolvers(
                                                            slaveInterpreter.GetResolveEngineFlags(true) |
                                                            EngineFlags.UseHidden, executeName, null,
                                                            LookupFlags.Default, ref execute, ref result);

                                                        if (code == ReturnCode.Ok)
                                                        {
                                                            //
                                                            // NOTE: Figure out the arguments for the command to
                                                            //       be executed.
                                                            //
                                                            ArgumentList executeArguments =
                                                                ArgumentList.GetRange(arguments, argumentIndex);

                                                            //
                                                            // NOTE: Create and push a new call frame to track the
                                                            //       activation of this alias.
                                                            //
                                                            string name = StringList.MakeList(
                                                                "interp invokehidden", executeName);

                                                            ICallFrame frame = interpreter.NewTrackingCallFrame(
                                                                name, CallFrameFlags.Interpreter);

                                                            interpreter.PushAutomaticCallFrame(frame);

                                                            ICallFrame nestedFrame = null;

                                                            if (!global && (@namespace != null))
                                                            {
                                                                string nestedName = StringList.MakeList(
                                                                    "namespace eval", @namespace.QualifiedName);

                                                                nestedFrame = slaveInterpreter.NewNamespaceCallFrame(
                                                                    nestedName, CallFrameFlags.Evaluate |
                                                                    CallFrameFlags.UseNamespace, null, @namespace,
                                                                    false);

                                                                slaveInterpreter.PushNamespaceCallFrame(nestedFrame);
                                                            }

                                                            //
                                                            // NOTE: Execute the command in the global scope?
                                                            //
                                                            if (global)
                                                                slaveInterpreter.PushGlobalCallFrame(true);
                                                            else if (nestedFrame != null)
                                                                slaveInterpreter.PushNamespaceCallFrame(nestedFrame);

                                                            //
                                                            // NOTE: Save the current engine flags and then enable
                                                            //       the external execution flags.
                                                            //
                                                            EngineFlags savedEngineFlags =
                                                                slaveInterpreter.BeginExternalExecution();

                                                            //
                                                            // NOTE: Execute the hidden command now.
                                                            //
                                                            code = slaveInterpreter.ExecuteHidden(
                                                                executeName, execute, clientData, executeArguments,
                                                                ref result);

                                                            //
                                                            // NOTE: Restore the saved engine flags, masking off the
                                                            //       external execution flags as necessary.
                                                            //
                                                            /* IGNORED */
                                                            slaveInterpreter.EndAndCleanupExternalExecution(
                                                                savedEngineFlags);

                                                            //
                                                            // NOTE: If we previously pushed the global call frame
                                                            //       (above), we also need to pop any leftover scope
                                                            //       call frames now; otherwise, the call stack will
                                                            //       be imbalanced.
                                                            //
                                                            if (global)
                                                                slaveInterpreter.PopGlobalCallFrame(true);
                                                            else if (nestedFrame != null)
                                                                slaveInterpreter.PopNamespaceCallFrame(nestedFrame);

                                                            //
                                                            // NOTE: Pop the original call frame that we pushed above
                                                            //       and any intervening scope call frames that may be
                                                            //       leftover (i.e. they were not explicitly closed).
                                                            //
                                                            /* IGNORED */
                                                            interpreter.PopCallFrame(CallFrameFlags.Scope, true);
                                                        }
                                                    }
                                                    else
                                                    {
                                                        result = "wrong # args: should be \"interp invokehidden path ?options? cmd ?arg ..?\"";
                                                        code = ReturnCode.Error;
                                                    }
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp invokehidden path ?options? cmd ?arg ..?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "issafe":
                                    {
                                        if ((arguments.Count == 2) || (arguments.Count == 3))
                                        {
                                            string path = (arguments.Count == 3) ?
                                                (string)arguments[2] : String.Empty;

                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                                result = slaveInterpreter.IsSafe();
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp issafe ?path?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "isstandard":
                                    {
                                        if ((arguments.Count == 2) || (arguments.Count == 3))
                                        {
                                            string path = (arguments.Count == 3) ?
                                                (string)arguments[2] : String.Empty;

                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                                result = slaveInterpreter.IsStandard();
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp isstandard ?path?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "makesafe":
                                    {
                                        if ((arguments.Count >= 2) && (arguments.Count <= 5))
                                        {
                                            string path = (arguments.Count >= 3) ?
                                                (string)arguments[2] : String.Empty;

                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                if (!interpreter.IsSafe())
                                                {
                                                    bool safe = true;

                                                    if (arguments.Count >= 4)
                                                    {
                                                        code = Value.GetBoolean2(
                                                            arguments[3], ValueFlags.AnyBoolean,
                                                            slaveInterpreter.CultureInfo,
                                                            ref safe, ref result);
                                                    }

                                                    MakeFlags makeFlags = MakeFlags.SafeLibrary;

                                                    if (code == ReturnCode.Ok)
                                                    {
                                                        if (arguments.Count >= 5)
                                                        {
                                                            object enumValue = EnumOps.TryParseFlagsEnum(
                                                                slaveInterpreter, typeof(MakeFlags),
                                                                makeFlags.ToString(), arguments[4],
                                                                slaveInterpreter.CultureInfo, true, true,
                                                                ref result);

                                                            if (enumValue is MakeFlags)
                                                                makeFlags = (MakeFlags)enumValue;
                                                            else
                                                                code = ReturnCode.Error;
                                                        }
                                                    }

                                                    if (code == ReturnCode.Ok)
                                                    {
                                                        if (safe != slaveInterpreter.IsSafe())
                                                        {
                                                            code = slaveInterpreter.MakeSafe(
                                                                makeFlags, safe, ref result);
                                                        }
                                                        else
                                                        {
                                                            result = String.Format(
                                                                "interpreter is already marked as \"{0}\"",
                                                                slaveInterpreter.IsSafe() ?
                                                                    "safe" : "unsafe");

                                                            code = ReturnCode.Error;
                                                        }
                                                    }
                                                }
                                                else
                                                {
                                                    result = "permission denied: safe interpreter cannot modify safety";
                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp makesafe ?path? ?safe? ?all?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "makestandard":
                                    {
                                        if ((arguments.Count >= 2) && (arguments.Count <= 5))
                                        {
                                            string path = (arguments.Count >= 3) ?
                                                (string)arguments[2] : String.Empty;

                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                if (!interpreter.IsSafe())
                                                {
                                                    bool standard = true;

                                                    if (arguments.Count >= 4)
                                                    {
                                                        code = Value.GetBoolean2(
                                                            arguments[3], ValueFlags.AnyBoolean,
                                                            slaveInterpreter.CultureInfo,
                                                            ref standard, ref result);
                                                    }

                                                    MakeFlags makeFlags = MakeFlags.StandardLibrary;

                                                    if (code == ReturnCode.Ok)
                                                    {
                                                        if (arguments.Count >= 5)
                                                        {
                                                            object enumValue = EnumOps.TryParseFlagsEnum(
                                                                slaveInterpreter, typeof(MakeFlags),
                                                                makeFlags.ToString(), arguments[4],
                                                                slaveInterpreter.CultureInfo, true, true,
                                                                ref result);

                                                            if (enumValue is MakeFlags)
                                                                makeFlags = (MakeFlags)enumValue;
                                                            else
                                                                code = ReturnCode.Error;
                                                        }
                                                    }

                                                    if (code == ReturnCode.Ok)
                                                    {
                                                        if (standard != slaveInterpreter.IsStandard())
                                                        {
                                                            code = slaveInterpreter.MakeStandard(
                                                                makeFlags, standard, ref result);
                                                        }
                                                        else
                                                        {
                                                            result = String.Format(
                                                                "interpreter is already marked as \"{0}\"",
                                                                slaveInterpreter.IsStandard() ?
                                                                    "standard" : "non-standard");

                                                            code = ReturnCode.Error;
                                                        }
                                                    }
                                                }
                                                else
                                                {
                                                    result = "permission denied: safe interpreter cannot modify standardization";
                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp makestandard ?path? ?standard? ?all?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "marktrusted":
                                    {
                                        if (arguments.Count == 3)
                                        {
                                            string path = arguments[2];
                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                if (!interpreter.IsSafe())
                                                {
                                                    code = slaveInterpreter.MarkTrusted(ref result);

                                                    if (code == ReturnCode.Ok)
                                                        result = String.Empty;
                                                }
                                                else
                                                {
                                                    result = "permission denied: safe interpreter cannot mark trusted";
                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp marktrusted path\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "nopolicy":
                                    {
                                        if (arguments.Count == 4)
                                        {
                                            string path = arguments[2];
                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                if (!interpreter.IsSafe())
                                                {
                                                    code = slaveInterpreter.RemovePolicy(
                                                        arguments[3], clientData, ref result);

                                                    if (code == ReturnCode.Ok)
                                                        result = String.Empty;
                                                }
                                                else
                                                {
                                                    result = "permission denied: safe interpreter cannot remove policy";
                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp nopolicy path name\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "policy":
                                    {
                                        if (arguments.Count >= 4)
                                        {
                                            OptionDictionary options = new OptionDictionary(
                                                new Option[] {
                                                new Option(null, OptionFlags.MustHaveTypeValue, Index.Invalid, Index.Invalid, "-type", null),
                                                new Option(null, OptionFlags.MustHaveWideIntegerValue, Index.Invalid, Index.Invalid, "-token", null),
                                                new Option(typeof(PolicyFlags), OptionFlags.MustHaveEnumValue, Index.Invalid, Index.Invalid, "-flags",
                                                    new Variant(PolicyFlags.Script)),
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, Option.EndOfOptions, null)
                                            });

                                            int argumentIndex = Index.Invalid;

                                            code = interpreter.GetOptions(options, arguments, 0, 2, Index.Invalid, true, ref argumentIndex, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                if ((argumentIndex != Index.Invalid) &&
                                                    ((argumentIndex + 2) == arguments.Count))
                                                {
                                                    Variant value = null;
                                                    Type type = null;

                                                    if (options.IsPresent("-type", ref value))
                                                        type = (Type)value.Value;

                                                    long token = 0;

                                                    if (options.IsPresent("-token", ref value))
                                                        token = (long)value.Value;

                                                    PolicyFlags flags = PolicyFlags.Script;

                                                    if (options.IsPresent("-flags", ref value))
                                                        flags = (PolicyFlags)value.Value;

                                                    string path = arguments[argumentIndex];
                                                    Interpreter slaveInterpreter = null;

                                                    code = interpreter.GetNestedSlaveInterpreter(
                                                        path, LookupFlags.Interpreter, false,
                                                        ref slaveInterpreter, ref result);

                                                    if (code == ReturnCode.Ok)
                                                    {
                                                        if (!interpreter.IsSafe())
                                                        {
                                                            if ((type != null) || (token != 0))
                                                            {
                                                                IPlugin plugin = slaveInterpreter.GetCorePlugin(ref result);

                                                                if (plugin != null)
                                                                {
                                                                    code = slaveInterpreter.AddScriptPolicy(
                                                                        flags, type, token, interpreter,
                                                                        arguments[argumentIndex + 1],
                                                                        plugin, clientData, ref result);
                                                                }
                                                                else
                                                                {
                                                                    code = ReturnCode.Error;
                                                                }
                                                            }
                                                            else
                                                            {
                                                                result = "option \"-type\" or \"-token\" must be specified";
                                                                code = ReturnCode.Error;
                                                            }
                                                        }
                                                        else
                                                        {
                                                            result = "permission denied: safe interpreter cannot add policy";
                                                            code = ReturnCode.Error;
                                                        }
                                                    }
                                                }
                                                else
                                                {
                                                    if ((argumentIndex != Index.Invalid) &&
                                                        Option.LooksLikeOption(arguments[argumentIndex]))
                                                    {
                                                        result = OptionDictionary.BadOption(options, arguments[argumentIndex]);
                                                    }
                                                    else
                                                    {
                                                        result = "wrong # args: should be \"interp policy ?options? path script\"";
                                                    }

                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp policy ?options? path script\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "queue":
                                    {
                                        if (arguments.Count >= 4)
                                        {
                                            OptionDictionary options = new OptionDictionary(
                                                new Option[] {
                                                new Option(null, OptionFlags.MustHaveDateTimeValue, Index.Invalid, Index.Invalid, "-when", null),
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, Option.EndOfOptions, null)
                                            });

                                            int argumentIndex = Index.Invalid;

                                            code = interpreter.GetOptions(options, arguments, 0, 3, Index.Invalid, true, ref argumentIndex, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                if (argumentIndex != Index.Invalid)
                                                {
                                                    Variant value = null;
                                                    DateTime dateTime = TimeOps.GetUtcNow();

                                                    if (options.IsPresent("-when", ref value))
                                                        dateTime = (DateTime)value.Value;

                                                    string path = arguments[2];
                                                    Interpreter slaveInterpreter = null;

                                                    code = interpreter.GetNestedSlaveInterpreter(
                                                        path, LookupFlags.Interpreter, false,
                                                        ref slaveInterpreter, ref result);

                                                    if (code == ReturnCode.Ok)
                                                    {
                                                        string text = null;

                                                        if ((argumentIndex + 1) == arguments.Count)
                                                            text = arguments[argumentIndex];
                                                        else
                                                            text = ListOps.Concat(arguments, argumentIndex);

                                                        code = slaveInterpreter.QueueScript(dateTime, text, ref result);
                                                    }
                                                }
                                                else
                                                {
                                                    result = "wrong # args: should be \"interp queue path ?options? arg ?arg ...?\"";
                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp queue path ?options? arg ?arg ...?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "readonly":
                                    {
                                        if ((arguments.Count >= 2) && (arguments.Count <= 4))
                                        {
                                            string path = (arguments.Count >= 3) ?
                                                (string)arguments[2] : String.Empty;

                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                bool readOnly = false;

                                                if (arguments.Count >= 4)
                                                {
                                                    code = Value.GetBoolean2(
                                                        arguments[3], ValueFlags.AnyBoolean,
                                                        slaveInterpreter.CultureInfo, ref readOnly, ref result);

                                                    if (code == ReturnCode.Ok)
                                                        slaveInterpreter.ReadOnly = readOnly;
                                                }

                                                if (code == ReturnCode.Ok)
                                                    result = slaveInterpreter.ReadOnly;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp readonly ?path? ?readonly?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "readorgetscriptfile":
                                    {
                                        if (arguments.Count >= 3)
                                        {
                                            OptionDictionary options = new OptionDictionary(
                                                new Option[] { 
                                                new Option(null, OptionFlags.MustHaveValue,
                                                    Index.Invalid, Index.Invalid, "-encoding", null),
                                                new Option(null, OptionFlags.None, Index.Invalid,
                                                    Index.Invalid, Option.EndOfOptions, null)
                                            });

                                            int argumentIndex = Index.Invalid;

                                            code = interpreter.GetOptions(
                                                options, arguments, 0, 2, Index.Invalid, false,
                                                ref argumentIndex, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                if ((argumentIndex != Index.Invalid) &&
                                                    ((argumentIndex + 1) == arguments.Count))
                                                {
                                                    Variant value = null;
                                                    string encodingName = null;

                                                    if (options.IsPresent("-encoding", ref value))
                                                        encodingName = value.ToString();

                                                    Encoding encoding = null;

                                                    if (encodingName != null)
                                                    {
                                                        code = Interpreter.GetEncoding(
                                                            interpreter, encodingName, ref encoding,
                                                            ref result);
                                                    }

                                                    if (code == ReturnCode.Ok)
                                                    {
                                                        string fileName = arguments[argumentIndex];

                                                        if (!String.IsNullOrEmpty(fileName))
                                                        {
                                                            EngineFlags engineFlags = interpreter.EngineFlags;
                                                            SubstitutionFlags substitutionFlags = interpreter.SubstitutionFlags;
                                                            EventFlags eventFlags = interpreter.EngineEventFlags;
                                                            ExpressionFlags expressionFlags = interpreter.ExpressionFlags;
                                                            string text = null;

                                                            code = Engine.ReadOrGetScriptFile(
                                                                interpreter, encoding, ref fileName, ref engineFlags,
                                                                ref substitutionFlags, ref eventFlags, ref expressionFlags,
                                                                ref text, ref result);

                                                            if (code == ReturnCode.Ok)
                                                                result = text;
                                                        }
                                                        else
                                                        {
                                                            result = "invalid file name";
                                                            code = ReturnCode.Error;
                                                        }
                                                    }
                                                }
                                                else
                                                {
                                                    if ((argumentIndex != Index.Invalid) &&
                                                        Option.LooksLikeOption(arguments[argumentIndex]))
                                                    {
                                                        result = OptionDictionary.BadOption(options, arguments[argumentIndex]);
                                                    }
                                                    else
                                                    {
                                                        result = "wrong # args: should be \"interp readorgetscriptfile ?options? fileName\"";
                                                    }

                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp readorgetscriptfile ?options? fileName\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "readylimit":
                                    {
                                        if ((arguments.Count == 3) || (arguments.Count == 4))
                                        {
                                            string path = arguments[2];
                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                int readyLimit = 0;

                                                if (arguments.Count == 4)
                                                {
                                                    code = Value.GetInteger2(
                                                        (IGetValue)arguments[3], ValueFlags.AnyInteger,
                                                        slaveInterpreter.CultureInfo, ref readyLimit,
                                                        ref result);

                                                    if (code == ReturnCode.Ok)
                                                        slaveInterpreter.ReadyLimit = readyLimit;
                                                }

                                                if (code == ReturnCode.Ok)
                                                    result = slaveInterpreter.ReadyLimit;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp readylimit path ?limit?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "recursionlimit":
                                    {
                                        if ((arguments.Count == 3) || (arguments.Count == 4))
                                        {
                                            string path = arguments[2];
                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                int recursionLimit = 0;

                                                if (arguments.Count == 4)
                                                {
                                                    code = Value.GetInteger2(
                                                        (IGetValue)arguments[3], ValueFlags.AnyInteger,
                                                        slaveInterpreter.CultureInfo, ref recursionLimit,
                                                        ref result);

                                                    if (code == ReturnCode.Ok)
                                                        slaveInterpreter.RecursionLimit = recursionLimit;
                                                }

                                                if (code == ReturnCode.Ok)
                                                    result = slaveInterpreter.RecursionLimit;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp recursionlimit path ?limit?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "resetcancel":
                                    {
                                        if (arguments.Count >= 3)
                                        {
                                            OptionDictionary options = new OptionDictionary(
                                                new Option[] {
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-force", null),
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, Option.EndOfOptions, null)
                                            });

                                            int argumentIndex = Index.Invalid;

                                            if (arguments.Count > 3)
                                                code = interpreter.GetOptions(options, arguments, 0, 3, Index.Invalid, true, ref argumentIndex, ref result);
                                            else
                                                code = ReturnCode.Ok;

                                            if (code == ReturnCode.Ok)
                                            {
                                                if (argumentIndex == Index.Invalid)
                                                {
                                                    bool force = false;

                                                    if (options.IsPresent("-force"))
                                                        force = true;

                                                    string path = arguments[2];
                                                    Interpreter slaveInterpreter = null;

                                                    code = interpreter.GetNestedSlaveInterpreter(
                                                        path, LookupFlags.Interpreter, false,
                                                        ref slaveInterpreter, ref result);

                                                    if (code == ReturnCode.Ok)
                                                    {
                                                        //
                                                        // NOTE: This really only works for the current interpreter
                                                        //       if the cancel was not specified with the unwind
                                                        //       flag; otherwise, this command will never actually
                                                        //       get a chance to execute.  For interpreters other
                                                        //       than the current interpreter, this will always
                                                        //       "just work".
                                                        //
                                                        bool reset = false;

                                                        code = Engine.ResetCancel(slaveInterpreter, force, ref reset, ref result);

                                                        if (code == ReturnCode.Ok)
                                                            result = reset;
                                                    }
                                                }
                                                else
                                                {
                                                    result = "wrong # args: should be \"interp resetcancel path ?options?\"";
                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp resetcancel path ?options?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "service":
                                    {
                                        if (arguments.Count >= 3)
                                        {
                                            string path = arguments[2];
                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                OptionDictionary options = new OptionDictionary(
                                                    new Option[] {
                                                    new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-dedicated", null),
                                                    new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-nocancel", null),
                                                    new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-erroronempty", null),
                                                    new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-userinterface", null),
                                                    new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-nocomplain", null),
                                                    new Option(null, OptionFlags.MustHaveIntegerValue, Index.Invalid, Index.Invalid, "-limit", null),
                                                    new Option(typeof(EventFlags), OptionFlags.MustHaveEnumValue, Index.Invalid, Index.Invalid, "-flags",
                                                        new Variant(slaveInterpreter.ServiceEventFlags)),
                                                    new Option(typeof(EventPriority), OptionFlags.MustHaveEnumValue, Index.Invalid, Index.Invalid, "-priority",
                                                        new Variant(EventPriority.Service)),
                                                    new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, Option.EndOfOptions, null)
                                                });

                                                int argumentIndex = Index.Invalid;

                                                if (arguments.Count > 3)
                                                    code = interpreter.GetOptions(options, arguments, 0, 3, Index.Invalid, true, ref argumentIndex, ref result);
                                                else
                                                    code = ReturnCode.Ok;

                                                if (code == ReturnCode.Ok)
                                                {
                                                    if (argumentIndex == Index.Invalid)
                                                    {
                                                        bool dedicated = false;

                                                        if (options.IsPresent("-dedicated"))
                                                            dedicated = true;

                                                        bool noCancel = false;

                                                        if (options.IsPresent("-nocancel"))
                                                            noCancel = true;

                                                        bool stopOnError = true;

                                                        if (options.IsPresent("-nocomplain"))
                                                            stopOnError = false;

                                                        bool errorOnEmpty = false;

                                                        if (options.IsPresent("-erroronempty"))
                                                            errorOnEmpty = true;

                                                        bool userInterface = false;

                                                        if (options.IsPresent("-userinterface"))
                                                            userInterface = true;

                                                        Variant value = null;
                                                        int limit = 0;

                                                        if (options.IsPresent("-limit", ref value))
                                                            limit = (int)value.Value;

                                                        EventFlags flags = slaveInterpreter.ServiceEventFlags;

                                                        if (options.IsPresent("-flags", ref value))
                                                            flags = (EventFlags)value.Value;

                                                        EventPriority priority = EventPriority.Service;

                                                        if (options.IsPresent("-priority", ref value))
                                                            priority = (EventPriority)value.Value;

                                                        if (dedicated)
                                                        {
                                                            try
                                                            {
                                                                if (Engine.QueueWorkItem(slaveInterpreter,
                                                                        EventManager.ServiceEventsThreadStart, slaveInterpreter))
                                                                {
                                                                    result = String.Empty;
                                                                    code = ReturnCode.Ok;
                                                                }
                                                                else
                                                                {
                                                                    result = "failed to queue event servicing work item";
                                                                    code = ReturnCode.Error;
                                                                }
                                                            }
                                                            catch (Exception e)
                                                            {
                                                                Engine.SetExceptionErrorCode(interpreter, e);

                                                                result = e;
                                                                code = ReturnCode.Error;
                                                            }
                                                        }
                                                        else
                                                        {
                                                            IEventManager eventManager = slaveInterpreter.EventManager;

                                                            if (EventOps.ManagerIsOk(eventManager))
                                                            {
                                                                code = eventManager.ServiceEvents(
                                                                    flags, priority, limit, noCancel, stopOnError,
                                                                    errorOnEmpty, userInterface, ref result);
                                                            }
                                                            else
                                                            {
                                                                result = "event manager not available";
                                                                code = ReturnCode.Error;
                                                            }
                                                        }
                                                    }
                                                    else
                                                    {
                                                        result = "wrong # args: should be \"interp service path ?options?\"";
                                                        code = ReturnCode.Error;
                                                    }
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp service path ?options?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "set":
                                    {
                                        if ((arguments.Count == 4) || (arguments.Count == 5))
                                        {
                                            string path = arguments[2];
                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                Result value;

                                                if (arguments.Count == 4)
                                                {
                                                    value = null;

                                                    code = slaveInterpreter.GetVariableValue(
                                                        VariableFlags.None, arguments[3], ref value, ref result);

                                                    if (code == ReturnCode.Ok)
                                                        result = value;
                                                }
                                                else if (arguments.Count == 5)
                                                {
                                                    value = arguments[4];

                                                    code = slaveInterpreter.SetVariableValue(
                                                        VariableFlags.None, arguments[3], value, ref result);

                                                    if (code == ReturnCode.Ok)
                                                        result = value;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp set interp varName ?newValue?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "slaves":
                                    {
                                        if ((arguments.Count == 2) || (arguments.Count == 3))
                                        {
                                            string path = (arguments.Count == 3) ?
                                                (string)arguments[2] : String.Empty;

                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                if (slaveInterpreter.HasSlaveInterpreters(ref result))
                                                {
                                                    result = slaveInterpreter.SlaveInterpretersToString(null, false);
                                                    code = ReturnCode.Ok;
                                                }
                                                else
                                                {
                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp slaves ?path?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "sleeptime":
                                    {
                                        if ((arguments.Count >= 2) && (arguments.Count <= 4))
                                        {
                                            string path = (arguments.Count >= 3) ?
                                                (string)arguments[2] : String.Empty;

                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                if (arguments.Count >= 4)
                                                {
                                                    int sleepTime = 0;

                                                    code = Value.GetInteger2(
                                                        (IGetValue)arguments[3], ValueFlags.AnyInteger,
                                                        slaveInterpreter.CultureInfo, ref sleepTime,
                                                        ref result);

                                                    if (code == ReturnCode.Ok)
                                                        slaveInterpreter.SleepTime = sleepTime;
                                                }

                                                if (code == ReturnCode.Ok)
                                                    result = slaveInterpreter.SleepTime;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp sleeptime ?path? ?newValue?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "subst":
                                    {
                                        if (arguments.Count >= 4)
                                        {
                                            OptionDictionary options = new OptionDictionary(
                                                new Option[] {
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-nobackslashes", null),
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-nocommands", null),
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-novariables", null),
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, Option.EndOfOptions, null)
                                            });

                                            int argumentIndex = Index.Invalid;

                                            code = interpreter.GetOptions(options, arguments, 0, 2, Index.Invalid, false, ref argumentIndex, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                if ((argumentIndex != Index.Invalid) &&
                                                    ((argumentIndex + 2) == arguments.Count))
                                                {
                                                    SubstitutionFlags substitutionFlags = SubstitutionFlags.Default;

                                                    if (options.IsPresent("-nobackslashes"))
                                                        substitutionFlags &= ~SubstitutionFlags.Backslashes;

                                                    if (options.IsPresent("-nocommands"))
                                                        substitutionFlags &= ~SubstitutionFlags.Commands;

                                                    if (options.IsPresent("-novariables"))
                                                        substitutionFlags &= ~SubstitutionFlags.Variables;

                                                    if (interpreter.HasSlaveInterpreters(ref result))
                                                    {
                                                        string path = arguments[argumentIndex];
                                                        Interpreter slaveInterpreter = null;

                                                        code = interpreter.GetNestedSlaveInterpreter(
                                                            path, LookupFlags.Interpreter, false,
                                                            ref slaveInterpreter, ref result);

                                                        if (code == ReturnCode.Ok)
                                                        {
                                                            string name = StringList.MakeList("interp subst", path);

                                                            ICallFrame frame = interpreter.NewTrackingCallFrame(name,
                                                                CallFrameFlags.Substitute);

                                                            interpreter.PushAutomaticCallFrame(frame);

                                                            code = slaveInterpreter.SubstituteString(
                                                                arguments[argumentIndex + 1], substitutionFlags, ref result);

                                                            if (code == ReturnCode.Error)
                                                                Engine.AddErrorInformation(interpreter, result,
                                                                    String.Format("{0}    (in interp subst \"{1}\" script line {2})",
                                                                        Environment.NewLine, path, Interpreter.GetErrorLine(slaveInterpreter)));

                                                            //
                                                            // NOTE: Pop the original call frame that we pushed above and 
                                                            //       any intervening scope call frames that may be leftover 
                                                            //       (i.e. they were not explicitly closed).
                                                            //
                                                            /* IGNORED */
                                                            interpreter.PopCallFrame(CallFrameFlags.Scope, true);
                                                        }
                                                    }
                                                    else
                                                    {
                                                        code = ReturnCode.Error;
                                                    }
                                                }
                                                else
                                                {
                                                    if ((argumentIndex != Index.Invalid) &&
                                                        Option.LooksLikeOption(arguments[argumentIndex]))
                                                    {
                                                        result = OptionDictionary.BadOption(options, arguments[argumentIndex]);
                                                    }
                                                    else
                                                    {
                                                        result = "wrong # args: should be \"interp subst ?options? path string\"";
                                                    }

                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp subst ?options? path string\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "target":
                                    {
                                        if (arguments.Count == 4)
                                        {
                                            string path = arguments[2];
                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                string sourceName = arguments[3];
                                                IAlias alias = null;

                                                code = slaveInterpreter.GetAlias(
                                                    sourceName, LookupFlags.Default,
                                                    ref alias, ref result);

                                                if (code == ReturnCode.Ok)
                                                {
                                                    code = interpreter.GetInterpreterPath(
                                                        alias.TargetInterpreter, ref result);

                                                    if (code != ReturnCode.Ok)
                                                        result = String.Format(
                                                            "target interpreter for alias \"{0}\" " +
                                                            "in path \"{1}\" is not my descendant",
                                                            sourceName, path);
                                                }
                                                else
                                                {
                                                    //
                                                    // NOTE: Modify the error message (COMPAT: Tcl).
                                                    //
                                                    result = String.Format(
                                                        "alias \"{0}\" in path \"{1}\" not found",
                                                        sourceName, path);
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp target path alias\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "timeout":
                                    {
                                        if ((arguments.Count >= 2) && (arguments.Count <= 4))
                                        {
                                            string path = (arguments.Count >= 3) ?
                                                (string)arguments[2] : String.Empty;

                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                if (arguments.Count >= 4)
                                                {
                                                    int timeout = _Timeout.None;

                                                    code = Value.GetInteger2(
                                                        (IGetValue)arguments[3], ValueFlags.AnyInteger,
                                                        slaveInterpreter.CultureInfo, ref timeout,
                                                        ref result);

                                                    if (code == ReturnCode.Ok)
                                                        slaveInterpreter.Timeout = timeout;
                                                }

                                                if (code == ReturnCode.Ok)
                                                    result = slaveInterpreter.Timeout;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp timeout ?path? ?newValue?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "unset":
                                    {
                                        if (arguments.Count == 4)
                                        {
                                            string path = arguments[2];
                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                code = interpreter.UnsetVariable(
                                                    VariableFlags.NoRemove, arguments[3], ref result);

                                                if (code == ReturnCode.Ok)
                                                    result = String.Empty;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp unset interp varName\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "watchdog":
                                    {
                                        if ((arguments.Count >= 2) && (arguments.Count <= 4))
                                        {
                                            string path = (arguments.Count >= 3) ?
                                                (string)arguments[2] : String.Empty;

                                            Interpreter slaveInterpreter = null;

                                            code = interpreter.GetNestedSlaveInterpreter(
                                                path, LookupFlags.Interpreter, false,
                                                ref slaveInterpreter, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                bool boolValue = false;

                                                if (arguments.Count >= 4)
                                                {
                                                    code = Value.GetBoolean2(
                                                        arguments[3], ValueFlags.AnyBoolean,
                                                        slaveInterpreter.CultureInfo, ref boolValue, ref result);

                                                    if (code == ReturnCode.Ok)
                                                    {
                                                        if (boolValue)
                                                            code = Interpreter.StartTimeoutThread(
                                                                slaveInterpreter, true, true, ref result);
                                                        else
                                                            code = Interpreter.InterruptTimeoutThread(
                                                                slaveInterpreter, true, ref result);
                                                    }
                                                }
                                                else
                                                {
                                                    boolValue = Interpreter.HasTimeoutThread(slaveInterpreter);
                                                }

                                                if (code == ReturnCode.Ok)
                                                    result = boolValue;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"interp watchdog ?path? ?enabled?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                default:
                                    {
                                        result = ScriptOps.BadSubCommand(null, null, subCommand, this, null, null);
                                        code = ReturnCode.Error;
                                        break;
                                    }
                            }
                        }
                    }
                    else
                    {
                        result = "wrong # args: should be \"interp cmd ?arg ...?\"";
                        code = ReturnCode.Error;
                    }
                }
                else
                {
                    result = "invalid argument list";
                    code = ReturnCode.Error;
                }
            }
            else
            {
                result = "invalid interpreter";
                code = ReturnCode.Error;
            }

            return code;
        }
        #endregion
    }
}
