//---------------------------------------------------------------------------------------------------------------
// This function checks if argument is constant. If it is it returns true, overwise false
//---------------------------------------------------------------------------------------------------------------
static bool GetConstantIDFromArgument(gtASCIIString sArgument, gtASCIIString cKey, unsigned int& nSlotID)
{
    unsigned int nKeyPosition = (unsigned int)sArgument.find(cKey);

    // Check if cKey is not end of other argument
    if (nKeyPosition == std::string::npos || (nKeyPosition != 0
                                              && sArgument[nKeyPosition - 1] != '>' // code can be in HTML
                                              && sArgument[nKeyPosition - 1] != ' '))

    {
        return false;
    } // End of if

    // Looking for not digital symbols in argument
    unsigned int nNextNotDigit = (unsigned int)sArgument.find_first_not_of("0123456789", nKeyPosition + cKey.length());

    gtASCIIString sSlotID; // this variable contains string with the slot number

    if (nNextNotDigit == std::string::npos)   // All character after cKey are digits
    {
        sSlotID = sArgument.substr(nKeyPosition + cKey.length());
    } // End of if

    // Check if the variable is finished with digit
    else if ((sArgument[nNextNotDigit] != '<' && sArgument[nNextNotDigit] != ' ' && sArgument[nNextNotDigit] != ',' &&
              sArgument[nNextNotDigit] != '.' && sArgument[nNextNotDigit] != '['  && sArgument[nNextNotDigit] != '\n')
             || nNextNotDigit <= nKeyPosition + 1)
    {
        return false;
    } // End of else if
    else
    {
        sSlotID = sArgument.substr(nKeyPosition + cKey.length(), nNextNotDigit - nKeyPosition - cKey.length());
    } // End of else

    int nScanRes = sscanf_s(sSlotID.asCharArray(), "%d", &nSlotID);

    if (nScanRes < 1)
    {
        Log(logERROR, "%s: Failed to read integer from Str = %s\n", __FUNCTION__, sSlotID.asCharArray());
        return false;
    }

    return true;
}// End of GetConstantIDFromArgument
//---------------------------------------------------------------------------------------------------------------
// This function returns of slots used in code
// cKey is symbol which shows what kind of slots are requested: 'c' for float constants, 'b' for boolean
// constants etc. Results are kept in usedSlots.
//---------------------------------------------------------------------------------------------------------------
long GetConstantsFromCode(gtASCIIString code, gtASCIIString cKey, std::list<unsigned long>& usedSlots)
{
    long hr = 0;
    typedef std::map<  gtASCIIString, std::vector<unsigned long> > ArgumentType;
    typedef std::map<  gtASCIIString, std::vector<unsigned long> >::iterator ArgumentIter;

    ArgumentType ArgumentLength;
    ArgumentIter ArgIter;

    // This map contains infoemation about arguments lenth
    // i.e the third argument of the m4x4 itstruction is 4x4 matrix,
    // which uses 4 slots, so if shader has instruction m4x4 oPos, v0, c0 it means
    // c0, c1, c3 and c4 are used, that is why ArgumentLength["m4x4"][2] = 4

    ArgumentLength["m3x2"].resize(3);
    ArgumentLength["m3x2"][0] = 1;
    ArgumentLength["m3x2"][1] = 1;
    ArgumentLength["m3x2"][2] = 2;
    ArgumentLength["m3x3"].resize(3);
    ArgumentLength["m3x3"][0] = 1;
    ArgumentLength["m3x3"][1] = 1;
    ArgumentLength["m3x3"][2] = 3;
    ArgumentLength["m3x4"].resize(3);
    ArgumentLength["m3x4"][0] = 1;
    ArgumentLength["m3x4"][1] = 1;
    ArgumentLength["m3x4"][2] = 4;
    ArgumentLength["m4x3"].resize(3);
    ArgumentLength["m4x3"][0] = 1;
    ArgumentLength["m4x3"][1] = 1;
    ArgumentLength["m4x3"][2] = 3;
    ArgumentLength["m4x4"].resize(3);
    ArgumentLength["m4x4"][0] = 1;
    ArgumentLength["m4x4"][1] = 1;
    ArgumentLength["m4x4"][2] = 4;

    ArgumentLength["texm3x2depth"].resize(2);
    ArgumentLength["texm3x2depth"][0] = 3;
    ArgumentLength["texm3x2depth"][1] = 2;
    ArgumentLength["texm3x2pad"].resize(2);
    ArgumentLength["texm3x2pad"][0] = 3;
    ArgumentLength["texm3x2pad"][1] = 2;
    ArgumentLength["texm3x2tex"].resize(2);
    ArgumentLength["texm3x2tex"][0] = 3;
    ArgumentLength["texm3x2tex"][1] = 2;
    ArgumentLength["texm3x3"].resize(2);
    ArgumentLength["texm3x3"][0] = 3;
    ArgumentLength["texm3x3"][1] = 3;
    ArgumentLength["texm3x3pad"].resize(2);
    ArgumentLength["texm3x3pad"][0] = 3;
    ArgumentLength["texm3x3pad"][1] = 3;
    ArgumentLength["texm3x3spec"].resize(2);
    ArgumentLength["texm3x3spec"][0] = 3;
    ArgumentLength["texm3x3spec"][1] = 3;
    ArgumentLength["texm3x3tex"].resize(2);
    ArgumentLength["texm3x3tex"][0] = 3;
    ArgumentLength["texm3x3tex"][1] = 3;
    ArgumentLength["texm3x3vspec"].resize(2);
    ArgumentLength["texm3x3vspec"][0] = 3;
    ArgumentLength["texm3x3vspec"][1] = 3;


    unsigned int nStartOfToken = 0;

    // This loop splits code to tokens
    while (nStartOfToken != std::string::npos)
    {
        unsigned int nNextToken = (unsigned int)code.find('\n', nStartOfToken + 1);

        // comment
        gtASCIIString sToken = (nNextToken == std::string::npos) ? code.substr(nStartOfToken) : code.substr(nStartOfToken, nNextToken - nStartOfToken);

        if (sToken.length() > 1 && sToken.substr(0, 1) != "//")      // Skip comments and empty strings
        {
            unsigned int nStartOfInstruction = (unsigned int)sToken.find_first_not_of(" \n", 0);      // comment
            unsigned int nEndOfInstruction = (unsigned int)sToken.find(' ', nStartOfInstruction);

            if (nEndOfInstruction == std::string::npos)
            {
                nStartOfToken = nNextToken;
                continue;
            }

            gtASCIIString sCommand = sToken.substr(nStartOfInstruction, nEndOfInstruction - nStartOfInstruction);

            unsigned int nArgument = 0;
            unsigned int nStartOfArgument = nEndOfInstruction + 1;
            unsigned int nEndOfArgument;

            do // This separates arguments of command
            {
                nEndOfArgument = (unsigned int)sToken.find(',', nStartOfArgument);
                gtASCIIString sArgument = (nEndOfArgument == std::string::npos) ?
                                          sToken.substr(nStartOfArgument) :
                                          sToken.substr(nStartOfArgument, nEndOfArgument - nStartOfArgument);
                unsigned int nSlotID;

                if (GetConstantIDFromArgument(sArgument, cKey,  nSlotID) == false)
                {
                    nArgument++;
                    nStartOfArgument = nEndOfArgument + 1;
                    continue;
                }

                // Calculation of used constants. Default is 1. Next 2 lines check if the command in "special cases map"
                ArgIter = ArgumentLength.find(sCommand);

                int nArgsCount = (ArgIter == ArgumentLength.end()) ? 1 :   // If coommand has not been find the lenth of argument is supposed 1
                                 (ArgIter->second.size() > nArgument ? ArgIter->second[nArgument] :
                                  1);  // If there no information for considered argument its lenth is supposed 1

                // This loop adds variables in the used constants list
                for (unsigned int i = nSlotID; i < nSlotID + nArgsCount; i++)
                {
                    bool nNotFind = true;

                    for (std::list<unsigned long>::const_iterator iter = usedSlots.begin(); iter != usedSlots.end(); ++iter)
                    {
                        if (*iter == i)
                        {
                            nNotFind = false;
                            break;
                        }
                    }

                    if (nNotFind)
                    {
                        usedSlots.push_back(i);
                    } // End of if
                }// End of for

                nArgument++;
                nStartOfArgument = nEndOfArgument + 1;
            }
            while (nEndOfArgument != std::string::npos);
        } // End of if ( sToken.size() > 1 && sToken.substr( 0, 1 ) != "//" )

        nStartOfToken = nNextToken;
    }// End of while ( nFound  != string::npos )

    return hr;
}// End of GetConstantsFromCode