/* SPDX-License-Identifier: BSD-3-Clause */
/*
 * Copyright 2015 Raritan Inc. All rights reserved.
 */

/**
 * Lua-Service
 *
 * Lua-Service is a service that you can use to upload and execute a Lua script.
 *
 * When the service is starting, a cleanup will be happend at first. That means
 * still running scripts will be killed and it will be tested for which script is
 * an option given. Does here something not match, then the script or the option
 * will be deleted.
 *
 * After the service is launched, the option 'autoRestart' will be for any script
 * evaluated. If the flag is 'true', the script is going to be executed with a
 * short delay (Environment->autoStartDelay).
 *
 * You can download and upload a script with the commands getScript() and setScript().
 * When on uploading the script name is not present a new script will be created.
 * If the name is already taken, then the old script will be overwritten.
 *
 * Use startScript() to execute a lua script and terminateScript() to stop a script.
 * If the option 'autoRestart' is set to 'true', then the script starts automatically
 * after it has exited.
 *
 * To get the output for a script use the command getScriptOutput(). The output
 * is limited to 'Environment->outputBufferSize' bytes and mapped to a virtual
 * address. On the first query call the method with starting address zero. After
 * that use the returned address 'nAddr' for the next request.
 *
 * A script can be called with arguments (see options and startWithArgs).
 */
module luaservice {

    /**
     * A structure that descripts the state of a script.
     *
     * When a script is uploaded the new execState is STAT_NEW. exitCode and
     * signal is not valid.
     *
     * When the execState is changing to STAT_TERMINATED then exitCode and signal
     * will be set.
     */
    structure ScriptState {

        /** execution state for a scripts */
        enumeration ExecState {
            STAT_NEW,          ///< the script never ran (after uploading or system (re)start)
            STAT_RUNNING,      ///< script state is running
            STAT_TERMINATED,   ///< script state is terminated
            STAT_RESTARTING    ///< script is terminated and restarts after 'restart interval'
        };

        /** Descripts the type of exitStatus */
        enumeration ExitType {
            EXIT_CODE,     ///< exitStatus is an exit code
            SIGNAL         ///< exitStatus is a signal
        };

        ExecState execState;   ///< execution state of the script
        ExitType  exitType;    ///< type of exit code
        int       exitStatus;  ///< exit status or signal
    };

    /** some script options */
    structure ScriptOptions_2_0_0 {
        map <string, string> defaultArgs;   ///< default arguments are passed to the lua script
        boolean autoStart;                  ///< starts a script after system booting
        boolean autoRestart;                ///< restarts a script after termination or crash
    };

    /**
     * The struct represents two kinds of information:
     * - limit (l)
     * - current status (cs)
     * Is a limit set to zero then there is no limit set. The unit of size
     * is byte. The unit of interval is millisecond.
     */
    structure Environment_2_0_0 {
        int maxScriptMemoryGrowth;///< maximum virtual memory growth per script  (l)
        int maxAmountOfScripts;   ///< number of scripts that can be stored  (l)
        int amountOfScripts;      ///< number of scripts that are stored  (cs)
        int maxScriptSize;        ///< maximum size of a script file  (l)
        int maxAllScriptSize;     ///< maximum size of all script files  (l)
        int allScriptSize;        ///< size of all script files  (cs)
        int outputBufferSize;     ///< output buffer size per script  (l)
        int restartInterval;      ///< minimum delay to next (re)start (cs)
        int autoStartDelay;       ///< minimum delay to 'autoStart' a script
    };

    /**
     * There is a single manager instance.
     */
    interface Manager_2_0_1 {

        /** Error codes */
        constant int NO_ERROR                          =  0; ///< no Error
        constant int ERR_INVALID_NAME                  =  1; ///< script name is invalid
        constant int ERR_NO_SUCH_SCRIPT                =  2; ///< script name not found
        constant int ERR_MAX_SCRIPT_NUMBERS_EXCEEDED   =  3; ///< maximum amount of stored script files is reached
        constant int ERR_MAX_SCRIPT_SIZE_EXCEEDED      =  4; ///< maximum size of a script file is reached
        constant int ERR_MAX_ALL_SCRIPT_SIZE_EXCEEDED  =  5; ///< maximum size of all script files is reached
        constant int ERR_NOT_TERMINATED                =  6; ///< script is not terminated
        constant int ERR_NOT_RUNNING                   =  7; ///< script is not running
        constant int ERR_INVALID_ADDR                  =  8; ///< address parameter is wrong
        constant int ERR_TOO_MANY_ARGUMENTS            = 10; ///< too many arguments
        constant int ERR_ARGUMENT_NOT_VALID            = 11; ///< the argument has one or more invalid characters

        /**
         * Upload a script to instance
         *
         * If there is a script with the same name the new script will replace
         * the existing script (script must be in STAT_NEW or STAT_TERMINATED).
         *
         * @param name The name of the script file
         * @param script The script file packed in a string
         * @param options Options that can be set or not
         *
         * @return NO_ERROR                           if OK
         * @return ERR_INVALID_NAME                   if script name is invalid
         * @return ERR_MAX_SCRIPT_SIZE_EXCEEDED       if the size of the new script is greater then the maximum file size
         * @return ERR_MAX_ALL_SCRIPT_SIZE_EXCEEDED   if maximum size of all script files is reached
         * @return ERR_MAX_SCRIPT_NUMBERS_EXCEEDED    if maximum amount of script files is reached
         * @return ERR_NOT_TERMINATED                 if try to replace a running script
         */
        int setScript(in string name, in string script, in ScriptOptions_2_0_0 options);

        /**
         * To download a script file to user.
         *
         * @param name The name of an existing script
         *
         * @return NO_ERROR             if OK
         * @return ERR_INVALID_NAME     if script name is invalid
         * @return ERR_NO_SUCH_SCRIPT   if there is no script with the name
         */
        int getScript(in string name, out string script);

        /**
         * Returns all script names in a string vector.
         *
         * If there are no scripts the vector is empty.
         *
         * @return A vector with all script names.
         */
        vector<string> getScriptNames();

        /**
         * Deletes a script.
         *
         * @param name The name of the script
         *
         * @return NO_ERROR             if OK
         * @return ERR_INVALID_NAME     if script name is invalid
         * @return ERR_NO_SUCH_SCRIPT   if there is no script with the name
         * @return ERR_NOT_TERMINATED   if try to delete a running script
         */
        int deleteScript(in string name);

        /**
         * Sets new options for a script.
         *
         * @param name The name of the script
         * @param options The new options
         *
         * @return NO_ERROR                      if OK
         * @return ERR_INVALID_NAME              if script name is invalid
         * @return ERR_NO_SUCH_SCRIPT            if there is no script with the name
         * @return ERR_TOO_MANY_ARGUMENTS        if the size of the map is to big
         * @return ERR_ARGUMENT_NOT_VALID        if a string in the arguments is not
         */
        int setScriptOptions(in string name, in ScriptOptions_2_0_0 options);

        /**
         * Returns the options for a script.
         *
         * @param name The name of the script
         * @param options The return value
         *
         * @return NO_ERROR             if OK
         * @return ERR_INVALID_NAME     if script name is invalid
         * @return ERR_NO_SUCH_SCRIPT   if there is no script with the name
         */
        int getScriptOptions(in string name, out ScriptOptions_2_0_0 options);

        /**
         * To query the environment information.
         *
         * @return a struct with the environment information
         */
        Environment_2_0_0 getEnvironment();

        /**
         * To get output from a script as a string
         *
         * The output is stored in a string buffer with a defined size. The buffer is addressable with an
         * (virtual) address. The address will be increased ervery time when the buffer will be filled.
         *
         * To get the output for the first time just call with address zero and then use the returned nAddr
         * argument.
         *
         * If iAddr is negative then the last n bytes will be returned, e.g. -9 returns the last 9 characters.
         * If iAddr is zero then the whole available buffer will be returned.
         * If iAddr is positive then the returned buffer starts at this address.
         * If iAddr is equal to nAddr then there is no data available
         * If iAddr and oAddr is not equal then there were data lost (execption: first call with zero).
         *
         * @param name The name of the script
         * @param iAddr The virtual start address where the returned output should begin.
         * @param oAddr The virtual address from where the string starts.
         * @param nAddr The virtual address for the next query.
         * @param more A boolean whitch indicates if there is more data available.
         *
         * @return NO_ERROR                      if OK
         * @return ERR_INVALID_NAME              if file name is invalid
         * @return ERR_NO_SUCH_SCRIPT            if there is no script with the name
         * @return ERR_INVALID_ADDR              if iAddr is negative and the absolute value of parameter iAddr is greater as the limit
         */
        int getScriptOutput(in string name, in long iAddr, out long oAddr, out long nAddr, out string oString, out boolean more);

        /**
         * Clear the output buffer of a script.
         *
         * @param name The name of the script
         *
         * @return NO_ERROR                      if OK
         * @return ERR_INVALID_NAME              if file name is invalid
         * @return ERR_NO_SUCH_SCRIPT            if there is no script with the name
         */
        int clearScriptOutput(in string name);

        /**
         * To start a script
         *
         * The function starts a lua script.
         *
         * @return NO_ERROR             if OK
         * @return ERR_INVALID_NAME     if file name is invalid
         * @return ERR_NO_SUCH_SCRIPT   if there is no script with the name
         * @return ERR_NOT_TERMINATED   if the script is running or restarting
         */
        int startScript(in string name);

        /**
         * To start a script with arguments
         *
         * The function starts a lua script. Additionally you can add arguments which are available from the
         * lua script. This args will override the default arguments. All args are stored in a global table
         * called ARGS in lua.
         *
         * @return NO_ERROR                      if OK
         * @return ERR_INVALID_NAME              if file name is invalid
         * @return ERR_NO_SUCH_SCRIPT            if there is no script with the name
         * @return ERR_NOT_TERMINATED            if the script is running or restarting
         * @return ERR_TOO_MANY_ARGUMENTS        if the size of the map is to big
         * @return ERR_ARGUMENT_NOT_VALID        if a string in the arguments is not valid
         */
        int startScriptWithArgs(in string name, in map<string, string> arguments);

        /**
         * To stop a script
         *
         * This command stops a running or restarting script. After terminating the option autorestart will
         * not be evaluated.
         *
         * @return NO_ERROR             if OK
         * @return ERR_INVALID_NAME     if file name is invalid
         * @return ERR_NO_SUCH_SCRIPT   if there is no script with the name
         * @return ERR_NOT_RUNNING      if the script is not running or restarting
         */
        int terminateScript(in string name);

        /**
         * Returns the state for a single script.
         *
         * @param name The script name
         * @param state The state of the script
         *
         * @return NO_ERROR             if OK
         * @return ERR_INVALID_NAME     if file name is invalid
         * @return ERR_NO_SUCH_SCRIPT   if there is no script with the name
         */
        int getScriptState(in string name, out ScriptState state);


        /**
         * Returns the state for all scripts. If the map is empty then there are no scripts on the machine.
         *
         * @return A map<string name, ScriptState state> with name and state for all available scripts.
         */
        map<string, ScriptState> getScriptStates();
    };

}
