#include "qmk_parser.h"

qmk_parser::qmk_parser()
{

}

qmk_parser::~qmk_parser()
{

}

QString qmk_parser::parseFiles(QString mainLayout, QString revLayout, QString mainConfig, QString revConfig, QString keymapConfig, QString keymap, QString keycodes, bool ignoreUndefinedKeys)
{
    m_isError = false;

    QVector<QStringList> allMacroList;
    QVector<QStringList> tempMacroList;
    QStringList macroInFile;
    int allMacroListSize;

    macroInFile = findMacro(deleteCommentsAndStrings(mainLayout));
    foreach (QString macro, macroInFile)
        allMacroList.push_back(parseMacro(macro));

    macroInFile = findMacro(deleteCommentsAndStrings(mainConfig));
    foreach (QString macro, macroInFile)
        tempMacroList.push_back(parseMacro(macro));
    allMacroListSize = allMacroList.size();
    for (int i = (allMacroListSize - 1); i >= 0; i--)
    {
        foreach (QStringList tempMacro, tempMacroList)
        {
            if (tempMacro[0] == allMacroList[i][0])
            {
                allMacroList.remove(i);
                break;
            }
        }
    }
    allMacroList.append(tempMacroList);
    tempMacroList.clear();

    macroInFile = findMacro(deleteCommentsAndStrings(revLayout));
    foreach (QString macro, macroInFile)
        tempMacroList.push_back(parseMacro(macro));
    allMacroListSize = allMacroList.size();
    for (int i = (allMacroListSize - 1); i >= 0; i--)
    {
        foreach (QStringList tempMacro, tempMacroList)
        {
            if (tempMacro[0] == allMacroList[i][0])
            {
                allMacroList.remove(i);
                break;
            }
        }
    }
    allMacroList.append(tempMacroList);
    tempMacroList.clear();

    macroInFile = findMacro(deleteCommentsAndStrings(revConfig));
    foreach (QString macro, macroInFile)
        tempMacroList.push_back(parseMacro(macro));
    allMacroListSize = allMacroList.size();
    for (int i = (allMacroListSize - 1); i >= 0; i--)
    {
        foreach (QStringList tempMacro, tempMacroList)
        {
            if (tempMacro[0] == allMacroList[i][0])
            {
                allMacroList.remove(i);
                break;
            }
        }
    }
    allMacroList.append(tempMacroList);
    tempMacroList.clear();

    macroInFile = findMacro(deleteCommentsAndStrings(keymapConfig));
    foreach (QString macro, macroInFile)
        tempMacroList.push_back(parseMacro(macro));
    allMacroListSize = allMacroList.size();
    for (int i = (allMacroListSize - 1); i >= 0; i--)
    {
        foreach (QStringList tempMacro, tempMacroList)
        {
            if (tempMacro[0] == allMacroList[i][0])
            {
                allMacroList.remove(i);
                break;
            }
        }
    }
    allMacroList.append(tempMacroList);
    tempMacroList.clear();

    keymap = deleteCommentsAndStrings(keymap);
    macroInFile = findMacro(keymap);
    foreach (QString macro, macroInFile)
        tempMacroList.push_back(parseMacro(macro));
    allMacroListSize = allMacroList.size();
    for (int i = (allMacroListSize - 1); i >= 0; i--)
    {
        foreach (QStringList tempMacro, tempMacroList)
        {
            if (tempMacro[0] == allMacroList[i][0])
            {
                allMacroList.remove(i);
                break;
            }
        }
    }
    allMacroList.append(tempMacroList);
    tempMacroList.clear();

    QString matrix = findExpression(keymap, "keymaps");
    QString matrixWithMacro = setMacroToExpression(matrix, allMacroList);

    QString clearedKeycodes = deleteCommentsAndStrings(keycodes);
    QStringList macroInKeycodes = findMacro(clearedKeycodes);
    QVector<QStringList> macroKeycodesList;
    foreach (QString s, macroInKeycodes)
        macroKeycodesList.push_back(parseMacro(s));

    matrixWithMacro = setMacroToExpression(matrixWithMacro, macroKeycodesList);

    int assignIndex = matrixWithMacro.indexOf("=");
    QString matrixVal = matrixWithMacro.mid(assignIndex + 1, matrixWithMacro.size() - assignIndex - 1);

    int leftBracketCnt = 0;
    for (int i = 0; i < matrixVal.size(); i++)
    {
        if (matrixVal[i] == "{")
            leftBracketCnt++;
        else if (matrixVal[i] == "}")
            break;
    }

    QVector<QVector<QVector<QString>>> matrix3;
    QVector<QVector<QString>> matrix2;
    QVector<QString> matrix1;

    if (leftBracketCnt == 1)
        matrix1 = parseOneDimArr(matrixVal);
    else if (leftBracketCnt == 2)
        matrix2 = parseTwoDimArr(matrixVal);
    else if (leftBracketCnt == 3)
        matrix3 = parseThreeDimArr(matrixVal);
    else
        return QString("Error - not correct dimensions in matrix data");

    if (m_isError)
        return QString("Parsing keyboard matrix error (ullegal matrix in keymap file)");

    QStringList keycodeEnums = findEnums(clearedKeycodes);

    QVector<QVector<QString>> enumValues;
    QVector<QVector<QString>> tempEnumValues;

    foreach (QString s, keycodeEnums) {
        if (!(getEnumName(s).contains("mouse", Qt::CaseInsensitive)))
        {
            tempEnumValues = getEnumValues(s);
            foreach (QVector<QString> enumValue, tempEnumValues)
            {
                if (!(enumValue[0].contains("mouse", Qt::CaseInsensitive)))
                    enumValues.push_back(enumValue);
            }
        }
    }

    QVector<QString> fnEnumVal(2);
    fnEnumVal[0] = "MO(1)";
    fnEnumVal[1] = "1";
    enumValues.push_back(fnEnumVal);

    m_Rows.clear();
    m_Columns.clear();
    m_diodeDirection = 0;
    foreach (QStringList macro, allMacroList) {
        if (macro[0] == "MATRIX_ROW_PINS")
            m_Rows = parseOneDimArr(macro[1].right(macro[1].size() - macro[1].indexOf("{")));
        else if (macro[0] == "MATRIX_COL_PINS")
            m_Columns = parseOneDimArr(macro[1].right(macro[1].size() - macro[1].indexOf("{")));
        else if (macro[0] == "DIODE_DIRECTION")
        {
            if (macro[1] == "COL2ROW")
                m_diodeDirection = 1;
            else
                m_diodeDirection = 2;
        }
    }

    if (!matrix3.isEmpty())
    {
        foreach (QVector<QVector<QString>> matrix2x, matrix3)
            matrix2.append(matrix2x);
    }

    if (!matrix2.isEmpty())
    {
        foreach (QVector<QString> matrix1x, matrix2)
            matrix1.append(matrix1x);
    }

    if ((matrix1.size() != (m_Columns.size() * m_Rows.size())) && (matrix1.size() != (2 * m_Columns.size() * m_Rows.size())))
        return QString("Error - matrix has not correct count of elements (maybe there is too many dimensions)");

    m_Matrix.resize(m_Rows.size());

    for (int i = 0; i < m_Rows.size(); i++)
    {
        m_Matrix[i].resize(m_Columns.size());
        for (int j = 0; j < m_Columns.size(); j++)
        {
            m_Matrix[i][j] = -1;
            foreach (QVector<QString> value, enumValues)
            {
                if (matrix1[i * m_Columns.size() + j] == value[0])
                {
                    m_Matrix[i][j] = value[1].toInt();
                    break;
                }
            }
            if (m_Matrix[i][j] == -1)
                m_Matrix[i][j] = strToNum(matrix1[i * m_Columns.size() + j]);
            if (m_Matrix[i][j] == -1)
            {
                if (!ignoreUndefinedKeys)
                    return QString("Error - undefined elements in matrix (%1)!").arg(matrix1[i * m_Columns.size() + j]);
                else
                    m_Matrix[i][j] = 0;
            }
        }
    }

    if (matrix1.size() == (m_Columns.size() * m_Rows.size()))
        m_FnMatrix = m_Matrix;
    else
    {
        m_FnMatrix.resize(m_Rows.size());
        for (int i = 0; i < m_Rows.size(); i++)
        {
            m_FnMatrix[i].resize(m_Columns.size());
            for (int j = 0; j < m_Columns.size(); j++)
            {
                m_FnMatrix[i][j] = -1;
                foreach (QVector<QString> value, enumValues)
                {
                    if (matrix1[m_Columns.size() * m_Rows.size() + i * m_Columns.size() + j] == value[0])
                    {
                        m_FnMatrix[i][j] = value[1].toInt();
                        break;
                    }
                }
                if (m_FnMatrix[i][j] == -1)
                {
                    m_FnMatrix[i][j] = strToNum(matrix1[m_Columns.size() * m_Rows.size() + i * m_Columns.size() + j]);
                    if (m_FnMatrix[i][j] == 1)  //  QMK FEATURE: CODE 0x01 IS TRANSPARENT
                        m_FnMatrix[i][j] = 0;
                }
                if (m_FnMatrix[i][j] == -1)
                {
                    if (!ignoreUndefinedKeys)
                        return QString("Error - undefined elements in matrix (%1)!").arg(matrix1[m_Columns.size() * m_Rows.size() + i * m_Columns.size() + j]);
                    else
                        m_FnMatrix[i][j] = 0;
                }
                if (m_FnMatrix[i][j] == 0)
                    m_FnMatrix[i][j] = m_Matrix[i][j];
            }
        }
    }

    return QString("");
}

QStringList qmk_parser::findMacro(QString src)
{
    QStringList lines = src.split("\n");
    QStringList macro;
    QString macroStr;
    bool macroFound = false;
    foreach (QString str, lines) {
        if (!macroFound)
        {
            if (str.contains("#define"))
            {
                macroFound = true;
                str = str.right(str.length() - 7);
            }
        }
        if (macroFound)
        {
            if (str.at(str.length() - 1) == "\\")
                macroStr += str.left(str.length() - 1);
            else
            {
                macroStr += str;
                macro.push_back(macroStr);
                macroFound = false;
                macroStr.clear();
            }
        }
    }
    return macro;
}

QStringList qmk_parser::parseMacro(QString macro)
{
    QString inputMacro;
    QStringList parsedMacro;

    inputMacro = macro.replace(QRegExp("^[ \t\v\r\n\f]+"), "");
    inputMacro = inputMacro.replace(QRegExp("[ \t\v\r\n\f]+"), " ");
    int firstSpace = inputMacro.indexOf(QRegExp("[ \t\v\r\n\f]+"));
    QString macroName = inputMacro.left(firstSpace);
    if (macroName.contains("("))
    {
        int leftBracketCnt = 0;
        int rightBracketCnt = 0;
        int argStart = inputMacro.indexOf("(");
        int argEnd = 0;
        for (int i = 0; i < inputMacro.size(); i++)
        {
            if (inputMacro[i] == "(")
                leftBracketCnt++;
            else if (inputMacro[i] == ")")
            {
                rightBracketCnt++;
                if (rightBracketCnt == leftBracketCnt)
                {
                    argEnd = i;
                    break;
                }
            }
        }
        if (argEnd <= argStart)
        {
            m_isError = true;
            return parsedMacro;
        }
        QString args = inputMacro.mid(argStart + 1, argEnd - argStart - 1);

        macroName = macroName.left(macroName.indexOf("("));
        parsedMacro.append(macroName);

        args += "\n";
        args.replace(QRegExp("^[ \t\v\r\n\f]+"), "");
        args.replace(QRegExp("[ \t\v\r\n\f]+$"), "");
        QStringList argsList = args.split(QRegExp("[, \t\v\r\n\f]+"));

        parsedMacro.append(argsList);

        QString body = inputMacro.right(inputMacro.size() - argEnd - 1);
        body += "\n";
        body = body.replace(QRegExp("^[ \t\v\r\n\f]+"), "");
        body = body.replace(QRegExp("[ \t\v\r\n\f]+$"), "");
        parsedMacro.append(body);
    }
    else
    {
        parsedMacro.append(macroName);

        if (!((firstSpace < 1) || ((inputMacro.size() - firstSpace) < 0)))
        {
            QString body = inputMacro.right(inputMacro.size() - firstSpace);
            body += "\n";
            body = body.replace(QRegExp("^[ \t\v\r\n\f]+"), "");
            body = body.replace(QRegExp("[ \t\v\r\n\f]+$"), "");
            parsedMacro.append(body);
        }
    }

    return parsedMacro;
}

QString qmk_parser::deleteCommentsAndStrings(QString src, bool deleteStrings)
{
    QString srcNoComments(src);
    int i = 0;
    bool isOneLineComment = false;
    bool isMultiLineComment = false;
    bool isString = false;
    QVector<QVector<int>> deleteAreas;
    QVector<int> tempArea(2, 0);
    while (i < srcNoComments.size())    {
        if (isOneLineComment)
        {
            if ((srcNoComments[i-1] != "\\") && (srcNoComments[i] == "\n"))
            {
                tempArea[1] = i;
                deleteAreas.push_back(tempArea);
                isOneLineComment = false;
            }
        }
        else if (isMultiLineComment)
        {
            if ((srcNoComments[i-1] == "*") && (srcNoComments[i] == "/"))
            {
                tempArea[1] = i + 1;
                deleteAreas.push_back(tempArea);
                isMultiLineComment = false;
            }
        }
        else if (isString)
        {
            if ((srcNoComments[i-1] != "\\") && (srcNoComments[i] == "\""))
            {
                tempArea[1] = i + 1;
                if (deleteStrings)
                    deleteAreas.push_back(tempArea);
                isString = false;
            }
        }
        else
        {
            if (srcNoComments[i] == "\"")
            {
                tempArea[0] = i;
                isString = true;
            }
            else if (i < (srcNoComments.size() - 1))
            {
                if ((srcNoComments[i] == "/") && (srcNoComments[i+1] == "/"))
                {
                    tempArea[0] = i;
                    isOneLineComment = true;
                }
                else if ((srcNoComments[i] == "/") && (srcNoComments[i+1] == "*"))
                {
                    tempArea[0] = i;
                    isMultiLineComment = true;
                }
            }
        }
        i++;
    }
    if (isOneLineComment)
    {
        tempArea[1] = srcNoComments.size();
        deleteAreas.push_back(tempArea);
    }
    if (isMultiLineComment)
        m_isError = true;
    if (isString)
        m_isError = true;

    for (int i = (deleteAreas.size() - 1); i >= 0; i--)
        srcNoComments.replace(deleteAreas[i][0], deleteAreas[i][1] - deleteAreas[i][0], "");

    //  THIS PART IS SIMPLE #IF 0 DELETER. #IF 0 IS IN KEYCODE.H. WORKS UNCORRECT IN OTHER SITUATIONS!!!
    bool isIfZero = false;
    QStringList srcLines = srcNoComments.split("\n");
    QString srcOut;
    for (int i = 0; i < srcLines.size(); i++)
    {
        if (srcLines[i].contains(QRegExp("^[\\s]*#if[\\s]*0")))
            isIfZero = true;
        if ((!isIfZero) && (!srcLines[i].contains("#endif")) && (!srcLines[i].contains("#else")) && (!srcLines[i].contains("#if")))
            srcOut += (srcLines[i] + "\n");
        if (isIfZero)
        {
            if ((srcLines[i].contains("#endif")) || (srcLines[i].contains("#else")))
                isIfZero = false;
        }
    }

    return srcOut;
}

QString qmk_parser::findExpression(QString src, QString expression)
{
    QStringList srcList = src.split("\n");
    QString fullExpression;
    foreach (QString str, srcList)
    {
        if (fullExpression.size() == 0)
        {
            if (str.contains(expression))
            {
                fullExpression = fullExpression + str + "\n";
                if (str.contains(";"))
                   break;
            }
        }
        else
        {
            fullExpression = fullExpression + str + "\n";
            if (str.contains(";"))
               break;
        }
    }
    fullExpression.replace(QRegExp("[ \t\v\r\n\f]+"), " ");
    fullExpression.replace(QRegExp("^[ \t\v\r\n\f]+"), "");
    fullExpression.replace(QRegExp("[ \t\v\r\n\f]+$"), "");
    return fullExpression;
}

QString qmk_parser::setMacroToExpression(QString expression, QVector<QStringList> macroList)
{
    expression.replace("\\", "");
    bool expressionHasMacro = true;

    while (expressionHasMacro)
    {
        expressionHasMacro = false;
        foreach (QStringList macro, macroList)
        {
            int macroIndex = expression.indexOf(macro[0]);
            if (macroIndex >= 0)
            {
                if (macroIndex > 0)
                {
                    if (QString(expression[macroIndex-1]).contains(QRegExp("[A-Za-z0-9_]")))
                        macroIndex = -1;
                }
                if ((macroIndex + macro[0].size()) < expression.size())
                {
                    if (QString(expression[macroIndex + macro[0].size()]).contains(QRegExp("[A-Za-z0-9_]")))
                        macroIndex = -1;
                }
            }
            if (macroIndex >= 0)
            {
                if (macro.size() > 2)   //  MACRO WITH ARGUMENTS
                {
                    int leftBracketCnt = 0;
                    int rightBracketCnt = 0;
                    int argStart = expression.indexOf("(", macroIndex);
                    int argEnd = 0;
                    for (int i = macroIndex; i < expression.size(); i++)
                    {
                        if (expression[i] == "(")
                            leftBracketCnt++;
                        else if (expression[i] == ")")
                        {
                            rightBracketCnt++;
                            if (rightBracketCnt == leftBracketCnt)
                            {
                                argEnd = i;
                                break;
                            }
                        }
                    }
                    if (argEnd <= argStart)
                    {
                        m_isError = true;
                        return QString("");
                    }
                    QString args = expression.mid(argStart + 1, argEnd - argStart - 1);

                    args += "\n";
                    args.replace(QRegExp("^[ \t\v\r\n\f]+"), "");
                    args.replace(QRegExp("[ \t\v\r\n\f]+$"), "");
                    QStringList argsList = args.split(QRegExp("[, \t\v\r\n\f]+"));

                    if (argsList.size() != (macro.size() - 2))
                    {
                        m_isError = true;
                        return QString("");
                    }

                    QString replacedText = macro[macro.size() - 1];

                    for (int i = 0; i < argsList.size(); i++)
                        replacedText.replace (macro[i + 1], argsList[i]);

                    expression.replace(macroIndex, argEnd - macroIndex + 1, replacedText);
                }
                else if (macro.size() == 2) //  MACRO WITHOUT ARGUMENTS
                    expression.replace(macro[0], macro[1]);

                if (macro.size() >= 2)
                    expressionHasMacro = true;
            }
        }
    }
    return expression;
}

QStringList qmk_parser::findEnums(QString src)
{
    QStringList output;
    QStringList srcRows = src.split("\n");
    QString currentEnum;
    foreach (QString s, srcRows)
    {
        if (currentEnum.isEmpty())
        {
            if (s.contains("enum"))
            {
                currentEnum = s + "\n";
                if (s.contains(";"))
                {
                    output.push_back(currentEnum);
                    currentEnum.clear();
                }
            }
        }
        else
        {
            currentEnum = currentEnum + s + "\n";
            if (s.contains(";"))
            {
                output.push_back(currentEnum);
                currentEnum.clear();
            }
        }
    }
    return output;
}

QString qmk_parser::getEnumName(QString enumSrc)
{
    if (!enumSrc.contains("{"))
        return QString("");
    enumSrc = enumSrc.left(enumSrc.indexOf("{"));
    enumSrc = enumSrc.simplified();
    QStringList enumNameList = enumSrc.split(QRegExp("\\s"));
    if (enumNameList.size() != 2)
        return QString("");
    if (enumNameList[0] != "enum")
        return QString("");
    return enumNameList[1];
}

QVector<QVector<QString>> qmk_parser::getEnumValues(QString src)
{
    QVector<QVector<QString>> output;
    QVector<QString> value(2);
    QVector<int> leftBrackets;
    QVector<int> rightBrackets;
    for (int i = 0; i < src.size(); i++)
    {
        if (src[i] == "{")
            leftBrackets.push_back(i);
        if (src[i] == "}")
            rightBrackets.push_back(i);
    }
    if ((leftBrackets.size() != 1) || (rightBrackets.size() != 1))
    {
        m_isError = true;
        return output;
    }
    QString enumContent = src.mid(leftBrackets[0] + 1, rightBrackets[0] - leftBrackets[0] - 1);
    QStringList enumValues = enumContent.split(QRegExp("[\\s]*,[\\s]*"));

    int currentIndex = 0;
    foreach (QString s, enumValues)
    {
        if (s.contains("="))
        {
            QStringList enumValueBody = s.split(QRegExp("[\\s]*=[\\s]*"));
            currentIndex = strToNum(enumValueBody[1].simplified());
            if (currentIndex == -1)
            {
                m_isError = true;
                return output;
            }
            value[0] = enumValueBody[0].simplified();
            value[1] = QString::number(currentIndex);
            currentIndex++;
        }
        else
        {
            value[0] = s.simplified();
            value[1] = QString::number(currentIndex);
            currentIndex++;
        }
        output.push_back(value);
    }

    return output;
}

QVector<QString> qmk_parser::parseOneDimArr(QString arr)
{
    arr.replace("{", "");
    arr.replace("}", "");
    arr.replace("\\", "");
    QVector<QString> output;
    QStringList arrElements = arr.split(QRegExp("[\\s]*,[\\s]*"));
    foreach (QString str, arrElements)
        output.push_back(str.simplified());
    return output;
}

QVector<QVector<QString>> qmk_parser::parseTwoDimArr(QString arr)
{
    QVector<QVector<QString>> output;
    QVector<int> leftBracketIndexes;
    QVector<int> rightBracketIndexes;
    for (int i = 0; i < arr.size(); i++)
    {
        if (arr[i] == "{")
            leftBracketIndexes.push_back(i);
        else if (arr[i] == "}")
            rightBracketIndexes.push_back(i);
    }
    if (leftBracketIndexes.size() != rightBracketIndexes.size())
    {
        m_isError = true;
        return output;
    }
    if ((leftBracketIndexes[1] < rightBracketIndexes[0]) && (leftBracketIndexes[leftBracketIndexes.size() - 1] < rightBracketIndexes[rightBracketIndexes.size() - 2]))
    {
        leftBracketIndexes.remove(0);
        rightBracketIndexes.remove(rightBracketIndexes.size() - 1);
    }
    for (int i = 0; i < (leftBracketIndexes.size() - 1); i++)
    {
        if (!((leftBracketIndexes[i] < rightBracketIndexes[i]) && (leftBracketIndexes[i + 1] > rightBracketIndexes[i])))
        {
            m_isError = true;
            return output;
        }
    }

    output.resize(leftBracketIndexes.size());
    QVector<int> arrIndexes;
    for (int i = 0; i < leftBracketIndexes.size(); i++)
    {
        int startIndex = 0;
        if (i > 0)
            startIndex = rightBracketIndexes[i - 1] + 1;
        QString indexStr = arr.mid(startIndex, leftBracketIndexes[i] - startIndex);
        int index = 0;
        if  ((indexStr.contains("[")) && (indexStr.contains("]")))
        {
            indexStr = indexStr.mid(indexStr.indexOf("[") + 1, indexStr.indexOf("]") - indexStr.indexOf("[") - 1);
            indexStr = indexStr.simplified();
            index = strToNum(indexStr);
            if (index < 0)
            {
                m_isError = true;
                return output;
            }
            arrIndexes.push_back(index);
        }
        QString oneDimentionStr = arr.mid(leftBracketIndexes[i], rightBracketIndexes[i] - leftBracketIndexes[i] + 1);
        if (!arrIndexes.isEmpty())
            output[index] = parseOneDimArr(oneDimentionStr);
        else
            output[i] = parseOneDimArr(oneDimentionStr);
    }

    if ((arrIndexes.size() != 0) && (arrIndexes.size() != output.size()))
    {
        output.clear();
        m_isError = true;
        return output;
    }

    return output;
}

QVector<QVector<QVector<QString>>> qmk_parser::parseThreeDimArr(QString arr)
{
    QVector<QVector<QVector<QString>>> output;
    QVector<int> leftBracketIndexes;
    QVector<int> rightBracketIndexes;
    for (int i = 0; i < arr.size(); i++)
    {
        if (arr[i] == "{")
            leftBracketIndexes.push_back(i);
        else if (arr[i] == "}")
            rightBracketIndexes.push_back(i);
    }
    if (leftBracketIndexes.size() != rightBracketIndexes.size())
    {
        m_isError = true;
        return output;
    }
    if ((leftBracketIndexes[2] < rightBracketIndexes[0]) && (leftBracketIndexes[leftBracketIndexes.size() - 1] < rightBracketIndexes[rightBracketIndexes.size() - 3]))
    {
        arr = arr.mid(leftBracketIndexes[0] + 1, rightBracketIndexes[rightBracketIndexes.size() - 1] - leftBracketIndexes[0] - 1);

//        leftBracketIndexes.remove(0);
//        rightBracketIndexes.remove(rightBracketIndexes.size() - 1);
    }

//    QVector<int> leftBracket2dimIndexes;
//    QVector<int> rightBracket2dimIndexes;
    leftBracketIndexes.clear();
    rightBracketIndexes.clear();

    int leftBracketCounter = 0;
    int rightBracketCounter = 0;
    for (int i = 0; i < arr.size(); i++)
    {
        if (arr[i] == "{")
        {
            if (leftBracketCounter == rightBracketCounter)
                leftBracketIndexes.push_back(i);
            leftBracketCounter++;
        }
        else if (arr[i] == "}")
        {
            rightBracketCounter++;
            if (leftBracketCounter == rightBracketCounter)
                rightBracketIndexes.push_back(i);
        }
    }

    if (leftBracketIndexes.size() != rightBracketIndexes.size())
    {
        m_isError = true;
        return output;
    }

    output.resize(leftBracketIndexes.size());

    QVector<int> arrIndexes;
    for (int i = 0; i < leftBracketIndexes.size(); i++)
    {
        int startIndex = 0;
        if (i > 0)
            startIndex = rightBracketIndexes[i - 1] + 1;
        QString indexStr = arr.mid(startIndex, leftBracketIndexes[i] - startIndex);
        int index = 0;
        if ((indexStr.contains("[")) && (indexStr.contains("]")))
        {
            indexStr = indexStr.mid(indexStr.indexOf("[") + 1, indexStr.indexOf("]") - indexStr.indexOf("[") - 1);
            indexStr = indexStr.simplified();
            index = strToNum(indexStr);
            if (index < 0)
            {
                m_isError = true;
                return output;
            }
            arrIndexes.push_back(index);
        }
        QString oneDimentionStr = arr.mid(leftBracketIndexes[i], rightBracketIndexes[i] - leftBracketIndexes[i] + 1);
        if (!arrIndexes.isEmpty())
            output[index] = parseTwoDimArr(oneDimentionStr);
        else
            output[i] = parseTwoDimArr(oneDimentionStr);
    }

    if ((arrIndexes.size() != 0) && (arrIndexes.size() != output.size()))
    {
        output.clear();
        m_isError = true;
        return output;
    }

    return output;
}

int qmk_parser::strToNum(QString s)
{
    bool success = false;
    int number;
    if ((s[0] != "0") || (s.size() == 1))
        number = s.toInt(&success, 10);
    else
    {
        if ((s[1] == "x") || (s[1] == "X"))
            number = s.right(s.size() - 2).toInt(&success, 16);
        else if ((s[1] == "b") || (s[1] == "B"))
            number = s.right(s.size() - 2).toInt(&success, 2);
        else
            number = s.right(s.size() - 1).toInt(&success, 8);
    }
    if (!success)
        number = -1;    //  ERROR SIGN
    return number;
}

QVector<QString> qmk_parser::getColumns()
{
    return m_Columns;
}

QVector<QString> qmk_parser::getRows()
{
    return m_Rows;
}

QVector<QVector<int>> qmk_parser::getMatrix()
{
    return m_Matrix;
}

QVector<QVector<int>> qmk_parser::getFnMatrix()
{
    return m_FnMatrix;
}

int qmk_parser::getDiodeDirection()
{
    return m_diodeDirection;
}
