#include "processingsystem.h"

#include <clienthandler.h>

ProcessingSystem::ProcessingSystem(ProviderDBLMS* providerDBLMS, UpdateController* updateController, QObject *parent):
    QObject(parent),
    providerDBLMS(nullptr),
    updateController(nullptr)
{
    this->providerDBLMS = providerDBLMS;
    this->updateController = updateController;
}

void ProcessingSystem::initialize(ServerLMSWidget *server,
                                  DataParser *dataParser,
                                  CommonClientHandler *commonClientHandler,
                                  Logger *logger,
                                  UpdateController *updateController)
{
    this->commonClientServer = commonClientHandler;
    this->dataParser = dataParser;
    this->server = server;
    this->updateController = updateController;

    connect(this,&ProcessingSystem::sigAuthChanged,commonClientHandler, &CommonClientHandler::slot_AuthChanged,Qt::AutoConnection);
    connect(this,&ProcessingSystem::sigUpdateListClients,server, &ServerLMSWidget::slotUpdateListClients,Qt::AutoConnection);
    connect(this,&ProcessingSystem::sigSetData,updateController,&UpdateController::setDataInfo,Qt::AutoConnection);
    connect(this,&ProcessingSystem::signal_msgToClientReady,commonClientHandler, &CommonClientHandler::slot_msgToClientFromGUI);
    connect(this,&ProcessingSystem::signal_msgFromClientReady,commonClientHandler, &CommonClientHandler::slot_msgToGUIfromClient);
    connect(this,&ProcessingSystem::sigLogMessage,logger,&Logger::addTextToLogger,Qt::QueuedConnection);
}

void ProcessingSystem::processingClientAutorization(ClientHandler *client, ClientAutorization clientAutorization)
{
    if(server->getStateBlockAutorization() == blocked)
    {
        QByteArray arrayAnswer = dataParser->ClientAnswer()->notify(NOTIFY_SERVER_BLOCKED);
        client->sendXmlAnswer(arrayAnswer);

        QString str = QString(arrayAnswer);
        emit sigLogMessage("To Client: " + str);

        return;
    }

    //Попытка авторизации клиента (проверка по БД)
    QString instructorName;
    QString traineeName;
    QByteArray arrayAnswer;

    if(providerDBLMS->authorizationTrainee(clientAutorization.Login, clientAutorization.Password, "", ""))
    {//Авторизуется обучаемый

        client->getClient()->setLogin(clientAutorization.Login);
        emit sigUpdateListClients();

        //KAV redact
        instructorName = providerDBLMS->getMainInstructorName();
        traineeName = providerDBLMS->getNameTraineeByLogin(clientAutorization.Login);

        arrayAnswer = dataParser->ClientAnswer()->authorization(true, instructorName, traineeName, "trainee", clientAutorization.Login);
    }
    else if(providerDBLMS->authorizationInstructor(clientAutorization.Login, clientAutorization.Password))
    {//Авторизуется инструктор

        client->getClient()->setLogin(clientAutorization.Login);
        client->getClient()->setTypeClient(clientAutorization.TypeClient);
        emit sigUpdateListClients();

        instructorName = providerDBLMS->getNameInstructorByLogin(clientAutorization.Login);

        arrayAnswer = dataParser->ClientAnswer()->authorization(true, instructorName, instructorName, "instructor", clientAutorization.Login);
    }
    else
    {//Никто не авторизовался
        arrayAnswer = dataParser->ClientAnswer()->authorization(false, "", "", "", "");
    }
    client->sendXmlAnswer(arrayAnswer);
    client->sendVersion();

    QString str = QString(arrayAnswer);
    //logger->addTextToLogger("To Client: " + str);

    //Извещаем об изменениях в авторизации
    emit sigAuthChanged();
}

void ProcessingSystem::processingClientDeAutorization(ClientHandler *client, ClientDeAutorization clientDeAutorization)
{
    if(server->getStateBlockAutorization() == blocked)
    {
        QByteArray arrayAnswer = dataParser->ClientAnswer()->notify(NOTIFY_SERVER_BLOCKED);
        client->sendXmlAnswer(arrayAnswer);

        QString str = QString(arrayAnswer);
        emit sigLogMessage("To Client: " + str);

        return;
    }

    //Попытка ДеАвторизации клиента (проверка по БД)
    QByteArray arrayAnswer;

    if(providerDBLMS->deAuthorizationTrainee(clientDeAutorization.Login))
    {//ДеАвторизуется обучаемый

        client->getClient()->setLogin("");
        emit sigUpdateListClients();

        arrayAnswer = dataParser->ClientAnswer()->deAuthorization(true, clientDeAutorization.Login);
    }
    else if(providerDBLMS->deAuthorizationInstructor(clientDeAutorization.Login))
    {//ДеАвторизуется инструктор

        client->getClient()->setLogin("");
        emit sigUpdateListClients();

        arrayAnswer = dataParser->ClientAnswer()->deAuthorization(true, clientDeAutorization.Login);
    }
    else
    {//Никто не ДеАвторизовался
        arrayAnswer = dataParser->ClientAnswer()->deAuthorization(false, "");
    }
    client->sendXmlAnswer(arrayAnswer);

    QString str = QString(arrayAnswer);
    //logger->addTextToLogger("To Client: " + str);

    //Извещаем об изменениях в авторизации
    emit sigAuthChanged();
}

void ProcessingSystem::processingClientQueryToDB(ClientHandler *client, ClientQueryToDB clientQueryToDB, int id, void* data)
{
    QByteArray arrayAnswer;

    qDebug() << "ProcessingQueryThread " << QThread::currentThreadId();
    switch (clientQueryToDB.typeQuery)
    {
        case TypeQueryToDB::TYPE_QUERY_GET_ALL_LISTS:
        {
            QList<Instructor> listInstructors = providerDBLMS->GetListAllInstructors();
            QList<Trainee> listTrainees = providerDBLMS->GetListAllTrainees();
            QList<Group> listGroups = providerDBLMS->GetListAllGroups();

            arrayAnswer = dataParser->DbAnswer()->listInstructors(true, &listInstructors);
            client->sendXmlAnswer(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_DB__LIST_INSTRUCTORS);

            arrayAnswer = dataParser->DbAnswer()->listGroups(true, &listGroups);
            client->sendXmlAnswer(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_DB__LIST_GROUPS);

            arrayAnswer = dataParser->DbAnswer()->listTrainees(true, &listTrainees);
            client->sendXmlAnswer(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_DB__LIST_TRAINEES);
            break;
        }
        case TypeQueryToDB::TYPE_QUERY_NEW_INSTRUCTOR:
        {
            int id_new;
            id_new = providerDBLMS->newInstructor();
            if(id_new)
            {
                (*(Instructor*)data).setID(id_new);
                providerDBLMS->editInstructor(*(Instructor*)data);
            }
            emit sigAuthChanged();
            break;
        }
        case TypeQueryToDB::TYPE_QUERY_DEL_INSTRUCTOR:
        {
            providerDBLMS->delInstructor(id);
            emit sigAuthChanged();
            break;
        }
        case TypeQueryToDB::TYPE_QUERY_EDIT_INSTRUCTOR:
        {
            providerDBLMS->editInstructor(*(Instructor*)data);
            emit sigAuthChanged();
            break;
        }

        case TypeQueryToDB::TYPE_QUERY_NEW_TRAINEE:
        {
            int id_new;
            id_new = providerDBLMS->newTrainee(id);
            if(id_new)
            {
                (*(Trainee*)data).setID(id_new);
                providerDBLMS->editTrainee(*(Trainee*)data);
            }
            emit sigAuthChanged();
            break;
        }
        case TypeQueryToDB::TYPE_QUERY_DEL_TRAINEE:
        {
            providerDBLMS->delTrainee(id);
            emit sigAuthChanged();
            break;
        }
        case TypeQueryToDB::TYPE_QUERY_EDIT_TRAINEE:
        {
            providerDBLMS->editTrainee(*(Trainee*)data);
            emit sigAuthChanged();
            break;
        }

        case TypeQueryToDB::TYPE_QUERY_NEW_GROUP:
        {
            int id_new;
            id_new = providerDBLMS->newGroup();
            if(id_new)
            {
                (*(Group*)data).setID(id_new);
                providerDBLMS->editGroup(*(Group*)data);
            }
            emit sigAuthChanged();
            break;
        }
        case TypeQueryToDB::TYPE_QUERY_DEL_GROUP:
        {
            providerDBLMS->delGroup(id);
            emit sigAuthChanged();
            break;
        }
        case TypeQueryToDB::TYPE_QUERY_EDIT_GROUP:
        {
            providerDBLMS->editGroup(*(Group*)data);
            emit sigAuthChanged();
            break;
        }

        case TypeQueryToDB::TYPE_QUERY_ASSIGN_TASK_AMM_TO_TRAINEE:
        {
            int id_new;
            id_new = providerDBLMS->newTaskAMM(id);
            if(id_new)
            {
                (*(TaskAmmFim*)data).setID(id_new);
                providerDBLMS->editTaskAMM(*(TaskAmmFim*)data);
            }
            //emit sigTasksChanged();
            break;
        }

        case TypeQueryToDB::TYPE_QUERY_ASSIGN_TASK_FIM_TO_TRAINEE:
        {
            int id_new;
            id_new = providerDBLMS->newTaskFIM(id);
            if(id_new)
            {
                (*(TaskAmmFim*)data).setID(id_new);
                providerDBLMS->editTaskFIM(*(TaskAmmFim*)data);
            }
            //emit sigTasksChanged();
            break;
        }
    }

    //client->sendXmlAnswer(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_DB_LIST_INSTRUCTORS);

    //QString str = QString(arrayAnswer);
    //logger->addTextToLogger("To Client: " + str);
}

void ProcessingSystem::processingClientQueryTasksXML(ClientHandler *client, ClientQueryTasksXML clientQueryTasksXML)
{
    QByteArray arrayAnswer;

    QString nameFile = "";
    QString pathFile = "";
    if(clientQueryTasksXML.Type == "fim")
    {
        nameFile = tasksFIMfileName;
        pathFile = updateController->getPathAdditionalFile(nameFile);
        client->sendFileBlock(pathFile);
        client->sendPacketType(PacketType::TYPE_XMLANSWER_QUERY_TASKS_XML_FIM);
    }
    else if(clientQueryTasksXML.Type == "amm")
    {
        nameFile = tasksAMMfileName;
        pathFile = updateController->getPathAdditionalFile(nameFile);
        client->sendFileBlock(pathFile);
        client->sendPacketType(PacketType::TYPE_XMLANSWER_QUERY_TASKS_XML_AMM);
    }
}

void ProcessingSystem::processingToClientMessage(ClientHandler *client, ToClientMessage toClientMessage)
{
    signal_msgToClientReady(toClientMessage.Login, toClientMessage.Text);
}

void ProcessingSystem::processingFromClientMessage(ClientHandler *client, ClientMessage clientMessage)
{
    /*
    QString peerAddress = client->getSocket()->peerAddress().toString();
    QString peerPort = QString::number(client->getSocket()->peerPort());

    QString str = "Msg From Client [" + peerAddress + ":" + peerPort + "] : " + clientMessage.Text;

    emit sigLogMessage(str);
    */

    signal_msgFromClientReady(client->getClient()->getLogin(), clientMessage.Text);
}

void ProcessingSystem::processingClientNotify(ClientHandler *client, ClientNotify clientNotify)
{
    if(clientNotify.Code == commandReadyClient)
    {//Клиент готов принять задания
        client->getClient()->setReady(true);    //скорее всего функции будут внутри хэндлера

        //Отправляем пакет с заданиями для Обучаемого(клиента)

        client->getSocket()->flush();

        QStringList listTasks;
        //TODO KAV redact
        //listTasks = pInstructorsAndTrainees->getDbLMS()->getWhatItDoes(client->getClient()->getLogin());

        QByteArray arrayAnswer = dataParser->ClientAnswer()->tasks(listTasks);
        client->sendXmlAnswer(arrayAnswer);

        QString str = QString(arrayAnswer);
        emit sigLogMessage("To Client: " + str);
    }
    else if(clientNotify.Code == commandDisableClient)
    {
        qDebug() << "processing thread: " << QThread::currentThreadId();
        client->sendDisable();
    }
    else if(clientNotify.Code == commandGetServerDataList)
    {
        client->sendHash();
    }
    else if(clientNotify.Code == commandCheckVersionList)
    {
        client->sendVersionList();
    }
    else if(clientNotify.Code == commandCanChangeVersion)
    {
        if (updateController->getCurrentVersion()->getIsChangeable())
        {
            client->sigSendNotify(commandChangable);
        }
        else
        {
            client->sigSendNotify(commandUnchangable);
        }

    }
}

void ProcessingSystem::setCurrentDataInfo(DataInfo *dataInfo)
{
    emit sigSetData(dataInfo);
}



