#include "fcb_inc_prot"

//==========================================/
int get_char_valid_num(string s)
//==========================================/
    {
    string valid = "0123456789";

    return FindSubString(valid, s) + 1;
    }

//==========================================/
int get_char_valid_letter(string s)
//==========================================/
    {
    string valid = "abcdefghijklmnopqrstuvwxyz_";

    return FindSubString(valid, s) + 1;
    }

//==========================================/
int get_char_valid_name(string s)
//==========================================/
    {
    string valid = "abcdefghijklmnopqrstuvwxyz_0123456789";

    return FindSubString(valid, s) + 1;
    }

//==========================================/
int get_is_number(string num)
//==========================================/
    {
    return (num == IntToString(StringToInt(num)));
    }

//==========================================/
void store_arg(string function_arg, int exe_index)
//==========================================/
    {
    int args_index = GetLocalInt(FCB_HOST, CMD_ARGS_INDEX_ + IntToHexString(exe_index)) + 1;
    SetLocalInt(FCB_HOST, CMD_ARGS_INDEX_ + IntToHexString(exe_index), args_index);

    SetLocalString(FCB_HOST, CMD_ARGS_ + IntToHexString(exe_index | args_index), function_arg);
    }

//==========================================/
string retrieve_arg(int args_index)
//==========================================/
    {
    int exe_index = GetLocalInt(FCB_HOST, CMD_EXE_REF_INDEX);

    int args_index_max = GetLocalInt(FCB_HOST, CMD_ARGS_INDEX_ + IntToHexString(exe_index));
    if(args_index_max >= args_index)
        {
        return GetLocalString(FCB_HOST, CMD_ARGS_ + IntToHexString(exe_index | args_index));
        }

    return CMD_ERROR_STRING;
    }

//==========================================/
void set_function_result(string result)
//==========================================/
    {
    int exe_index = GetLocalInt(FCB_HOST, CMD_EXE_REF_INDEX);

    SetLocalString(FCB_HOST, CMD_FUNCTION_RESULT_ + IntToHexString(exe_index), result);
    }

//==========================================/
string get_function_result(int exe_index)
//==========================================/
    {
    return GetLocalString(FCB_HOST, CMD_FUNCTION_RESULT_ + IntToHexString(exe_index));
    }

//==========================================/
void set_function_result_valid()
//==========================================/
    {
    int exe_index = GetLocalInt(FCB_HOST, CMD_EXE_REF_INDEX);

    SetLocalInt(FCB_HOST, CMD_FUNCTION_RESP_VALID_ + IntToHexString(exe_index), CMD_VALID_BIT);
    }

//==========================================/
int get_function_result_valid(int exe_index)
//==========================================/
    {
    int valid = CMD_VALID_BIT & GetLocalInt(FCB_HOST, CMD_FUNCTION_RESP_VALID_ + IntToHexString(exe_index));
    DeleteLocalInt(FCB_HOST, CMD_FUNCTION_RESP_VALID_ + IntToHexString(exe_index));

    return valid;
    }

//==========================================/
string parse_init(string input)
//==========================================/
    {
    object user = GetLocalObject(FCB_HOST, USER);

    int parse_state = INPUT_PARSE_STATE_INIT;

    int cmd_str_len = GetStringLength(input);
    int cmd_str_pos = 0;

    //kill end spaces
    string s = GetSubString(input, cmd_str_len-1, 1);
    while(cmd_str_len >= 0 && s == CMD_TXT_SPACE)
        {
        cmd_str_len--;
        s = GetSubString(input, cmd_str_len-1, 1);
        }

    s = GetSubString(input, cmd_str_pos, 1);
    while(cmd_str_pos <= cmd_str_len)
        {
        switch(parse_state)
            {
            //--------------------------------------/
            case INPUT_PARSE_STATE_INIT:
                {
                if(s == CMD_TXT_CMDSTART)
                    {
                    parse_state = INPUT_PARSE_STATE_CMD;
                    }

                else if(s != CMD_TXT_SPACE)
                    {
                    return input;
                    }

                break;
                }

            //--------------------------------------/
            case INPUT_PARSE_STATE_CMD:
                {
                DeleteLocalInt(FCB_HOST, CMD_EXE_INDEX);
                string parsed_cmd = parse_var(GetStringRight(input, cmd_str_len - cmd_str_pos), user);

                SendMessageToPC(user, parsed_cmd);
                return parsed_cmd;

                break;
                }
            }

        cmd_str_pos++;
        s = GetSubString(input, cmd_str_pos, 1);
        }

    return input;
    }

//==========================================/
string parse_var(string cmd, object user)
//==========================================/
    {
    string CMD_TXT_QUOTE = GetLocalString(FCB_HOST, CMD_QUOTE);

    string arg = "";

    int bracket_cnt = 0;

    int parse_state = VAR_PARSE_STATE_INIT;

    int cmd_str_len = GetStringLength(cmd);
    int cmd_str_pos = 0;

    //kill end spaces
    string s = GetSubString(cmd, cmd_str_len-1, 1);
    while(cmd_str_len >= 0 && s == CMD_TXT_SPACE)
        {
        cmd_str_len--;
        s = GetSubString(cmd, cmd_str_len-1, 1);
        }

    //begin
    //begin
    s = GetSubString(cmd, cmd_str_pos, 1);
    while(cmd_str_pos <= cmd_str_len)
        {
        //--------------------------------------/
        if(s == CMD_TXT_BRACKET_START)
            {
            bracket_cnt++;
            }
        else if(s == CMD_TXT_BRACKET_END)
            {
            bracket_cnt--;
            }
        if(bracket_cnt < 0)
            {
            parse_state = VAR_PARSE_STATE_ERROR;
            }

        //--------------------------------------/
        switch(parse_state)
            {
            //--------------------------------------/
            case VAR_PARSE_STATE_INIT:
                {
                if(s == CMD_TXT_QUOTE)
                    {
                    parse_state = VAR_PARSE_STATE_STRING;
                    }

                else if(get_char_valid_letter(s))
                    {
                    arg += s;

                    parse_state = VAR_PARSE_STATE_FUNCTION;
                    }

                else if(get_char_valid_num(s))
                    {
                    arg += s;

                    if(cmd_str_pos == cmd_str_len-1)
                        {
                        return arg;
                        }
                    else
                        {
                        parse_state = VAR_PARSE_STATE_NUM;
                        }
                    }

                else if(s != CMD_TXT_SPACE)
                    {
                    parse_state = VAR_PARSE_STATE_ERROR;
                    }

                break;
                }

            //--------------------------------------/
            case VAR_PARSE_STATE_STRING:
                {
                if(s == CMD_TXT_QUOTE)
                    {
                    if(cmd_str_pos == cmd_str_len-1)
                        {
                        return arg;
                        }

                    else
                        {
                        parse_state = VAR_PARSE_STATE_ERROR;
                        }
                    }

                else
                    {
                    arg += s;
                    }

                break;
                }

            //--------------------------------------/
            case VAR_PARSE_STATE_FUNCTION:
                {
                if(s == CMD_TXT_BRACKET_START)
                    {
                    return parse_function_arg(arg, GetStringRight(cmd, cmd_str_len - cmd_str_pos-1), user);
                    }

                else if(get_char_valid_name(s))
                    {
                    arg += s;
                    }

                else
                    {
                    parse_state = VAR_PARSE_STATE_ERROR;
                    }

                break;
                }

            //--------------------------------------/
            case VAR_PARSE_STATE_NUM:
                {
                if(get_char_valid_num(s))
                    {
                    arg += s;

                    if(cmd_str_pos == cmd_str_len-1)
                        {
                        return arg;
                        }
                    }

                else
                    {
                    parse_state = VAR_PARSE_STATE_ERROR;
                    }

                break;
                }

            //--------------------------------------/
            case VAR_PARSE_STATE_ERROR:
                {
                SendMessageToPC(user, "var: " + CMD_ERROR_MSG);
                return CMD_ERROR_STRING;
                }
            }

        cmd_str_pos++;
        s = GetSubString(cmd, cmd_str_pos, 1);
        }

    ////
    SendMessageToPC(user, "var: " + CMD_ERROR_MSG);
    return CMD_ERROR_STRING;
    }

//==========================================/
string parse_function_arg(string function_name, string cmd, object user)
//==========================================/
    {
    string CMD_TXT_QUOTE = GetLocalString(FCB_HOST, CMD_QUOTE);
    //function_name( a, b, c, d, ...)
    //**************X <- begin here

    int exe_index = GetLocalInt(FCB_HOST, CMD_EXE_INDEX) + INCR_F10;
    SetLocalInt(FCB_HOST, CMD_EXE_INDEX, exe_index);

    string function_arg = "";

    int bracket_cnt = 1;
    int quote_state = 0;

    int parse_state = CMD_PARSE_STATE_INIT;

    int cmd_str_len = GetStringLength(cmd);
    int cmd_str_pos = 0;

    //kill end spaces
    string s = GetSubString(cmd, cmd_str_len-1, 1);
    while(cmd_str_len >= 0 && s == CMD_TXT_SPACE)
        {
        cmd_str_len--;
        s = GetSubString(cmd, cmd_str_len-1, 1);
        }

    //begin
    s = GetSubString(cmd, cmd_str_pos, 1);
    while(cmd_str_pos <= cmd_str_len)
        {
        //--------------------------------------/
        if(s == CMD_TXT_BRACKET_START)
            {
            bracket_cnt++;
            }
        else if(s == CMD_TXT_BRACKET_END)
            {
            bracket_cnt--;
            }
        if(bracket_cnt < 0)
            {
            parse_state = CMD_PARSE_STATE_ERROR;
            }

        //--------------------------------------/
        if(s == CMD_TXT_QUOTE)
            {
            quote_state = !quote_state;
            }

        /////
        //SpeakString("state: " + IntToString(parse_state));
        //SpeakString("arg: " + function_arg);

        //--------------------------------------/
        switch(parse_state)
            {
            //--------------------------------------/
            case CMD_PARSE_STATE_INIT:
                {
                if(s == CMD_TXT_BRACKET_END)
                    {
                    if(cmd_str_pos == cmd_str_len-1)
                        {
                        parse_state = CMD_PARSE_STATE_END;
                        }
                    else
                        {
                        parse_state = CMD_PARSE_STATE_ERROR;
                        }
                    }

                else if(s != CMD_TXT_SPACE)
                    {
                    function_arg += s;

                    parse_state = CMD_PARSE_STATE_ARG;
                    }

                break;
                }

            //--------------------------------------/
            case CMD_PARSE_STATE_ARG:
                {
                if(s == CMD_TXT_COMMA && bracket_cnt == 1 && !quote_state)
                    {
                    if(function_arg != CMD_TXT_BLANK)
                        {
                        string arg = parse_var(function_arg, user);

                        if(arg != CMD_ERROR_STRING)
                            {
                            store_arg(arg, exe_index);
                            function_arg = CMD_TXT_BLANK;
                            }

                        else
                            {
                            parse_state = CMD_PARSE_STATE_ERROR;
                            }
                        }
                    else
                        {
                        parse_state = CMD_PARSE_STATE_ERROR;
                        }
                    }

                else if(s == CMD_TXT_BRACKET_END && bracket_cnt == 0 && !quote_state)
                    {
                    if(function_arg != CMD_TXT_BLANK)
                        {
                        string arg = parse_var(function_arg, user);

                        if(arg != CMD_ERROR_STRING)
                            {
                            store_arg(arg, exe_index);

                            if(cmd_str_pos == cmd_str_len-1)
                                {
                                parse_state = CMD_PARSE_STATE_END;
                                }
                            else
                                {
                                parse_state = CMD_PARSE_STATE_ERROR;
                                }
                            }

                        else
                            {
                            parse_state = CMD_PARSE_STATE_ERROR;
                            }
                        }

                    else
                        {
                        parse_state = CMD_PARSE_STATE_ERROR;
                        }
                    }

                else
                    {
                    function_arg += s;
                    }

                break;
                }

            //--------------------------------------/
            case CMD_PARSE_STATE_END:
                {
                SetLocalInt(FCB_HOST, CMD_EXE_REF_INDEX, exe_index);
                ExecuteScript(CMD_SCRIPT_PREFIX + function_name, FCB_HOST);

                DeleteLocalInt(FCB_HOST, CMD_EXE_REF_INDEX);
                DeleteLocalInt(FCB_HOST, CMD_ARGS_INDEX_ + IntToHexString(exe_index));

                if(get_function_result_valid(exe_index))
                    {
                    return get_function_result(exe_index);
                    }

                break;
                }

            //--------------------------------------/
            case CMD_PARSE_STATE_ERROR:
                {
                SendMessageToPC(user, "function: " + CMD_ERROR_MSG);

                DeleteLocalInt(FCB_HOST, CMD_ARGS_INDEX_ + IntToHexString(exe_index));
                return CMD_ERROR_STRING;
                }
            }

        cmd_str_pos++;
        s = GetSubString(cmd, cmd_str_pos, 1);
        }

    ////
    SendMessageToPC(user, "function: " + CMD_ERROR_MSG);

    DeleteLocalInt(FCB_HOST, CMD_ARGS_INDEX_ + IntToHexString(exe_index));
    return CMD_ERROR_STRING;
    }
