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

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

namespace Eagle._Commands
{
    [ObjectId("74ca173d-5378-4eb2-9d7c-4952ce598b33")]
    [CommandFlags(CommandFlags.NativeCode | CommandFlags.Unsafe | CommandFlags.NonStandard)]
    [ObjectGroup("nativeEnvironment")]
    internal sealed class Tcl : Core
    {
        public Tcl(
            ICommandData commandData
            )
            : base(commandData)
        {
            // do nothing.
        }

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

        #region IEnsemble Members
        private static readonly EnsembleDictionary subCommands = new EnsembleDictionary(new string[] {
            "active", "cancel", "canceled", "command", "complete",
            "convert", "create", "delete", "errorline", "eval",
            "exceptions", "exists", "expr", "find", "interps",
            "load", "master", "module", "preserve", "queue",
            "ready", "recordandeval", "release", "resetcancel",
            "select", "set", "source", "subst", "threads",
            "types", "unload", "unset", "update", "versionrange"
        });

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

        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;

            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 "active":
                                    {
                                        //
                                        // NOTE: We support the full TIP #335 semantics.  Please refer to
                                        //       "http://tip.tcl.tk/335" for more information.
                                        //
                                        if (arguments.Count == 3)
                                        {
                                            IntPtr interp = IntPtr.Zero;

                                            code = interpreter.GetTclInterpreter(
                                                arguments[2], LookupFlags.Default,
                                                ref interp, ref result);

                                            if (code == ReturnCode.Ok)
                                                result = TclWrapper.GetInterpActive(TclApi.GetTclApi(interpreter), interp);
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl active interp\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "cancel":
                                    {
                                        //
                                        // NOTE: We support the full TIP #285 semantics.  Please refer to
                                        //       "http://tip.tcl.tk/285" for more information.
                                        //
                                        if (arguments.Count >= 3)
                                        {
                                            if (interpreter.HasTclInterpreters(ref result))
                                            {
                                                OptionDictionary options = new OptionDictionary(
                                                    new Option[] {
                                                    new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-time", null),
                                                    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;

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

                                                if (code == ReturnCode.Ok)
                                                {
                                                    IntPtr interp = IntPtr.Zero;
                                                    Result cancelResult = null;

                                                    if (argumentIndex != Index.Invalid)
                                                    {
                                                        if ((argumentIndex + 2) >= arguments.Count)
                                                        {
                                                            code = interpreter.GetTclInterpreter(
                                                                arguments[argumentIndex], LookupFlags.Default,
                                                                ref interp, ref result);

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

                                                            code = ReturnCode.Error;
                                                        }
                                                    }
                                                    else
                                                    {
                                                        //
                                                        // NOTE: Interpreter path is REQUIRED for the Tcl command, since we do
                                                        //       not have the concept of "current interpreter" on the Tcl side.
                                                        //
                                                        result = "wrong # args: should be \"tcl cancel ?options? path ?result?\"";
                                                        code = ReturnCode.Error;
                                                    }

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

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

                                                        bool unwind = false;

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

                                                        IClientData performanceClientData = time ?
                                                            new PerformanceClientData(null, unwind ?
                                                                "UnwindTclEvaluate" : "CancelTclEvaluate",
                                                                false) : null;

                                                        code = TclWrapper.CancelEvaluate(
                                                            TclApi.GetTclApi(interpreter), interp, unwind, cancelResult,
                                                            ref performanceClientData, ref result);

                                                        if (code == ReturnCode.Ok)
                                                            result = String.Empty;
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                code = ReturnCode.Error;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl cancel ?options? path ?result?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "canceled":
                                    {
                                        //
                                        // NOTE: We support the full TIP #285 semantics.  Please refer to
                                        //       "http://tip.tcl.tk/285" for more information.
                                        //
                                        if (arguments.Count == 3)
                                        {
                                            IntPtr interp = IntPtr.Zero;

                                            code = interpreter.GetTclInterpreter(
                                                arguments[2], LookupFlags.Default, ref interp, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                //
                                                // NOTE: This can (and should) legitimately return errors.
                                                //
                                                code = TclWrapper.Canceled(TclApi.GetTclApi(interpreter), interp, ref result);

                                                if (code == ReturnCode.Ok)
                                                    result = String.Empty;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl canceled interp\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "command":
                                    {
                                        //
                                        // NOTE: Sub-commands are "create", "delete", "exists", and "list".
                                        //
                                        if (arguments.Count >= 3)
                                        {
                                            switch (arguments[2])
                                            {
                                                case "create":
                                                    {
                                                        if (arguments.Count >= 6)
                                                        {
                                                            OptionDictionary options = new OptionDictionary(
                                                                new Option[] {
                                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-noforcedelete", null),
                                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-nocomplain", 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, false, ref argumentIndex, ref result);

                                                            if (code == ReturnCode.Ok)
                                                            {
                                                                if ((argumentIndex != Index.Invalid) &&
                                                                    ((argumentIndex + 3) == arguments.Count))
                                                                {
                                                                    bool forceDelete = true;

                                                                    if (options.IsPresent("-noforcedelete"))
                                                                        forceDelete = false;

                                                                    bool noComplain = false;

                                                                    if (options.IsPresent("-nocomplain"))
                                                                        noComplain = true;

                                                                    //
                                                                    // NOTE: Get the IExecute interface.  We do not actually care
                                                                    //       whether this is a procedure or command.
                                                                    //
                                                                    string executeName = arguments[argumentIndex];
                                                                    IExecute execute = null;

                                                                    code = interpreter.GetIExecuteViaResolvers(
                                                                        interpreter.GetResolveEngineFlags(true),
                                                                        executeName, null, LookupFlags.Default,
                                                                        ref execute, ref result);

                                                                    if (code == ReturnCode.Ok)
                                                                        code = interpreter.AddTclBridge(
                                                                            execute, arguments[argumentIndex + 1],
                                                                            arguments[argumentIndex + 2], null,
                                                                            forceDelete, noComplain, ref result);
                                                                }
                                                                else
                                                                {
                                                                    if ((argumentIndex != Index.Invalid) &&
                                                                        Option.LooksLikeOption(arguments[argumentIndex]))
                                                                    {
                                                                        result = OptionDictionary.BadOption(options, arguments[argumentIndex]);
                                                                    }
                                                                    else
                                                                    {
                                                                        result = "wrong # args: should be \"tcl command create ?options? srcCmd interp targetCmd\"";
                                                                    }

                                                                    code = ReturnCode.Error;
                                                                }
                                                            }
                                                        }
                                                        else
                                                        {
                                                            result = "wrong # args: should be \"tcl command create ?options? srcCmd interp targetCmd\"";
                                                            code = ReturnCode.Error;
                                                        }
                                                        break;
                                                    }
                                                case "delete":
                                                    {
                                                        //
                                                        // NOTE: Syntax is: "tcl command delete interp targetCmd".
                                                        //
                                                        if (arguments.Count == 5)
                                                        {
                                                            code = interpreter.RemoveTclBridge(arguments[3], arguments[4], null, ref result);
                                                        }
                                                        else
                                                        {
                                                            result = "wrong # args: should be \"tcl command delete interp targetCmd\"";
                                                            code = ReturnCode.Error;
                                                        }
                                                        break;
                                                    }
                                                case "exists":
                                                    {
                                                        if (arguments.Count == 5)
                                                        {
                                                            string bridgeName =
                                                                FormatOps.TclBridgeName(arguments[3], arguments[4]);

                                                            TclBridge tclBridge = null;

                                                            code = interpreter.GetTclBridge(
                                                                bridgeName, LookupFlags.NoVerbose, ref tclBridge);

                                                            if ((code == ReturnCode.Ok) && (tclBridge != null))
                                                                result = true;
                                                            else
                                                                result = false;

                                                            code = ReturnCode.Ok; // NOTE: Force result to Ok.
                                                        }
                                                        else
                                                        {
                                                            result = "wrong # args: should be \"tcl command exists interp targetCmd\"";
                                                            code = ReturnCode.Error;
                                                        }
                                                        break;
                                                    }
                                                case "list":
                                                    {
                                                        if ((arguments.Count == 3) || (arguments.Count == 4))
                                                        {
                                                            string pattern = null;

                                                            if (arguments.Count == 4)
                                                                pattern = arguments[3];

                                                            result = interpreter.TclBridgesToString(pattern, false);
                                                        }
                                                        else
                                                        {
                                                            result = "wrong # args: should be \"tcl command list ?pattern?\"";
                                                            code = ReturnCode.Error;
                                                        }
                                                        break;
                                                    }
                                                default:
                                                    {
                                                        result = ScriptOps.BadValue(
                                                            null, "option", arguments[2],
                                                            new string[] { "create", "delete", "exists", "list" }, null, null);

                                                        code = ReturnCode.Error;
                                                        break;
                                                    }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl command arg ?arg ...?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "complete":
                                    {
                                        if (arguments.Count == 3)
                                        {
                                            bool complete = false;

                                            code = TclWrapper.IsCommandComplete(
                                                TclApi.GetTclApi(interpreter), arguments[2], ref complete, ref result);

                                            if (code == ReturnCode.Ok)
                                                result = complete;
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl complete command\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "convert":
                                    {
                                        if (arguments.Count == 5)
                                        {
                                            IntPtr interp = IntPtr.Zero;

                                            code = interpreter.GetTclInterpreter(
                                                arguments[2], LookupFlags.Default, ref interp, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                code = TclWrapper.ConvertToType(
                                                    TclApi.GetTclApi(interpreter), interp, arguments[3], arguments[4], ref result);

                                                if (code == ReturnCode.Ok)
                                                    result = String.Empty;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl convert interp string type\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "create":
                                    {
                                        if (arguments.Count >= 2)
                                        {
                                            OptionDictionary options = new OptionDictionary(
                                                new Option[] {
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-alias", null),
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-noinitialize", null),
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-memory", null),
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-safe", null),
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-nobridge", null),
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-noforcedelete", null),
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-nocomplain", 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, true, ref argumentIndex, ref result);
                                            else
                                                code = ReturnCode.Ok;

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

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

                                                    bool initialize = true;

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

                                                    bool memory = false;

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

                                                    bool safe = false;

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

                                                    bool bridge = true;

                                                    if (options.IsPresent("-nobridge"))
                                                        bridge = false;

                                                    bool forceDelete = true;

                                                    if (options.IsPresent("-noforcedelete"))
                                                        forceDelete = false;

                                                    bool noComplain = false;

                                                    if (options.IsPresent("-nocomplain"))
                                                        noComplain = true;

                                                    if (!bridge || interpreter.HasTclBridges(ref result))
                                                    {
                                                        string interpName = null;

                                                        code = interpreter.CreateTclInterpreter(initialize, memory, safe, ref result);

                                                        if (code == ReturnCode.Ok)
                                                        {
                                                            //
                                                            // NOTE: Grab the Tcl interpreter name, we will need it below.
                                                            //
                                                            interpName = result;

                                                            //
                                                            // NOTE: Create an alias for the new Tcl interpreter handle?
                                                            //
                                                            if ((code == ReturnCode.Ok) && alias)
                                                                code = interpreter.AddTclAlias(interpName, ref result);

                                                            //
                                                            // NOTE: Add a bridged eval command to the Tcl interpreter?
                                                            //
                                                            if ((code == ReturnCode.Ok) && bridge)
                                                            {
                                                                code = interpreter.AddStandardTclBridge(
                                                                    interpName, null, null, forceDelete, noComplain,
                                                                    ref result);
                                                            }

                                                            //
                                                            // NOTE: If we succeeded, return interpreter name as the result.
                                                            //
                                                            if (code == ReturnCode.Ok)
                                                                result = interpName;
                                                        }

                                                        //
                                                        // NOTE: If we failed above, cleanup the Tcl interpreter now.
                                                        //
                                                        if ((code != ReturnCode.Ok) && (interpName != null))
                                                        {
                                                            Result deleteResult = null;

                                                            if (interpreter.DeleteTclInterpreter(
                                                                    interpName, ref deleteResult) != ReturnCode.Ok)
                                                            {
                                                                ResultList errors = new ResultList();

                                                                errors.Add(result);
                                                                errors.Add(deleteResult);

                                                                result = errors;
                                                            }
                                                        }
                                                    }
                                                    else
                                                    {
                                                        code = ReturnCode.Error;
                                                    }
                                                }
                                                else
                                                {
                                                    result = "wrong # args: should be \"tcl create ?options?\"";
                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl create ?options?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "delete":
                                    {
                                        if (arguments.Count == 3)
                                        {
                                            string interpName = arguments[2];

                                            if ((interpreter.DoesAliasExist(interpName) != ReturnCode.Ok) ||
                                                (interpreter.RemoveAliasAndCommand(interpName, clientData, false, ref result) == ReturnCode.Ok))
                                            {
                                                code = interpreter.DeleteTclInterpreter(interpName, ref result);
                                            }
                                            else
                                            {
                                                code = ReturnCode.Error;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl delete interp\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "errorline":
                                    {
                                        //
                                        // NOTE: We support the full TIP #336 semantics.  Please refer to
                                        //       "http://tip.tcl.tk/336" for more information.
                                        //
                                        if ((arguments.Count == 3) || (arguments.Count == 4))
                                        {
                                            IntPtr interp = IntPtr.Zero;

                                            code = interpreter.GetTclInterpreter(
                                                arguments[2], LookupFlags.Default, ref interp, ref result);

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

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

                                                    if (code == ReturnCode.Ok)
                                                        code = TclWrapper.SetErrorLine(TclApi.GetTclApi(interpreter), interp,
                                                            line, ref result);
                                                }

                                                if (code == ReturnCode.Ok)
                                                    result = TclWrapper.GetErrorLine(TclApi.GetTclApi(interpreter), interp);
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl errorline interp ?line?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "eval":
                                    {
                                        if (arguments.Count >= 4)
                                        {
                                            OptionDictionary options = new OptionDictionary(
                                                new Option[] {
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-time", null),
                                                new Option(null, OptionFlags.MustHaveBooleanValue, Index.Invalid, Index.Invalid, "-exceptions", 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))
                                                {
                                                    bool time = false;

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

                                                    Variant value = null;
                                                    bool exceptions = interpreter.TclExceptions;

                                                    if (options.IsPresent("-exceptions", ref value))
                                                        exceptions = (bool)value.Value;

                                                    IClientData performanceClientData = time ?
                                                        new PerformanceClientData(null,
                                                            "EvaluateTclScript", false) : null;

                                                    //
                                                    // NOTE: Perform a concat operation if more than one script
                                                    //       argument was specified.
                                                    //
                                                    if (((argumentIndex + 2) == arguments.Count))
                                                        code = interpreter.EvaluateTclScript(
                                                            arguments[argumentIndex], arguments[argumentIndex + 1],
                                                            Tcl_EvalFlags.TCL_EVAL_NONE, exceptions,
                                                            ref performanceClientData, ref result);
                                                    else
                                                        code = interpreter.EvaluateTclScript(
                                                            arguments[argumentIndex],
                                                            ListOps.Concat(arguments, argumentIndex + 1),
                                                            Tcl_EvalFlags.TCL_EVAL_NONE, exceptions,
                                                            ref performanceClientData, ref result);
                                                }
                                                else
                                                {
                                                    if ((argumentIndex != Index.Invalid) &&
                                                        Option.LooksLikeOption(arguments[argumentIndex]))
                                                    {
                                                        result = OptionDictionary.BadOption(
                                                            options, arguments[argumentIndex]);
                                                    }
                                                    else
                                                    {
                                                        result = "wrong # args: should be \"tcl eval ?options? interp arg ?arg ...?\"";
                                                    }

                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl eval ?options? interp arg ?arg ...?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "exceptions":
                                    {
                                        if ((arguments.Count == 2) || (arguments.Count == 3))
                                        {
                                            ITclApi tclApi = TclApi.GetTclApi(interpreter);

                                            if (tclApi != null)
                                            {
                                                if (arguments.Count == 3)
                                                {
                                                    bool exceptions = false;

                                                    code = Value.GetBoolean2(
                                                        arguments[2], ValueFlags.AnyBoolean,
                                                        interpreter.CultureInfo, ref exceptions,
                                                        ref result);

                                                    if (code == ReturnCode.Ok)
                                                        tclApi.Exceptions = exceptions;
                                                }

                                                if (code == ReturnCode.Ok)
                                                    result = tclApi.Exceptions;
                                            }
                                            else
                                            {
                                                result = "invalid Tcl API object";
                                                code = ReturnCode.Error;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl exceptions ?exceptions?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "exists":
                                    {
                                        if (arguments.Count == 3)
                                        {
                                            IntPtr interp = IntPtr.Zero;

                                            code = interpreter.GetTclInterpreter(
                                                arguments[2], LookupFlags.NoVerbose, ref interp);

                                            if ((code == ReturnCode.Ok) && (interp != IntPtr.Zero))
                                                result = true;
                                            else
                                                result = false;

                                            code = ReturnCode.Ok; // NOTE: Force result to Ok.
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl exists interp\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "expr":
                                    {
                                        if (arguments.Count >= 4)
                                        {
                                            OptionDictionary options = new OptionDictionary(
                                                new Option[] {
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-time", null),
                                                new Option(null, OptionFlags.MustHaveBooleanValue, Index.Invalid, Index.Invalid, "-exceptions", 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))
                                                {
                                                    bool time = false;

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

                                                    Variant value = null;
                                                    bool exceptions = interpreter.TclExceptions;

                                                    if (options.IsPresent("-exceptions", ref value))
                                                        exceptions = (bool)value.Value;

                                                    IClientData performanceClientData = time ?
                                                        new PerformanceClientData(null,
                                                            "EvaluateTclExpression", false) : null;

                                                    //
                                                    // NOTE: Perform a concat operation if more than one
                                                    //       argument was specified.
                                                    //
                                                    if (((argumentIndex + 2) == arguments.Count))
                                                        code = interpreter.EvaluateTclExpression(
                                                            arguments[argumentIndex],
                                                            arguments[argumentIndex + 1], exceptions,
                                                            ref performanceClientData, ref result);
                                                    else
                                                        code = interpreter.EvaluateTclExpression(
                                                            arguments[argumentIndex],
                                                            ListOps.Concat(arguments, argumentIndex + 1),
                                                            exceptions, ref performanceClientData,
                                                            ref result);
                                                }
                                                else
                                                {
                                                    if ((argumentIndex != Index.Invalid) &&
                                                        Option.LooksLikeOption(arguments[argumentIndex]))
                                                    {
                                                        result = OptionDictionary.BadOption(
                                                            options, arguments[argumentIndex]);
                                                    }
                                                    else
                                                    {
                                                        result = "wrong # args: should be \"tcl expr ?options? interp arg ?arg ...?\"";
                                                    }

                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl expr ?options? interp arg ?arg ...?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "find":
                                    {
                                        if (arguments.Count >= 2)
                                        {
                                            OptionDictionary options = new OptionDictionary(
                                                new Option[] {
                                                new Option(typeof(FindFlags), OptionFlags.MustHaveEnumValue, Index.Invalid, Index.Invalid, "-flags",
                                                    new Variant(FindFlags.Default)),
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-architecture", null),
                                                new Option(null, OptionFlags.MustHaveVersionValue, Index.Invalid, Index.Invalid, "-minimumversion", null),
                                                new Option(null, OptionFlags.MustHaveVersionValue, Index.Invalid, Index.Invalid, "-maximumversion", null),
                                                new Option(null, OptionFlags.MustHaveVersionValue, Index.Invalid, Index.Invalid, "-unknownversion", null),
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-verbose", null),
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-full", 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)
                                            {
                                                if ((argumentIndex == Index.Invalid) ||
                                                    ((argumentIndex + 2) >= arguments.Count))
                                                {
                                                    Variant value = null;
                                                    FindFlags flags = FindFlags.Default;

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

                                                    bool architecture = false;

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

                                                    if (options.IsPresent("-verbose"))
                                                        flags |= FindFlags.Verbose;

                                                    bool full = false;

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

                                                    Version minimumVersion = TclWrapper.GetDefaultMinimumVersion(flags);

                                                    if (options.IsPresent("-minimumversion", ref value))
                                                        minimumVersion = (Version)value.Value;

                                                    Version maximumVersion = TclWrapper.GetDefaultMaximumVersion(flags);

                                                    if (options.IsPresent("-maximumversion", ref value))
                                                        maximumVersion = (Version)value.Value;

                                                    Version unknownVersion = TclWrapper.GetDefaultUnknownVersion(flags);

                                                    if (options.IsPresent("-unknownversion", ref value))
                                                        unknownVersion = (Version)value.Value;

                                                    string path = null;

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

                                                        if (!String.IsNullOrEmpty(path))
                                                        {
                                                            path = PathOps.ResolveFullPath(interpreter, path);

                                                            if (path == null)
                                                            {
                                                                result = String.Format(
                                                                    "cannot resolve full path for \"{0}\"",
                                                                    arguments[argumentIndex]);

                                                                code = ReturnCode.Error;
                                                            }
                                                        }
                                                    }

                                                    if (code == ReturnCode.Ok)
                                                    {
                                                        TclBuildDictionary builds = null;
                                                        ResultList errors = null;

                                                        code = TclWrapper.Find(
                                                            flags, null, path, minimumVersion, maximumVersion,
                                                            unknownVersion, clientData, architecture, ref builds,
                                                            ref errors);

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

                                                            if ((argumentIndex != Index.Invalid) &&
                                                                ((argumentIndex + 1) < arguments.Count))
                                                            {
                                                                pattern = arguments[argumentIndex + 1];
                                                            }

                                                            if (full)
                                                            {
                                                                StringList list = new StringList();

                                                                foreach (TclBuild build in builds.Values)
                                                                    list.Add(build.ToString());

                                                                result = list;
                                                            }
                                                            else
                                                            {
                                                                //
                                                                // NOTE: *NOCASE* File names are not case-sensitive
                                                                //       on Windows.
                                                                //
                                                                result = builds.ToString(pattern, true);
                                                            }
                                                        }
                                                        else
                                                        {
                                                            result = ListOps.Concat(errors, 0, Environment.NewLine);
                                                        }
                                                    }
                                                }
                                                else
                                                {
                                                    if ((argumentIndex != Index.Invalid) &&
                                                        Option.LooksLikeOption(arguments[argumentIndex]))
                                                    {
                                                        result = OptionDictionary.BadOption(options, arguments[argumentIndex]);
                                                    }
                                                    else
                                                    {
                                                        result = "wrong # args: should be \"tcl find ?options? ?path? ?pattern?\"";
                                                    }

                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl find ?options? ?path? ?pattern?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "interps":
                                    {
                                        if ((arguments.Count == 2) || (arguments.Count == 3))
                                        {
                                            lock (interpreter.TclSyncRoot)
                                            {
                                                if (interpreter.HasTclInterpreters())
                                                {
                                                    string pattern = null;

                                                    if (arguments.Count == 3)
                                                        pattern = arguments[2];

                                                    IntPtrDictionary interps = null;

                                                    code = interpreter.GetTclInterpreters(
                                                        pattern, LookupFlags.Default, false, false,
                                                        ref interps, ref result);

                                                    if (code == ReturnCode.Ok)
                                                        result = interps.ToString();
                                                }
                                                else
                                                {
                                                    result = String.Empty;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl interps ?pattern?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "load":
                                    {
                                        if (arguments.Count >= 2)
                                        {
                                            if (interpreter.HasTclInterpreters(ref result))
                                            {
                                                OptionDictionary options = new OptionDictionary(
                                                    new Option[] {
                                                    new Option(typeof(FindFlags), OptionFlags.MustHaveEnumValue, Index.Invalid, Index.Invalid, "-flags",
                                                        new Variant(FindFlags.Default)),
                                                    new Option(null, OptionFlags.MustHaveVersionValue, Index.Invalid, Index.Invalid, "-minimumversion", null),
                                                    new Option(null, OptionFlags.MustHaveVersionValue, Index.Invalid, Index.Invalid, "-maximumversion", null),
                                                    new Option(null, OptionFlags.MustHaveVersionValue, Index.Invalid, Index.Invalid, "-unknownversion", 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, true, ref argumentIndex, ref result);
                                                else
                                                    code = ReturnCode.Ok;

                                                if (code == ReturnCode.Ok)
                                                {
                                                    if ((argumentIndex == Index.Invalid) ||
                                                        ((argumentIndex + 1) == arguments.Count))
                                                    {
                                                        Variant value = null;
                                                        FindFlags flags = FindFlags.Default;

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

                                                        Version minimumVersion = TclWrapper.GetDefaultMinimumVersion(flags);

                                                        if (options.IsPresent("-minimumversion", ref value))
                                                            minimumVersion = (Version)value.Value;

                                                        Version maximumVersion = TclWrapper.GetDefaultMaximumVersion(flags);

                                                        if (options.IsPresent("-maximumversion", ref value))
                                                            maximumVersion = (Version)value.Value;

                                                        Version unknownVersion = TclWrapper.GetDefaultUnknownVersion(flags);

                                                        if (options.IsPresent("-unknownversion", ref value))
                                                            unknownVersion = (Version)value.Value;

                                                        string path = null;

                                                        if (argumentIndex != Index.Invalid)
                                                        {
                                                            //
                                                            // NOTE: Ok, they want to look at a specific file or
                                                            //       directory [only].
                                                            //
                                                            path = arguments[argumentIndex];

                                                            if (!String.IsNullOrEmpty(path))
                                                            {
                                                                path = PathOps.ResolveFullPath(interpreter, path);

                                                                if (path != null)
                                                                {
                                                                    //
                                                                    // NOTE: Prohibit the loader from attempting to
                                                                    //       search anywhere else.
                                                                    //
                                                                    flags = FindFlags.SpecificPath;
                                                                }
                                                                else
                                                                {
                                                                    result = String.Format(
                                                                        "cannot resolve full path for \"{0}\"",
                                                                        arguments[argumentIndex]);

                                                                    code = ReturnCode.Error;
                                                                }
                                                            }
                                                        }

                                                        if (code == ReturnCode.Ok)
                                                        {
                                                            code = interpreter.LoadTcl(
                                                                flags, path, minimumVersion, maximumVersion,
                                                                unknownVersion, clientData, ref result);
                                                        }
                                                    }
                                                    else
                                                    {
                                                        if ((argumentIndex != Index.Invalid) &&
                                                            Option.LooksLikeOption(arguments[argumentIndex]))
                                                        {
                                                            result = OptionDictionary.BadOption(options, arguments[argumentIndex]);
                                                        }
                                                        else
                                                        {
                                                            result = "wrong # args: should be \"tcl load ?options? ?path?\"";
                                                        }

                                                        code = ReturnCode.Error;
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                code = ReturnCode.Error;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl load ?options? ?path?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "master":
                                    {
                                        if (arguments.Count == 2)
                                        {
                                            string name = null;
                                            IntPtr interp = IntPtr.Zero; /* NOT USED */

                                            code = interpreter.GetAnyTclMasterInterpreter(
                                                LookupFlags.Default, ref name, ref interp,
                                                ref result);

                                            if (code == ReturnCode.Ok)
                                                result = name;
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl master\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "module":
                                    {
                                        if (arguments.Count == 2)
                                        {
                                            if (TclApi.CheckModule(TclApi.GetTclApi(interpreter), ref result))
                                            {
                                                result = TclApi.GetTclApi(interpreter).FileName;
                                                code = ReturnCode.Ok;
                                            }
                                            else
                                            {
                                                code = ReturnCode.Error;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl module\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "preserve":
                                    {
                                        if (arguments.Count == 3)
                                        {
                                            IntPtr interp = IntPtr.Zero;

                                            code = interpreter.GetTclInterpreter(
                                                arguments[2], LookupFlags.Default, ref interp, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                code = TclWrapper.Preserve(TclApi.GetTclApi(interpreter), interp, ref result);

                                                if (code == ReturnCode.Ok)
                                                    result = String.Empty;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl preserve interp\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "queue":
                                    {
                                        if (arguments.Count >= 4)
                                        {
#if TCL_THREADS
                                            OptionDictionary options = new OptionDictionary(
                                                new Option[] {
                                                new Option(typeof(EventType), OptionFlags.MustHaveEnumValue, Index.Invalid, Index.Invalid, "-eventtype",
                                                    new Variant(EventType.Evaluate)),
                                                new Option(typeof(EventFlags), OptionFlags.MustHaveEnumValue, Index.Invalid, Index.Invalid, "-eventflags",
                                                    new Variant(EventFlags.None)),
                                                new Option(null, OptionFlags.MustHaveObjectValue, Index.Invalid, Index.Invalid, "-data", null),
                                                new Option(null, OptionFlags.MustHaveBooleanValue, Index.Invalid, Index.Invalid, "-exceptions", null),
                                                new Option(null, OptionFlags.MustHaveBooleanValue, Index.Invalid, Index.Invalid, "-synchronous", 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, true, ref argumentIndex, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                if ((argumentIndex != Index.Invalid) &&
                                                    ((argumentIndex + 1) < arguments.Count))
                                                {
                                                    Variant value = null;
                                                    EventType eventType = EventType.Evaluate;

                                                    if (options.IsPresent("-eventtype", ref value))
                                                        eventType = (EventType)value.Value;

                                                    EventFlags eventFlags = EventFlags.None;

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

                                                    bool exceptions = interpreter.TclExceptions;

                                                    if (options.IsPresent("-exceptions", ref value))
                                                        exceptions = (bool)value.Value;

                                                    bool synchronous = false;

                                                    if (options.IsPresent("-synchronous", ref value))
                                                        synchronous = (bool)value.Value;

                                                    object data;

                                                    if (((argumentIndex + 2) == arguments.Count))
                                                    {
                                                        data = new AnyTriplet<Tcl_EvalFlags, bool, string>(
                                                            Tcl_EvalFlags.TCL_EVAL_NONE, exceptions,
                                                            arguments[argumentIndex + 1]);
                                                    }
                                                    else
                                                    {
                                                        data = new AnyTriplet<Tcl_EvalFlags, bool, string>(
                                                            Tcl_EvalFlags.TCL_EVAL_NONE, exceptions,
                                                            ListOps.Concat(arguments, argumentIndex + 1));
                                                    }

                                                    if (options.IsPresent("-data", ref value))
                                                    {
                                                        IObject @object = (IObject)value.Value;

                                                        data = @object.Value;
                                                    }

                                                    code = interpreter.QueueTclThreadEvent(
                                                        arguments[argumentIndex], eventType,
                                                        eventFlags, data, synchronous,
                                                        ref result);
                                                }
                                                else
                                                {
                                                    if ((argumentIndex != Index.Invalid) &&
                                                        Option.LooksLikeOption(arguments[argumentIndex]))
                                                    {
                                                        result = OptionDictionary.BadOption(
                                                            options, arguments[argumentIndex]);
                                                    }
                                                    else
                                                    {
                                                        result = "wrong # args: should be \"tcl queue ?options? interp arg ?arg ...?\"";
                                                    }

                                                    code = ReturnCode.Error;
                                                }
                                            }
#else
                                            result = "not implemented";
                                            code = ReturnCode.Error;
#endif
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl queue ?options? interp arg ?arg ...?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "ready":
                                    {
                                        if ((arguments.Count == 2) || (arguments.Count == 3))
                                        {
                                            if (arguments.Count == 3)
                                            {
                                                //
                                                // NOTE: Perform a full check of the Tcl API object
                                                //       and the specified Tcl interpreter, including
                                                //       the thread affinity.
                                                //
                                                result = interpreter.IsTclInterpreterReady(arguments[2]);
                                            }
                                            else
                                            {
                                                //
                                                // NOTE: See if the Tcl API object is Ok (no Tcl
                                                //       interpreter name was supplied).
                                                //
                                                result = TclApi.CheckModule(TclApi.GetTclApi(interpreter));
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl ready ?interp?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "recordandeval":
                                    {
                                        if (arguments.Count >= 4)
                                        {
                                            OptionDictionary options = new OptionDictionary(
                                                new Option[] {
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-time", null),
                                                new Option(null, OptionFlags.MustHaveBooleanValue, Index.Invalid, Index.Invalid, "-exceptions", 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))
                                                {
                                                    bool time = false;

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

                                                    Variant value = null;
                                                    bool exceptions = interpreter.TclExceptions;

                                                    if (options.IsPresent("-exceptions", ref value))
                                                        exceptions = (bool)value.Value;

                                                    IClientData performanceClientData = time ?
                                                        new PerformanceClientData(null,
                                                            "RecordAndEvaluateTclScript", false) : null;

                                                    //
                                                    // NOTE: Perform a concat operation if more than one script
                                                    //       argument was specified.
                                                    //
                                                    if (((argumentIndex + 2) == arguments.Count))
                                                        code = interpreter.RecordAndEvaluateTclScript(
                                                            arguments[argumentIndex], arguments[argumentIndex + 1],
                                                            Tcl_EvalFlags.TCL_EVAL_NONE, exceptions,
                                                            ref performanceClientData, ref result);
                                                    else
                                                        code = interpreter.RecordAndEvaluateTclScript(
                                                            arguments[argumentIndex],
                                                            ListOps.Concat(arguments, argumentIndex + 1),
                                                            Tcl_EvalFlags.TCL_EVAL_NONE, exceptions,
                                                            ref performanceClientData, ref result);
                                                }
                                                else
                                                {
                                                    if ((argumentIndex != Index.Invalid) &&
                                                        Option.LooksLikeOption(arguments[argumentIndex]))
                                                    {
                                                        result = OptionDictionary.BadOption(
                                                            options, arguments[argumentIndex]);
                                                    }
                                                    else
                                                    {
                                                        result = "wrong # args: should be \"tcl recordandeval ?options? interp arg ?arg ...?\"";
                                                    }

                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl recordandeval ?options? interp arg ?arg ...?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "release":
                                    {
                                        if (arguments.Count == 3)
                                        {
                                            IntPtr interp = IntPtr.Zero;

                                            code = interpreter.GetTclInterpreter(
                                                arguments[2], LookupFlags.Default, ref interp, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                code = TclWrapper.Release(TclApi.GetTclApi(interpreter), interp, ref result);

                                                if (code == ReturnCode.Ok)
                                                    result = String.Empty;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl release interp\"";
                                            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, "-slaves", null),
                                                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;

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

                                            if (code == ReturnCode.Ok)
                                            {
                                                if ((argumentIndex != Index.Invalid) &&
                                                    ((argumentIndex + 1) == arguments.Count))
                                                {
                                                    bool slaves = false;

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

                                                    bool force = false;

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

                                                    IntPtr interp = IntPtr.Zero;

                                                    code = interpreter.GetTclInterpreter(
                                                        arguments[argumentIndex], LookupFlags.Default, ref interp, ref result);

                                                    if (code == ReturnCode.Ok)
                                                        code = TclWrapper.ResetCancellation(TclApi.GetTclApi(interpreter), interp, force, ref result);

                                                    if ((code == ReturnCode.Ok) && slaves)
                                                        code = TclWrapper.SetSlaveCancelFlags(TclApi.GetTclApi(interpreter), interp,
                                                            Tcl_EvalFlags.TCL_EVAL_NONE, force, ref result);

                                                    if (code == ReturnCode.Ok)
                                                        result = String.Empty;
                                                }
                                                else
                                                {
                                                    if ((argumentIndex != Index.Invalid) &&
                                                        Option.LooksLikeOption(arguments[argumentIndex]))
                                                    {
                                                        result = OptionDictionary.BadOption(
                                                            options, arguments[argumentIndex]);
                                                    }
                                                    else
                                                    {
                                                        result = "wrong # args: should be \"tcl resetcancel ?options? interp\"";
                                                    }

                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl resetcancel ?options? interp\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "select":
                                    {
                                        if (arguments.Count >= 2)
                                        {
                                            OptionDictionary options = new OptionDictionary(
                                                new Option[] {
                                                new Option(typeof(FindFlags), OptionFlags.MustHaveEnumValue, Index.Invalid, Index.Invalid, "-flags",
                                                    new Variant(FindFlags.Default)),
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-architecture", null),
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-verbose", null),
                                                new Option(null, OptionFlags.MustHaveVersionValue, Index.Invalid, Index.Invalid, "-minimumversion", null),
                                                new Option(null, OptionFlags.MustHaveVersionValue, Index.Invalid, Index.Invalid, "-maximumversion", null),
                                                new Option(null, OptionFlags.MustHaveVersionValue, Index.Invalid, Index.Invalid, "-unknownversion", 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, true, ref argumentIndex, ref result);
                                            else
                                                code = ReturnCode.Ok;

                                            if (code == ReturnCode.Ok)
                                            {
                                                if ((argumentIndex == Index.Invalid) ||
                                                    ((argumentIndex + 1) == arguments.Count))
                                                {
                                                    Variant value = null;
                                                    FindFlags flags = FindFlags.Default;

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

                                                    bool architecture = false;

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

                                                    if (options.IsPresent("-verbose"))
                                                        flags |= FindFlags.Verbose;

                                                    Version minimumVersion = TclWrapper.GetDefaultMinimumVersion(flags);

                                                    if (options.IsPresent("-minimumversion", ref value))
                                                        minimumVersion = (Version)value.Value;

                                                    Version maximumVersion = TclWrapper.GetDefaultMaximumVersion(flags);

                                                    if (options.IsPresent("-maximumversion", ref value))
                                                        maximumVersion = (Version)value.Value;

                                                    Version unknownVersion = TclWrapper.GetDefaultUnknownVersion(flags);

                                                    if (options.IsPresent("-unknownversion", ref value))
                                                        unknownVersion = (Version)value.Value;

                                                    string path = null;

                                                    if (argumentIndex != Index.Invalid)
                                                    {
                                                        //
                                                        // NOTE: Ok, they want to look at a specific file or
                                                        //       directory [only].
                                                        //
                                                        path = arguments[argumentIndex];

                                                        if (!String.IsNullOrEmpty(path))
                                                        {
                                                            path = PathOps.ResolveFullPath(interpreter, path);

                                                            if (path != null)
                                                            {
                                                                //
                                                                // NOTE: Allow the Tcl detection logic to use
                                                                //       the specific file or directory.
                                                                //
                                                                flags |= FindFlags.SpecificPath;
                                                            }
                                                            else
                                                            {
                                                                result = String.Format(
                                                                    "cannot resolve full path for \"{0}\"",
                                                                    arguments[argumentIndex]);

                                                                code = ReturnCode.Error;
                                                            }
                                                        }
                                                    }

                                                    if (code == ReturnCode.Ok)
                                                    {
                                                        TclBuildDictionary builds = null;
                                                        ResultList errors = null;

                                                        code = TclWrapper.Find(
                                                            flags, null, path, minimumVersion, maximumVersion,
                                                            unknownVersion, clientData, architecture, ref builds,
                                                            ref errors);

                                                        if (code == ReturnCode.Ok)
                                                        {
                                                            TclBuild build = null;

                                                            code = TclWrapper.Select(builds, minimumVersion, maximumVersion,
                                                                architecture, ref build, ref errors);

                                                            if (code == ReturnCode.Ok)
                                                                result = build.ToString();
                                                            else
                                                                result = ListOps.Concat(errors, 0, Environment.NewLine);
                                                        }
                                                        else
                                                        {
                                                            result = ListOps.Concat(errors, 0, Environment.NewLine);
                                                        }
                                                    }
                                                }
                                                else
                                                {
                                                    if ((argumentIndex != Index.Invalid) &&
                                                        Option.LooksLikeOption(arguments[argumentIndex]))
                                                    {
                                                        result = OptionDictionary.BadOption(options, arguments[argumentIndex]);
                                                    }
                                                    else
                                                    {
                                                        result = "wrong # args: should be \"tcl select ?options? ?path?\"";
                                                    }

                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl select ?options? ?path?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "set":
                                    {
                                        if ((arguments.Count == 4) || (arguments.Count == 5))
                                        {
                                            IntPtr interp = IntPtr.Zero;

                                            code = interpreter.GetTclInterpreter(
                                                arguments[2], LookupFlags.Default, ref interp, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                if (arguments.Count == 4)
                                                {
                                                    code = TclWrapper.GetVariable(TclApi.GetTclApi(interpreter), interp,
                                                        Tcl_VarFlags.TCL_LEAVE_ERR_MSG, arguments[3], ref result, ref result);
                                                }
                                                else if (arguments.Count == 5)
                                                {
                                                    Result value = arguments[4];

                                                    code = TclWrapper.SetVariable(TclApi.GetTclApi(interpreter), interp,
                                                        Tcl_VarFlags.TCL_LEAVE_ERR_MSG, arguments[3], ref value, ref result);

                                                    if (code == ReturnCode.Ok)
                                                        result = value;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl set interp varName ?newValue?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "source":
                                    {
                                        if (arguments.Count >= 4)
                                        {
                                            OptionDictionary options = new OptionDictionary(
                                                new Option[] {
                                                new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-time", null),
                                                new Option(null, OptionFlags.MustHaveBooleanValue, Index.Invalid, Index.Invalid, "-exceptions", 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))
                                                {
                                                    bool time = false;

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

                                                    Variant value = null;
                                                    bool exceptions = interpreter.TclExceptions;

                                                    if (options.IsPresent("-exceptions", ref value))
                                                        exceptions = (bool)value.Value;

                                                    IClientData performanceClientData = time ?
                                                        new PerformanceClientData(null,
                                                            "EvaluateTclFile", false) : null;

                                                    code = interpreter.EvaluateTclFile(
                                                        arguments[argumentIndex], arguments[argumentIndex + 1],
                                                        exceptions, ref performanceClientData, ref result);
                                                }
                                                else
                                                {
                                                    if ((argumentIndex != Index.Invalid) &&
                                                        Option.LooksLikeOption(arguments[argumentIndex]))
                                                    {
                                                        result = OptionDictionary.BadOption(options, arguments[argumentIndex]);
                                                    }
                                                    else
                                                    {
                                                        result = "wrong # args: should be \"tcl source ?options? interp fileName\"";
                                                    }

                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl source ?options? interp fileName\"";
                                            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, "-time", null),
                                                new Option(null, OptionFlags.MustHaveBooleanValue, Index.Invalid, Index.Invalid, "-exceptions", 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))
                                                {
                                                    Tcl_SubstFlags flags = Tcl_SubstFlags.TCL_SUBST_ALL;

                                                    if (options.IsPresent("-nobackslashes"))
                                                        flags &= ~Tcl_SubstFlags.TCL_SUBST_BACKSLASHES;

                                                    if (options.IsPresent("-nocommands"))
                                                        flags &= ~Tcl_SubstFlags.TCL_SUBST_COMMANDS;

                                                    if (options.IsPresent("-novariables"))
                                                        flags &= ~Tcl_SubstFlags.TCL_SUBST_VARIABLES;

                                                    bool time = false;

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

                                                    Variant value = null;
                                                    bool exceptions = interpreter.TclExceptions;

                                                    if (options.IsPresent("-exceptions", ref value))
                                                        exceptions = (bool)value.Value;

                                                    IClientData performanceClientData = time ?
                                                        new PerformanceClientData(null,
                                                            "SubstituteTclString", false) : null;

                                                    code = interpreter.SubstituteTclString(
                                                        arguments[argumentIndex], arguments[argumentIndex + 1],
                                                        flags, exceptions, ref performanceClientData, ref result);
                                                }
                                                else
                                                {
                                                    if ((argumentIndex != Index.Invalid) &&
                                                        Option.LooksLikeOption(arguments[argumentIndex]))
                                                    {
                                                        result = OptionDictionary.BadOption(options, arguments[argumentIndex]);
                                                    }
                                                    else
                                                    {
                                                        result = "wrong # args: should be \"tcl subst ?options? interp string\"";
                                                    }

                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl subst ?options? interp string\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "threads":
                                    {
                                        if ((arguments.Count == 2) || (arguments.Count == 3))
                                        {
#if TCL_THREADS
                                            string pattern = null;

                                            if (arguments.Count == 3)
                                                pattern = arguments[2];

                                            result = interpreter.TclThreadsToString(pattern, false);
#else
                                            result = "not implemented";
                                            code = ReturnCode.Error;
#endif
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl threads ?pattern?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "types":
                                    {
                                        if (arguments.Count == 3)
                                        {
                                            IntPtr interp = IntPtr.Zero;

                                            code = interpreter.GetTclInterpreter(
                                                arguments[2], LookupFlags.Default, ref interp, ref result);

                                            if (code == ReturnCode.Ok)
                                                code = TclWrapper.GetAllObjectTypes(TclApi.GetTclApi(interpreter), interp, ref result);
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl types interp\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "unload":
                                    {
                                        if (arguments.Count == 2)
                                        {
                                            code = interpreter.UnloadTcl(UnloadFlags.Default, ref result);

                                            if (code == ReturnCode.Ok)
                                                result = String.Empty;
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl unload\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "unset":
                                    {
                                        if (arguments.Count == 4)
                                        {
                                            IntPtr interp = IntPtr.Zero;

                                            code = interpreter.GetTclInterpreter(
                                                arguments[2], LookupFlags.Default, ref interp, ref result);

                                            if (code == ReturnCode.Ok)
                                            {
                                                code = TclWrapper.UnsetVariable(TclApi.GetTclApi(interpreter), interp,
                                                    Tcl_VarFlags.TCL_LEAVE_ERR_MSG, arguments[3], ref result);

                                                if (code == ReturnCode.Ok)
                                                    result = String.Empty;
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl unset interp varName\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                case "update":
                                    {
                                        OptionDictionary options = new OptionDictionary(
                                            new Option[] {
                                            new Option(null, OptionFlags.MustHaveIntegerValue, Index.Invalid, Index.Invalid, "-timeout", null),
                                            new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-wait", null),
                                            new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-all", null),
                                            new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-nocomplain", 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, true, ref argumentIndex, ref result);
                                        else
                                            code = ReturnCode.Ok;

                                        if (code == ReturnCode.Ok)
                                        {
                                            if (argumentIndex == Index.Invalid)
                                            {
                                                Variant value = null;
                                                int timeout = _Timeout.Infinite;

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

                                                bool wait = false;

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

                                                bool all = false;

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

                                                bool noComplain = false;

                                                if (options.IsPresent("-nocomplain"))
                                                    noComplain = true;

                                                int count = 0;
                                                ITclApi tclApi = TclApi.GetTclApi(interpreter);

                                                code = TclWrapper.DoOneEvent(
                                                    interpreter, timeout, wait, all,
                                                    noComplain, ref count, ref tclApi,
                                                    ref result);

                                                TclApi.SetTclApi(interpreter, tclApi);

                                                if (code == ReturnCode.Ok)
                                                    result = count;
                                            }
                                            else
                                            {
                                                result = "wrong # args: should be \"tcl update ?options?\"";
                                                code = ReturnCode.Error;
                                            }
                                        }
                                        break;
                                    }
                                case "versionrange":
                                    {
                                        if (arguments.Count >= 2)
                                        {
                                            OptionDictionary options = new OptionDictionary(
                                                new Option[] {
                                                new Option(typeof(FindFlags), OptionFlags.MustHaveEnumValue, Index.Invalid, Index.Invalid, "-flags",
                                                    new Variant(FindFlags.Default)),
                                                new Option(null, OptionFlags.MustHaveVersionValue, Index.Invalid, Index.Invalid, "-minimumversion", null),
                                                new Option(null, OptionFlags.MustHaveVersionValue, Index.Invalid, Index.Invalid, "-maximumversion", null),
                                                new Option(null, OptionFlags.MustHaveIntegerValue, Index.Invalid, Index.Invalid, "-intermediateminimum", null),
                                                new Option(null, OptionFlags.MustHaveIntegerValue, Index.Invalid, Index.Invalid, "-intermediatemaximum", 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, true, ref argumentIndex, ref result);
                                            else
                                                code = ReturnCode.Ok;

                                            if (code == ReturnCode.Ok)
                                            {
                                                if (argumentIndex == Index.Invalid)
                                                {
                                                    Variant value = null;
                                                    FindFlags flags = FindFlags.Default;

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

                                                    Version minimumVersion = TclWrapper.GetDefaultMinimumVersion(flags);

                                                    if (options.IsPresent("-minimumversion", ref value))
                                                        minimumVersion = (Version)value.Value;

                                                    Version maximumVersion = TclWrapper.GetDefaultMaximumVersion(flags);

                                                    if (options.IsPresent("-maximumversion", ref value))
                                                        maximumVersion = (Version)value.Value;

                                                    int? intermediateMinimum = TclWrapper.GetDefaultIntermediateMinimum(flags);

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

                                                    int? intermediateMaximum = TclWrapper.GetDefaultIntermediateMaximum(flags);

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

                                                    code = TclWrapper.GetVersionRange(
                                                        flags, minimumVersion, maximumVersion, intermediateMinimum,
                                                        intermediateMaximum, ref result);
                                                }
                                                else
                                                {
                                                    result = "wrong # args: should be \"tcl versionrange ?options?\"";
                                                    code = ReturnCode.Error;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            result = "wrong # args: should be \"tcl versionrange ?options?\"";
                                            code = ReturnCode.Error;
                                        }
                                        break;
                                    }
                                default:
                                    {
                                        result = ScriptOps.BadSubCommand(null, null, subCommand, this, null, null);
                                        code = ReturnCode.Error;
                                        break;
                                    }
                            }
                        }
                    }
                    else
                    {
                        result = "wrong # args: should be \"tcl arg ?arg ...?\"";
                        code = ReturnCode.Error;
                    }
                }
                else
                {
                    result = "invalid argument list";
                    code = ReturnCode.Error;
                }
            }
            else
            {
                result = "invalid interpreter";
                code = ReturnCode.Error;
            }

            return code;
        }
        #endregion
    }
}
