#include "processparser.h"
#include "tasksAmmFim.h"

ProcessParser::ProcessParser(QObject *parent) : QObject(parent) //TODO: переименовать в XMLProcessParser?
{

}

void ProcessParser::initialize(ProcessingSystem *processingSystem)
{
    this->processingSystem = processingSystem;
}

void ProcessParser::slot_read(ClientHandler *client, QByteArray array)
{
    QXmlStreamReader xmlReader(array);

    xmlReader.readNext();   // Переходим к первому элементу в файле

    //Крутимся в цикле до тех пор, пока не достигнем конца документа
    while(!xmlReader.atEnd())
    {
        //Проверяем, является ли элемент началом тега
        if(xmlReader.isStartElement())
        {
            //Анализируем теги
            if(xmlReader.name() == "ClientAutorization")
            {//Запрос авторизации от клиента

                clientAuth(xmlReader,client);
            }
            else if(xmlReader.name() == "ClientDeAutorization")
            {//Запрос ДеАвторизации от клиента

                clientDeAuth(xmlReader,client);
            }
            else if(xmlReader.name() == "QueryToDB")
            {//Запрос к базе данных от клиента

                queryToDb(xmlReader,client, array);
            }
            else if(xmlReader.name() == "QueryTasksXML")
            {//Запрос файла XML с задачами

                queryTasksXML(xmlReader,client);
            }
            else if(xmlReader.name() == "ClientMessage")
            {//Сообщение от клиента

                clientMessage(xmlReader,client);
            }
            else if(xmlReader.name() == "ClientNotify")
            {//Уведомление от клиента

                clientNotify(xmlReader,client);
            }
            else if(xmlReader.name() == "DataInfo")
            {
                  clientDataInfo(xmlReader,client);
            }
            else if(xmlReader.name() == "ListTasksAMM")
            {
                if(client->getClient()->getClientType() == TypeClientAutorization::TYPE_UNITY_CLIENT)
                {//Отчет по задаче АММ от Юнити-клиента
                    clientUnityTaskAMMreport(xmlReader,client, array);
                }
            }
            else if(xmlReader.name() == "ListTasksFIM")
            {
                if(client->getClient()->getClientType() == TypeClientAutorization::TYPE_UNITY_CLIENT)
                {//Отчет по задаче FIM от Юнити-клиента
                    clientUnityTaskFIMreport(xmlReader,client, array);
                }
            }
            else
            {
                emit sigLogMessage("XmlParser: unrecognized tag");
            }

        }
        xmlReader.readNext(); // Переходим к следующему элементу файла
    }//while(!xmlReader.atEnd())
}

void ProcessParser::clientDataInfo(QXmlStreamReader &xmlReader,ClientHandler *client)
{
    DataInfo *dataInfo = new DataInfo;

    foreach(const QXmlStreamAttribute &attr, xmlReader.attributes())
    {
        QString name = attr.name().toString();
        QString value = attr.value().toString();

        if(name == "path")
            dataInfo->path= value.toUtf8();

        if(name == "size")
            dataInfo->size = value.toLong();
    }

    processingSystem->setCurrentDataInfo(dataInfo);

}

void ProcessParser::clientUnityTaskAMMreport(QXmlStreamReader &xmlReader, ClientHandler *client, QByteArray array)
{
    QDomDocument commonDOM;
    commonDOM.setContent(array);

    QList<TaskAmmFim> listTasks;
    int trainee_id = 0;
    QDomNode listNode = commonDOM.namedItem("ListTasksAMM");
    trainee_id = listNode.toElement().attribute("trainee_id").toInt();

    for(int i = 0; i < listNode.childNodes().count(); i++)
    {
        QDomNode taskNode = listNode.childNodes().at(i);
        if(taskNode.nodeName() == "taskAMM")
        {//Задача
            TaskAmmFim task;
            task.setID(taskNode.toElement().attribute("task_id").toInt());
            task.ammProcedure.title = taskNode.toElement().attribute("title");
            task.ammProcedure.dmCode = taskNode.toElement().attribute("dmCode");
            task.status = taskNode.toElement().attribute("status");

            listTasks.append(task);

            //Изменение задачи
            void* data = nullptr;
            data = &task;
            ClientQueryToDB queryToDB;
            queryToDB.typeQuery = TypeQueryToDB::TYPE_QUERY_SET_REPORT_TASK_AMM_TO_TRAINEE;
            processingSystem->processingClientQueryToDB(client, queryToDB, trainee_id, data);
        }
    }

    emit processingSystem->sigStatusTasksAMMofTraineeChanged(trainee_id);
}

void ProcessParser::clientUnityTaskFIMreport(QXmlStreamReader &xmlReader, ClientHandler *client, QByteArray array)
{
    QDomDocument commonDOM;
    commonDOM.setContent(array);

    QList<TaskAmmFim> listTasks;
    int trainee_id = 0;
    QDomNode listNode = commonDOM.namedItem("ListTasksFIM");
    trainee_id = listNode.toElement().attribute("trainee_id").toInt();

    for(int i = 0; i < listNode.childNodes().count(); i++)
    {//Задачи
        QDomNode taskNode = listNode.childNodes().at(i);
        if(taskNode.nodeName() == "taskFIM")
        {
            TaskAmmFim task;
            task.setID(taskNode.toElement().attribute("task_id").toInt());
            task.title = taskNode.toElement().attribute("title");
            task.status = taskNode.toElement().attribute("status");


            for(int j = 0; j < taskNode.childNodes().count(); j++)
            {//Неисправности
                QDomNode malfOrReportNode = taskNode.childNodes().at(j);
                if(malfOrReportNode.nodeName() == "malfunction")
                {
                    /*
                    Malfunction malfunction;
                    malfunction.num = malfunctionNode.toElement().attribute("num");
                    malfunction.dmCode = malfunctionNode.toElement().attribute("dmCode");
                    malfunction.description = malfunctionNode.toElement().attribute("description");

                    task.malfunctionList.append(malfunction);
                    */
                }
                else
                    if(malfOrReportNode.nodeName() == "report")
                    {//Отчет
                        FIMReport report;
                        report.id = 0; //malfOrReportNode.toElement().attribute("report_id").toInt();

                        for(int k = 0; k < malfOrReportNode.childNodes().count(); k++)
                        {
                            QDomNode reportItemNode = malfOrReportNode.childNodes().at(k);
                            if(reportItemNode.nodeName() == "item")
                            {
                                FIMReportItem reportItem;
                                reportItem.id = 0; //reportItemNode.toElement().attribute("item_id").toInt();
                                reportItem.text = reportItemNode.toElement().attribute("title");

                                if(reportItemNode.childNodes().count())
                                {
                                    QDomNode procedureIDNode = reportItemNode.childNodes().at(0);
                                    reportItem.procedure.doc = procedureIDNode.toElement().attribute("doc");
                                    reportItem.procedure.title = procedureIDNode.toElement().attribute("title");
                                    reportItem.procedure.dmCode = procedureIDNode.toElement().attribute("dmCode");
                                    reportItem.procedure.result = procedureIDNode.toElement().attribute("result");
                                }

                                report.itemList.append(reportItem);
                            }
                        }

                        task.report = report;
                    }
            }
            /*

            //TODO -------------- (!Заглушка!) Отчет о выполнении
            FIMReport report;
            FIMReportItem reportItem;
            QString text;             // текст, вводимый обучаемым
            ProcedureID procedure;   // ссылка на процедуру, при необходимости

            text = "1. Выполнил такую процедуру";
            procedure.doc = "fim";
            procedure.title = "Процедура №1";
            procedure.dmCode = "RRJ-N-27-92-00-51D01-420A-A";
            procedure.result = "viewed";
            reportItem.text = text;
            reportItem.procedure = procedure;
            report.itemList.append(reportItem);

            text = "2. Выполнил такую процедуру";
            procedure.doc = "fim";
            procedure.title = "Процедура №2";
            procedure.dmCode = "RRJ-N-28-22-00-01A01-420A-A";
            procedure.result = "viewed";
            reportItem.text = text;
            reportItem.procedure = procedure;
            report.itemList.append(reportItem);

            task.report = report;
            //-----------------
            */


            listTasks.append(task);

            //Изменение задачи
            void* data = nullptr;
            data = &task;
            ClientQueryToDB queryToDB;
            queryToDB.typeQuery = TypeQueryToDB::TYPE_QUERY_SET_REPORT_TASK_FIM_TO_TRAINEE;
            processingSystem->processingClientQueryToDB(client, queryToDB, trainee_id, data);
        }
    }

    emit processingSystem->sigStatusTasksFIMofTraineeChanged(trainee_id);
}

TaskAmmFim ProcessParser::xmlParserQueryToDB_ASSIGN_TASK_FIM_TO_TRAINEE(QByteArray array)
{
    TaskAmmFim task;

    QDomDocument commonDOM;
    commonDOM.setContent(array);

    QDomNode mainNode = commonDOM.namedItem("QueryToDB");

    task.title = mainNode.toElement().attribute("title");

    for(int i = 0; i < mainNode.childNodes().count(); i++)
    {
        QDomNode malfunctionNode = mainNode.childNodes().at(i);
        if(malfunctionNode.nodeName() == "malfunction")
        {//Неисправность
            Malfunction malfunction;

            malfunction.num = malfunctionNode.toElement().attribute("num");
            malfunction.dmCode = malfunctionNode.toElement().attribute("dmCode");
            malfunction.description = malfunctionNode.toElement().attribute("description");

            //Сигналы
            for(int j = 0; j < malfunctionNode.childNodes().count(); j++)
            {
                QDomNode signNode = malfunctionNode.childNodes().at(j);
                if(signNode.nodeName() == "malfunctionSign")
                {
                    MalfunctionSign sign;

                    sign.type = signNode.toElement().attribute("type").toInt();
                    sign.description = signNode.toElement().attribute("description");

                    malfunction.malfunctionSigns.append(sign);
                }
            }

            task.malfunctionList.append(malfunction);
        }
    }

    return task;
}

void ProcessParser::clientAuth(QXmlStreamReader &xmlReader,ClientHandler *client)
{
    ClientAutorization clientAutorization;

    /*Перебираем все атрибуты тега*/
    foreach(const QXmlStreamAttribute &attr, xmlReader.attributes())
    {
        QString name = attr.name().toString();
        QString value = attr.value().toString();
        //addTextToLogger(name + ": " + value);

        if(name == "Login")
            clientAutorization.Login = value;
        else if(name == "Password")
            clientAutorization.Password = value;
        else if(name == "NumberOfScreen")
            clientAutorization.NumberOfScreen = value.toInt();
        else if(name == "TypeClient")
            clientAutorization.TypeClient = (TypeClientAutorization)value.toInt();
    }

    processingSystem->processingClientAutorization(client, clientAutorization);
}

void ProcessParser::clientDeAuth(QXmlStreamReader &xmlReader,ClientHandler *client)
{
    ClientDeAutorization clientDeAutorization;

    /*Перебираем все атрибуты тега*/
    foreach(const QXmlStreamAttribute &attr, xmlReader.attributes())
    {
        QString name = attr.name().toString();
        QString value = attr.value().toString();
        //addTextToLogger(name + ": " + value);

        if(name == "Login")
            clientDeAutorization.Login = value;
    }

    processingSystem->processingClientDeAutorization(client, clientDeAutorization);
}

void ProcessParser::queryToDb(QXmlStreamReader &xmlReader,ClientHandler *client, QByteArray array)
{
    ClientQueryToDB queryToDB;
    int id = 0;
    Instructor instructor;
    Trainee trainee;
    Group group;
    TaskAmmFim task;
    QString status = "";
    void* data = nullptr;

    /*Перебираем все атрибуты тега*/
    foreach(const QXmlStreamAttribute &attr, xmlReader.attributes())
    {
        QString name = attr.name().toString();
        QString value = attr.value().toString();
        //addTextToLogger(name + ": " + value);

        if(name == "TypeQuery")
        {
            queryToDB.typeQuery = (TypeQueryToDB)value.toInt();
            if(queryToDB.typeQuery == TypeQueryToDB::TYPE_QUERY_ASSIGN_TASK_FIM_TO_TRAINEE)
            {
                task = xmlParserQueryToDB_ASSIGN_TASK_FIM_TO_TRAINEE(array);
            }
        }
        else if(name == "id")
            id = value.toInt();
        else
        {
            switch (queryToDB.typeQuery)
            {
            case TypeQueryToDB::TYPE_QUERY_NEW_INSTRUCTOR:
            case TypeQueryToDB::TYPE_QUERY_EDIT_INSTRUCTOR:
                if(name == "instructor_id")
                    instructor.setID(value.toInt());
                else if(name == "name")
                    instructor.setName(value);
                else if(name == "login")
                    instructor.setLogin(value);
                else if(name == "password")
                    instructor.setPassword(value);
                else if(name == "is_admin")
                    instructor.setIsAdmin(value.toInt());
                else if(name == "archived")
                    instructor.setArchived(value.toInt());
                else if(name == "logged_in")
                    instructor.setLoggedIn(value.toInt());
                break;
            case TypeQueryToDB::TYPE_QUERY_NEW_TRAINEE:
            case TypeQueryToDB::TYPE_QUERY_EDIT_TRAINEE:
                if(name == "trainee_id")
                    trainee.setID(value.toInt());
                else if(name == "name")
                    trainee.setName(value);
                else if(name == "login")
                    trainee.setLogin(value);
                else if(name == "password")
                    trainee.setPassword(value);
                else if(name == "archived")
                    trainee.setArchived(value.toInt());
                else if(name == "logged_in")
                    trainee.setLoggedIn(value.toInt());
                else if(name == "group_trainee")
                {
                    Group group(value.toInt(), "");
                    trainee.setGroup(group);
                }
                else if(name == "computer_trainee")
                {
                    Computer computer(value.toInt(), "", "", Classroom());
                    trainee.setComputer(computer);
                }
                break;
            case TypeQueryToDB::TYPE_QUERY_NEW_GROUP:
            case TypeQueryToDB::TYPE_QUERY_EDIT_GROUP:
                if(name == "group_id")
                    group.setID(value.toInt());
                else if(name == "name")
                    group.setName(value);
                break;

            case TypeQueryToDB::TYPE_QUERY_ASSIGN_TASK_AMM_TO_TRAINEE:
                if(name == "title")
                    task.ammProcedure.title = value;
                else if(name == "dmCode")
                    task.ammProcedure.dmCode = value;
                break;
            case TypeQueryToDB::TYPE_QUERY_ASSIGN_TASK_FIM_TO_TRAINEE:
                //if(name == "title")
                    //task.title = value;
                break;

            case TypeQueryToDB::TYPE_QUERY_CHANGE_STATUS_REPORT_TASK_AMM_TO_TRAINEE:
            case TypeQueryToDB::TYPE_QUERY_CHANGE_STATUS_REPORT_TASK_FIM_TO_TRAINEE:
                if(name == "status")
                    status = value;
                break;
            };
        }
    }

    switch (queryToDB.typeQuery)
    {
    case TypeQueryToDB::TYPE_QUERY_NEW_INSTRUCTOR:
    case TypeQueryToDB::TYPE_QUERY_EDIT_INSTRUCTOR:
        data = &instructor;
        break;
    case TypeQueryToDB::TYPE_QUERY_NEW_TRAINEE:
    case TypeQueryToDB::TYPE_QUERY_EDIT_TRAINEE:
        data = &trainee;
        break;
    case TypeQueryToDB::TYPE_QUERY_NEW_GROUP:
    case TypeQueryToDB::TYPE_QUERY_EDIT_GROUP:
        data = &group;
        break;
    case TypeQueryToDB::TYPE_QUERY_ASSIGN_TASK_AMM_TO_TRAINEE:
    case TypeQueryToDB::TYPE_QUERY_ASSIGN_TASK_FIM_TO_TRAINEE:
        data = &task;
        break;
    case TypeQueryToDB::TYPE_QUERY_CHANGE_STATUS_REPORT_TASK_AMM_TO_TRAINEE:
    case TypeQueryToDB::TYPE_QUERY_CHANGE_STATUS_REPORT_TASK_FIM_TO_TRAINEE:
        data = &status;
        break;
    };

    processingSystem->processingClientQueryToDB(client, queryToDB, id, data);
}

void ProcessParser::queryTasksXML(QXmlStreamReader &xmlReader, ClientHandler *client)
{
    ClientQueryTasksXML clientQueryTasksXML;

    /*Перебираем все атрибуты тега*/
    foreach(const QXmlStreamAttribute &attr, xmlReader.attributes())
    {
        QString name = attr.name().toString();
        QString value = attr.value().toString();
        //addTextToLogger(name + ": " + value);

        if(name == "Type")
            clientQueryTasksXML.Type = value;
    }

    processingSystem->processingClientQueryTasksXML(client, clientQueryTasksXML);
}

void ProcessParser::clientMessage(QXmlStreamReader &xmlReader,ClientHandler *client)
{
    ClientMessage clientMessage;

    /*Перебираем все атрибуты тега*/
    foreach(const QXmlStreamAttribute &attr, xmlReader.attributes())
    {
        QString name = attr.name().toString();
        QString value = attr.value().toString();
        //addTextToLogger(name + ": " + value);

        if (name == "Text")
            clientMessage.Text = value;
        if (name == "From")
            clientMessage.From = value;
        if (name == "To")
            clientMessage.To = value;
    }

    processingSystem->processingSendMessage(clientMessage);

}

void ProcessParser::clientNotify(QXmlStreamReader &xmlReader,ClientHandler *client)
{
    ClientNotify clientNotify;

    /*Перебираем все атрибуты тега*/
    foreach(const QXmlStreamAttribute &attr, xmlReader.attributes())
    {
        QString name = attr.name().toString();
        QString value = attr.value().toString();

        if(name == "Code")
            clientNotify.Code = value;
    }

    processingSystem->processingClientNotify(client, clientNotify);
}


