/* Copyright (c) 2000-2006 ActiveState Software Inc.
   See the file LICENSE.txt for licensing information. */

#include "nsISupports.idl"
#include "nsITreeView.idl"
#include "domstubs.idl"

interface ISciMoz;
interface koILanguage;
interface koIAsyncCallback;

#include "koIFile.idl"
#include "koIPrefs.idl"

//XXX build system can't handle recursive dependancies :-(
//    so may need to add some addition includes.


// This represents a question for data to make of the user and, after asked,
// the user's answer. (Used by koIInterpolationService.)
[scriptable, uuid(6CBEF397-0919-45db-85C7-6D74624C689E)]
interface koIInterpolationQuery : nsISupports {
    // The "id" allows .Interpolate2() to know _where_ to interpolate
    // the user's answer into raw strings.
    //
    // If the code was "%(s:ask:Search for)" then:
    //    "id" might be "%(__ask1__)
    //    "code" would be "s"
    //    "question" would be "Search for"
    //    "mruName" is the name identifying the preference with which
    //        an MRU of answers for this question will be stored. This is
    //        generally very similar to "question". If the mruName is
    //        empty or null, then no MRU is maintaned.
    //    "answer" would start out either being null, if there had been no
    //        selection, or the value of the selection, if there had been one.
    //        After asking the user it would be whatever the user entered.
    //    "isPassword" is a boolean indicating if this is a query for a
    //        password.
    attribute wstring id;
    attribute wstring code;
    attribute wstring question;
    attribute string mruName;
    attribute wstring answer;
    attribute boolean isPassword;
};


[scriptable, function, uuid(0e8f9db6-fb16-4e07-8334-41ce74e01730)]
interface koIInterpolationCallback : nsISupports {
    AString interpolationCallback(in AString code, in AString filepath,
                                  in long lineNum, in AString word,
                                  in AString selection, in AString projectFile,
                                  in koIPreferenceSet prefSet);
};


// A generic interpolate service to enable parts of Komodo to
// interpolate the shortcut codes that were born as part of the Run
// Command system, e.g. %F for the full path to the current file, etc.
//
// See interpolate.js for a utility method for calling this service
// properly from JavaScript.
//
// (This was generalized so it can be used for the snippets system too.)
[scriptable, uuid(F86357E5-0F9D-4416-B196-60D423DBE1BF)]
interface koIInterpolationService : nsISupports {
    // Interpolate codes into the given strings.
    // 
    // This is a two step process. First, it must be determined if the
    // Komodo must prompt the user for data (as per the %(X:ask) codes).
    // Then, with the answers from the user the final interpolated strings
    // can be made.
    //
    //  "strings" is the list of raw strings to interpolate without brackets
    //  "bracketedStrings" is the list of raw strings to interpolate with brackets
    //      Bracketting is done with double-square-brackets:
    //          [[...code...]]
    //  "filename" is the filename of the current file (null, if N/A)
    //  "lineNum" is the current line number (0, if N/A)
    //  "word" is the current word under cursor (null if none)
    //  "selection" is the current selection (null if none)
    //
    //  "i1strings" is the list of strings after the first interpolation
    //      step.
    //  "i2strings" is the list of strings after the second
    //      interpolation step.
    //
    // If an error is encountered an exception will be raised and an
    // error with errno=NS_ERROR_INVALID_ARG will be set on
    // koILastErrorService.
    //
    // An interpolation example:
    // 1. A run command can interpolate the command and cwd strings:
    //
    //     strings:   findstr /s /n /c:"%(w:orask:Search Term)" %(ask:File Pattern:*.*)
    //                %(ask:Search in:%D)
    //
    // 2. First interpolation pass will interpolate non-asking codes and
    //    will generate koIInterpolationQuery objects for asking codes. Presume
    //    for this example that the user has C:\tmp\hello.py open with
    //    the string "Spam and Eggs" selected. After Interpolate1() you
    //    will get the following. The "%(__queryN__)" things are markers
    //    for later interpolation:
    //
    //     i1strings: findstr /s /n /c:"%(__query0__)" %(__query1__)
    //                findstr /s /n /c:"%(__query0__)" %(__query1__)
    //                %(__query2__)
    //                %(__query2__)
    //     queries:   [{'id': '%(__query0__)', 'code': 'w',
    //                  'question': 'Search Term', answer: 'Spam and Eggs',
    //                  'isPassword': False},
    //                 {'id': '%(__query1__)', 'code': 'ask',
    //                  'question': 'File Pattern', answer: '*.*',
    //                  'isPassword': False},
    //                 {'id': '%(__query2__)', 'code': 'ask', 
    //                  'question': 'Search in', answer: 'C:\\tmp',
    //                  'isPassword': False}]
    //    (See NOTE on why strings are doubled below.)
    //
    //    Note that if there are no "asking" codes (i.e. the "queries"
    //    list is empty) then Interpolate2() need not be called (i.e.
    //    skip steps 3 and 4).
    //
    // 3. The user of this service (see interpolate.js) will
    //    then put up a dialog presenting these queries to the user. For
    //    this example, let say the user changes the "File Pattern" to
    //    "*.py" and leaves the other two alone.
    //
    // 4. Interpolate2() is called with the modified queries and the marked
    //    up i1command and i1cwd. The result is the final fully interpreted
    //    strings:
    //
    //     i2strings: findstr /s /n /c:"Spam and Eggs" *.py
    //                findstr /s /n /c:"Spam and Eggs" *.py
    //                C:\tmp
    //                C:\tmp
    //    (See NOTE on why strings are doubled below.)
    //
    // 5. The user of this service can then use those strings to run the
    //    command.
    //
    // NOTE:
    //  The number of strings returned by Interpolate*() is doubled: the
    //  first is for *use* and the second for *display*.  The two will
    //  never be different after Interpolate1() but may be after
    //  Interpolate2() if one or more queries include asking for a
    //  password (via the 'askpass' code) which should be obscured for
    //  display in the UI. 
    //
    //  An example using askpass might be:
    //
    //     strings:   scp "%F" %(ask:username)@(%askpass:password):/tmp
    //
    //     i1strings: scp "/home/trentm/foo.py" %(__query0__)@%(__query1__):/tmp
    //     queries:   [{'id': '%(__query0__)', 'code': 'ask',
    //                  'question': 'username', answer: '',
    //                  'isPassword': False},
    //                 {'id': '%(__query1__)', 'code': 'askpass', 
    //                  'question': 'password', answer: '',
    //                  'isPassword': True}]
    //
    //     i2strings: scp "/home/trentm/foo.py" trentm@sekrit:/tmp
    //                scp "/home/trentm/foo.py" trentm@******:/tmp
    //
    void Interpolate1(in unsigned long scount,
                      [array, size_is(scount)] in wstring strings,
                      in unsigned long bcount,
                      [array, size_is(bcount)] in wstring bracketedStrings,
                      in wstring fileName, in long lineNum,
                      in wstring word, in wstring selection,
                      in wstring projectFile,
                      in koIPreferenceSet prefSet,
                      in wstring lineText,
                      out unsigned long qcount,
                      [array, size_is(qcount)] out koIInterpolationQuery queries,
                      out unsigned long i1count,
                      [array, size_is(i1count)] out wstring i1strings);

    void Interpolate2(in unsigned long i1count,
                      [array, size_is(i1count)] in wstring i1strings,
                      in unsigned long qcount,
                      [array, size_is(qcount)] in koIInterpolationQuery queries,
                      out unsigned long i2count,
                      [array, size_is(i2count)] out wstring i2strings);

    // Return a list of offsets into the given strings demarking the
    // interpolation code blocks in that string. There will alway be an
    // even number of offsets: <start1>, <end1>, <start2>, <end2>, ...
    void GetBlockOffsets(in wstring s, in boolean bracketed,
                         out unsigned long count,
                         [array, size_is(count)] out long offsets);

    void addCode(in AString code, in koIInterpolationCallback callback);
    void removeCode(in AString code);
};

[scriptable, uuid(03276c9a-6140-40ea-9906-a0f77a4d8227)]
interface koITerminalInterrupt : nsISupports{
    // returns true if the interrupt eats the data.  If false, the terminal handler
    // will pass the data on to the regular handler.
    boolean write([array, size_is(count)] in octet text, in unsigned long count);
    boolean puts(in AString text); // get around xpconnect limitations
};

[scriptable, uuid(AA8F8983-8B2B-4B27-80CB-BB04ECF6B915)]
interface koITerminalHandler : nsISupports{
    // The scintilla to use must be called once after creation.
    void setScintilla(in ISciMoz scintilla);
    void setLanguage(in koILanguage languageObj);
    readonly attribute boolean active;
    // You must call "startSession()" to make the output window "active"
    // When the session is complete, call "endSession()" to cleanup.
    void startSession();
    // - Std handlers to be passed to child processes. They will proxy
    //   reading and writing between the child and the terminal window.
    readonly attribute koIFile stdin;
    readonly attribute koIFile stdout;
    readonly attribute koIFile stderr;
    // Sets up the hooks for proxying the real io from the child process to
    // and from the terminal.
    void hookIO(in koIFile stdin, in koIFile stdout, in koIFile stderr,
                in wstring name);
    // Sets up fake io handles that can be used to send/receive data to/from
    // external sources like the remote debugger without having to come from
    // the real io handles.
    void setupDebuggerRedirectIOHandles();

    // if this is set, stdin from the terminal will be written here instead
    // once it is unset, it will return to the regular stdin handler.  if the
    // write method returns false, then the terminal will still pass the data
    // to the regular stin file above.
    attribute koITerminalInterrupt stdinHandler;
    
    void endSession();

    // Clear the contents of the terminal window. (Note that
    // "startSession()" calls this internally as well.)
    void clear();

    // avoid interleaving ui access by locking and releasing the terminal handler
    void acquireLock();
    void releaseLock();
    
    // used to tell the terminal handler where to continue with stdout/err
    attribute long lastWritePosition;

    // koITerminalHandler calls itself via proxy to run the following function
    // in the UI thread.  This function should not be called otherwise, but it
    // is necessary to have this interface so Mozilla's proxy will work
    void proxyAddText(in long length, in AString data, in wstring io_name);

    // When the above proxyAddText is called - this callback handler will then
    // be called afterwards to notify that the scintilla text was added. This
    // callbackHandler will *always* be called on the main UI thread.
    void setAddTextCallback(in koIAsyncCallback callbackHandler);
};

// One of these is used to interface between the command output window
// and the process being run in that Windows.
[scriptable, uuid(786D1791-042F-4CDC-9E46-CDB305010FDC)]
interface koITreeOutputHandler : koITerminalHandler {
    // Set the current working directory (for this session) to use to
    // give any parsed filenames context. Null implies the current
    // directory.
    void setCwd(in wstring cwd);
    // Set the current filename, if any (for this session). (If
    // filenames are not parsed from command output, then the filename
    // defaults to the current file.)
    void setCurrentFile(in wstring filename);

    // Data query methods for tree UI handling.
    wstring getFile(in unsigned long index);
    wstring getLine(in unsigned long index);   // e.g., "3" or "5-11"
    wstring getColumn(in unsigned long index); // e.g., "3" or "5-11"

    // Parse the given line.
    void parseLine(in AString line, out wstring file, out string lineNum,
                   out string columnNum);
    // Sort the tree data by a certain key (this key typically matches
    // the <treecol id=.../>  id's).
    void sort(in string sortBy);
    
    // Set the regex to use for parsing command output lines for this
    // session. If the regular expression is invalid, this will raise an
    // exception and set the error on the last error service.
    void setParseRegex(in wstring parseRegex);
};

// This is implemented in run's JavaScript code.
[scriptable, uuid(CE58C7CF-DE1F-4f24-87C2-6069B6F856BF)]
interface koIRunTerminationListener: nsISupports {
    void onTerminate(in long result);
};


/**
 * This is a "run command" specific wrapper around process.ProcessOpen
 * to enable passing back a handle to a process to be able to .kill()
 * and .wait() for it.
 */
[scriptable, uuid(30851CB2-3BAE-4243-9AC2-B8AA7783AD8F)]
interface koIRunProcess: nsISupports {

    // Terminate the process.
    //   "exitCode" is what the process return value is set to.
    void kill(in long exitCode);
    
    // Wait for the process to terminate and return its exit value.
    //   "timeout" is a number of seconds to wait for the process to
    //             terminate. A value of -1 means to never timeout.
    // Wait will raise an exception if the method times out before the
    // process has finished executing.
    long wait(in long timeout);

    /**
     * @deprecated since Komodo 4.3.0, use getStdout instead.
     */
    AString readStdout();
    /**
     * @deprecated since Komodo 4.3.0, use getStderr instead.
     */
    AString readStderr();

    /**
     * The data for these calls is only available after the process has
     * finished.
     * @since Komodo 4.3.0
     */
    AString getStdout();
    AString getStderr();
    
    readonly attribute wstring uuid;
};

[function, scriptable, uuid(b12cafa0-1d80-40d2-aace-8769bae616f6)]
interface koIRunAsyncCallback: nsISupports {
        /**
         * Callback handler for the RunAsync command - called when the process
         * finishes.
         *
         * @param command - The original command that was run.
         * @param returncode - The exitcode of the finished process.
         * @param stdout - The stdout output from the process.
         * @param stderr - The stderr output from the process.
         */
    void callback(in wstring command, in long returncode,
                  in AString stdout, in AString stderr);
};

[scriptable, uuid(6D22AC55-BD4F-455e-9A80-A820FD8190EE)]
interface koIRunService : nsISupports {
    // Encode/decode a command (and all options) into a string for use
    // in an "Recent Commands" MRU list.
    wstring Encode(in wstring command, in wstring cwd, in wstring env,
                   in boolean insertOutput, in boolean operateOnSelection,
                   in boolean doNotOpenOutputWindow, in string runIn,
                   in boolean parseOutput, in wstring parseRegex,
                   in boolean showParsedOutputList);
    void Decode(in wstring encoded, out wstring command,
                out wstring cwd, out wstring env,
                out boolean insertOutput, out boolean operateOnSelection,
                out boolean doNotOpenOutputWindow, out string runIn,
                out boolean parseOutput, out wstring parseRegex,
                out boolean showParsedOutputList);

        /**
         * Run the given command in the given terminal. A terminal is like the
         * Komodo Command Output window or Komodo's debugging terminals, it is
         * *not* like an xterm or windows command prompt.
         *
         * @param command {string}  The command string to run.
         * @param cwd {string}  The dir in which to run the command ('' or null
         *                      to inherit from parent).
         * @param env {string}  A string representing environment changes to
         *                      make for the child process, these are to be
         *                      merged in with the parent environment. The
         *                      format is: VAR1=value1\nVAR2=value2\n...
         * @param terminal {Components.interfaces.koITreeOutputHandler}  The
         *                 Komodo terminal widget handling the io.
         * @param termListener {Components.interfaces.koIRunTerminationListener}
         *                 Process terminalination listener.
         * @param input {string}  If supplied, then the command is run via
         *                        "command < input", where the input is placed
         *                        in a temporary file and redirected to stdin.
         * @returns {Components.interfaces.koIRunProcess}  The process handle.
         */
    koIRunProcess RunInTerminal(in wstring command, in wstring cwd, in
                                wstring env, in koITreeOutputHandler terminal,
                                in koIRunTerminationListener termListener,
                                in AString input);

        /**
         * Run will start the process running and then return. Run has the
         * ability to run the command in a new (console) window, such as an
         * xterm or windows command prompt. Any input passed to this function
         * will be redirected using a temporary file.
         *
         * @param command {string}  The command string to run.
         * @param cwd {string}  The dir in which to run the command ('' or null
         *                      to inherit from parent).
         * @param env {string}  A string representing environment changes to
         *                      make for the child process, these are to be
         *                      merged in with the parent environment. The
         *                      format is: VAR1=value1\nVAR2=value2\n...
         * @param console {boolean} indicating whether the child should be
         *                          spawned with a new console window or not.
         * @param input {string}  If supplied, then the command is run via
         *                        "command < input", where the input is placed
         *                        in a temporary file and redirected to stdin.
         */
    unsigned long Run(in wstring command, in wstring cwd, in wstring env,
             in boolean console, in AString input);

        /**
         * Run and capture the output/error/retval from running the given
         * command. This call will block until the process has finished
         * before returning. It is suggested not to use this method unless you
         * are absolutely sure that the process will exit quickly, otherwise
         * if called in the main UI thread, then the whole Komodo UI will be
         * locked until the process is completed!
         *
         * @param command {string}  The command string to run.
         * @param cwd {string}  The dir in which to run the command ('' or null
         *                      to inherit from parent).
         * @param env {string}  A string representing environment changes to
         *                      make for the child process, these are to be
         *                      merged in with the parent environment. The
         *                      format is: VAR1=value1\nVAR2=value2\n...
         * @param input {string}  If supplied, then the command is run via
         *                        "command < input", where the input is placed
         *                        in a temporary file and redirected to stdin.
         * @param output {string}  The resulting stdout read from the process.
         * @param error {string}  The resulting stderr read from the process.
         * @returns {int}  The return code from the finished process.
         */
    unsigned long RunAndCaptureOutput(in wstring command,
                                 in wstring cwd, in wstring env,
                                 in AString input,
                                 // The output and error should be an AString
                                 // (in order to support null bytes), but
                                 // multiple AString out values cause problems
                                 // for Python XPCOM components: bug 84054.
                                 out wstring output, out wstring error);

        /**
         * Starts running the given command and then returns immediately.
         * An observer (nsIObserver) notification will be sent when the process
         * finally terminates. The arguments to the notification will be:
         *   subject: {Components.interfaces.koIRunProcess} The process handle.
         *   topic:   "run_terminated"
         *   data:    The command {string} that was just run.
         *
         * @param command {string}  The command string to run.
         * @param cwd {string}  The dir in which to run the command ('' or null
         *                      to inherit from parent).
         * @param env {string}  A string representing environment changes to
         *                      make for the child process, these are to be
         *                      merged in with the parent environment. The
         *                      format is: VAR1=value1\nVAR2=value2\n...
         * @param input {string}  If supplied, then the command is run via
         *                        "command < input", where the input is placed
         *                        in a temporary file and redirected to stdin.
         * @returns {Components.interfaces.koIRunProcess}  The process handle.
         */
    koIRunProcess RunAndNotify(in wstring command, in wstring cwd,
                               in wstring env, in AString input);


        /**
         * Starts running the given command and then returns immediately. If a
         * callback object is given, it will be called when the process has
         * finished.
         *
         * Note: The callback will be fired on the same thread that RunAsync was
         *       called (started) from.
         *
         * @param command {string}  The command string to run.
         * @param callback {koIRunAsyncCallback}  The callback handler to be
         *                      called at process completion.
         * @param cwd {string}  The dir in which to run the command ('' or null
         *                      to inherit from parent).
         * @param env {string}  A string representing environment changes to
         *                      make for the child process, these are to be
         *                      merged in with the parent environment. The
         *                      format is: VAR1=value1\nVAR2=value2\n...
         * @param input {string}  If supplied, then the command is run via
         *                        "command < input", where the input is placed
         *                        in a temporary file and redirected to stdin.
         * @returns {Components.interfaces.koIRunProcess}  The process handle.
         */
    koIRunProcess RunAsync(in wstring command,
                           [optional] in koIRunAsyncCallback callback,
                           [optional] in wstring cwd,
                           [optional] in wstring env,
                           [optional] in AString input);
    
    void argvSplit(in wstring argvStr, [optional] out unsigned long count,
                                  [retval, array, size_is(count)] out wstring arg);
};


[scriptable, uuid(3A4CDA03-F58F-436e-87D1-630D14E1A820)] 
interface koIRunEnvView : nsITreeView {
    // An tree view for Run Command environment variables.
    // XXX Should koIEnvironmentView just be used instead?

    void Set(in wstring variable, in wstring value);
    void Delete(in long index);
    // Return true iff have a datum with the given variable name.
    // XXX Techinally Have() is redundant given Index().
    boolean Have(in wstring variable);
    // Return the index of the given variable name, -1 if there is no
    // such variable in the view.
    long Index(in wstring variable);

    // Sort the find result data by a certain key (this key typically
    // matches the <treecol id=.../>  id's).
    void Sort(in string sortBy);

    // Return a specific piece of data at the given index.
    wstring GetVariable(in unsigned long index);
    wstring GetValue(in unsigned long index);
    
    // Return a string with the '\n'-separated environment variables:
    //    VAR1=value1\nVAR2=value2\n...
    // This is named after the Win32 API function with similar
    // funcionality.
    // XXX Do we have to deal with env vars with newlines?
    wstring GetEnvironmentStrings();
    // Set the environment data set from a string encoded as by
    // GetEnvironmentStrings().
    void SetEnvironmentStrings(in wstring s);
};
