#include "connectortoserver.h"
#include <QThread>

ConnectorToServer::ConnectorToServer(QWidget* parentWidget, QObject *parent) :
    QObject(parent),
    parentWidget(parentWidget),
    connectionThread(nullptr),
    client(nullptr),
    dataParser(nullptr),
    sendSystem(nullptr),
    recognizeSystem(nullptr),
    versionSelectWidget(nullptr),
    versionContainer(nullptr),
    notifyController(nullptr),
    isLoggedIn(false),
    fl_GetedOfflineMessages(false)
{
    initialize();
}

ConnectorToServer::~ConnectorToServer()
{
    delete client;
    delete versionSelectWidget;
    delete notifyController;
    delete versionContainer;
    delete recognizeSystem;
    delete sendSystem;
    delete dataParser;

    connectionThread->quit();
    connectionThread->wait();
    delete connectionThread;
}

bool ConnectorToServer::authorizationInstructorLocal(QString login, QString password)
{
    if (!client->getIsConnected())
    {
        return false;
    }

    ClientAutorization *autorization = new ClientAutorization;
    autorization->Login = login;
    autorization->Password = password;
    autorization->TypeClient = TypeClientAutorization::TYPE_GUI;
    isLoggedIn = true;

    QByteArray array = dataParser->createAuthMessage(autorization);
    emit signal_sendXMLmsgGUItoServer(array);

    return true;
}

bool ConnectorToServer::deAuthorizationInstructorLocal(QString login)
{
    if (!client->getIsConnected())
    {
        return false;
    }

    ClientDeAutorization *deAutorization = new ClientDeAutorization;
    deAutorization->Login = login;
    isLoggedIn = false;

    QByteArray array = dataParser->createDeAuthMessage(deAutorization);
    emit signal_sendXMLmsgGUItoServer(array);

    return true;
}

bool ConnectorToServer::sendQueryToDB(TypeQueryToDB typeQuery, int id, void* data)
{
    if (!client->getIsConnected())
    {
        return false;
    }

    ClientQueryToDB *queryToDB = new ClientQueryToDB;
    queryToDB->typeQuery = typeQuery;

    QByteArray array = dataParser->createQueryToDBMessage(queryToDB, id, data);
    emit signal_sendXMLmsgGUItoServer(array);

    return true;
}

bool ConnectorToServer::sendMessage(ClientMessage clientMessage)
{
    if (!client->getIsConnected())
    {
        return false;
    }
    QByteArray array = dataParser->createMessage(clientMessage);
    emit signal_sendXMLmsgGUItoServer(array);

    return true;
}

bool ConnectorToServer::sendClientNotify(QString command)
{
    QByteArray answer = dataParser->xmlAnswer_notify(command);
    emit sigSendAnswerToServer(answer);
    return true;
}
bool ConnectorToServer::sendQueryTasksXML(QString type)
{
    if (!client->getIsConnected())
    {
        return false;
    }

    QByteArray array = dataParser->createQueryTasksXMLMessage(type);
    emit signal_sendXMLmsgGUItoServer(array);

    return true;
}

void ConnectorToServer::setLoginName(QString name)
{
    versionSelectWidget->setAuthor(name);
}

ServerSettings ConnectorToServer::getServerSettings()
{
    return  serverSettings;
}

bool ConnectorToServer::getIsConnected()
{
    return client->getIsConnected();
}

void ConnectorToServer::SetConnectToServer()
{
    serverSettings = *dataParser->getServerSettings();
    emit sigSetConnect(dataParser->getServerSettings(),connectionThread);
}

void ConnectorToServer::StopConnectToServer()
{
    emit sigStopConnect();
    clearListModelDB();
}

QByteArray ConnectorToServer::getListTaskFimArray()
{
    return listTaskFimArray;
}

QByteArray ConnectorToServer::getListTaskAmmArray()
{
    return listTaskAmmArray;
}

QList<Instructor> ConnectorToServer::getListInstructors()
{
    return listInstructors;
}

QList<Trainee> ConnectorToServer::getListTrainees()
{
    return listTrainees;
}

QList<Group> ConnectorToServer::getListGroups()
{
    return listGroups;
}

QList<Computer> ConnectorToServer::getListComputers()
{
    return  listComputers;
}

QList<Classroom> ConnectorToServer::getListClassrooms()
{
    return listClassrooms;
}

QList<TaskAmmFim> ConnectorToServer::getListTasksAMMforTrainee(int trainee_id)
{
    if(mapTasksAMM.contains(trainee_id))
        return mapTasksAMM.value(trainee_id);
    else
        return QList<TaskAmmFim>();
}

QList<TaskAmmFim> ConnectorToServer::getListTasksFIMforTrainee(int trainee_id)
{
    if(mapTasksFIM.contains(trainee_id))
        return mapTasksFIM.value(trainee_id);
    else
        return QList<TaskAmmFim>();
}

int ConnectorToServer::getCountTasksAMMforTrainee(int trainee_id)
{
    if(mapTasksAMM.contains(trainee_id))
        return mapTasksAMM.value(trainee_id).count();
    else
        return 0;
}

int ConnectorToServer::getCountTasksFIMforTrainee(int trainee_id)
{
    if(mapTasksFIM.contains(trainee_id))
        return mapTasksFIM.value(trainee_id).count();
    else
        return 0;
}

bool ConnectorToServer::isArchivedInstructor(int id)
{
    for(Instructor instructor : listInstructors)
    {
        if(instructor.getID() == id)
        {
            if(instructor.getArchived()) return true; else return false;
        }
    }
    return false;
}

bool ConnectorToServer::isAdminInstructor(int id)
{
    for(Instructor instructor : listInstructors)
    {
        if(instructor.getID() == id)
        {
            if(instructor.getIsAdmin()) return true; else return false;
        }
    }
    return false;
}

bool ConnectorToServer::isLoggedInInstructor(int id)
{
    for(Instructor instructor : listInstructors)
    {
        if(instructor.getID() == id)
        {
            if(instructor.getLoggedIn()) return true; else return false;
        }
    }
    return false;
}

Instructor ConnectorToServer::getInstructor(int id)
{
    for(Instructor instructor : listInstructors)
    {
        if(instructor.getID() == id)
            return instructor;
    }
    return Instructor();
}

QList<Trainee> ConnectorToServer::getListTraineesInGroup(int id)
{
    QList<Trainee> list;
    for(Trainee trainee : listTrainees)
    {
        if(trainee.getGroup().getID() == id)
            list.append(trainee);
    }
    return list;
}

bool ConnectorToServer::isArchivedTrainee(int id)
{
    for(Trainee trainee : listTrainees)
    {
        if(trainee.getID() == id)
        {
            if(trainee.getArchived()) return true; else return false;
        }
    }
    return false;
}

bool ConnectorToServer::isLoggedInTrainee(int id)
{
    for(Trainee trainee : listTrainees)
    {
        if(trainee.getID() == id)
        {
            if(trainee.getLoggedIn()) return true; else return false;
        }
    }
    return false;
}

Trainee ConnectorToServer::getTrainee(int id)
{
    for(Trainee trainee : listTrainees)
    {
        if(trainee.getID() == id)
            return trainee;
    }
    return Trainee();
}

Group ConnectorToServer::getGroup(int id)
{
    for(Group group : listGroups)
    {
        if(group.getID() == id)
            return group;
    }
    return Group();
}

int ConnectorToServer::getIdTraineeByLogin(QString login)
{
    for(Trainee trainee : listTrainees)
    {
        if(trainee.getLogin() == login)
            return trainee.getID();
    }
    return 0;
}

int ConnectorToServer::getIdInstructorByLogin(QString login)
{
    for(Instructor instructor : listInstructors)
    {
        if(instructor.getLogin() == login)
            return instructor.getID();
    }
    return 0;
}

void ConnectorToServer::showVersionSelect()
{
    QByteArray answer = dataParser->xmlAnswer_notify(cmd_CheckVersionList);
    emit sigSendAnswerToServer(answer);
}

void ConnectorToServer::slot_AnswerQueryToDB_ListInstructors(QList<Instructor> listInstructors)
{
    this->listInstructors = listInstructors;
    emit signal_UpdateDB(true, false);

    QList<User> listUsers;
    for(Instructor instructor : listInstructors)
    {
        listUsers.append(instructor);
    }
    emit signal_reInitMessangerByUsers(listUsers);
}

void ConnectorToServer::slot_AnswerQueryToDB_ListGroups(QList<Group> listGroups)
{
    this->listGroups = listGroups;
    emit signal_UpdateDB(false, true);
}

void ConnectorToServer::slot_AnswerQueryToDB_ListTrainees(QList<Trainee> listTrainees)
{
    this->listTrainees = listTrainees;
    emit signal_UpdateDB(false, true);

    QList<User> listUsers;
    for(Trainee trainee : listTrainees)
    {
        listUsers.append(trainee);
    }
    emit signal_reInitMessangerByUsers(listUsers);

    if (isLoggedIn)
    {
        sendClientNotify(cmd_GetOfflineMessages);
    }
}

void ConnectorToServer::slot_AnswerQueryToDB_ListComputers(QList<Computer> listComputers)
{
    this->listComputers = listComputers;
    //emit signal_UpdateDB(false, true); //TODO
}

void ConnectorToServer::slot_AnswerQueryToDB_ListClassrooms(QList<Classroom> listClassrooms)
{
    this->listClassrooms = listClassrooms;
    //emit signal_UpdateDB(false, true); //TODO
}

void ConnectorToServer::slot_AnswerQueryToDB_ListTasksAMMforTrainee(QList<TaskAmmFim> listTasks, int trainee_id)
{
    //Удаляем старые задачи этого обучаемого
    mapTasksAMM.remove(trainee_id);

    //Добавляем новые
    mapTasksAMM.insert(trainee_id, listTasks);

    emit signal_UpdateTasksAMMforTrainee(trainee_id);
}

void ConnectorToServer::slot_AnswerQueryToDB_ListTasksFIMforTrainee(QList<TaskAmmFim> listTasks, int trainee_id)
{
    //Удаляем старые задачи этого обучаемого
    mapTasksFIM.remove(trainee_id);

    //Добавляем новые
    mapTasksFIM.insert(trainee_id, listTasks);

    emit signal_UpdateTasksFIMforTrainee(trainee_id);
}

void ConnectorToServer::slot_AnswerQueryTasksXML_FIM(QByteArray array)
{
    this->listTaskFimArray = array;
    emit signal_UpdateTasksFIM();
}

void ConnectorToServer::slot_AnswerQueryTasksXML_AMM(QByteArray array)
{
    this->listTaskAmmArray = array;
    emit signal_UpdateTasksAMM();

    //Запрос старых оффлайн-сообщений
    if(!fl_GetedOfflineMessages)
    {
        sendClientNotify(cmd_GetOfflineMessages);
        fl_GetedOfflineMessages = true;
    }
}

void ConnectorToServer::slot_sendMessage(ClientMessage clientMessage)
{
     sendMessage(clientMessage);
}

void ConnectorToServer::showServerList(QList<StreamingVersionData *> *serverList)
{
    versionSelectWidget->fillView(serverList);
}

void ConnectorToServer::slot_HashReady()
{
    //sendQueryTasksXML("fim");
    //sendQueryTasksXML("amm");
}

void ConnectorToServer::slot_Auth(ServerAuthorization *serverAuth)
{
    this->serverAuth = *serverAuth;
    emit sigLoginResult(serverAuth);
}

void ConnectorToServer::initialize()
{
    createObjects();

    bindConnection();

    emit sigInitializeClient(recognizeSystem,sendSystem,connectionThread);

    SetConnectToServer();
}

void ConnectorToServer::bindConnection()
{
    connect(this,&ConnectorToServer::sigInitializeClient,client,&TCPClient::initialize,Qt::AutoConnection);
    connect(this,&ConnectorToServer::sigSetConnect,client,&TCPClient::setConnect,Qt::AutoConnection);
    connect(this,&ConnectorToServer::sigStopConnect,client,&TCPClient::setDisconnect,Qt::AutoConnection);

    connect(this,&ConnectorToServer::signal_sendXMLmsgGUItoServer,sendSystem,&SendSystem::sendXMLmsgGUItoServer);
    connect(this,&ConnectorToServer::sigSendAnswerToServer,sendSystem,&SendSystem::sendXMLAnswer,Qt::AutoConnection);

    connect(recognizeSystem,&RecognizeSystem::sigAuth,this,&ConnectorToServer::slot_Auth); // ::sigLoginResult);
    connect(recognizeSystem,&RecognizeSystem::sigDeAuth,this,&ConnectorToServer::sigDeLoginResult);
    connect(recognizeSystem,&RecognizeSystem::signal_ReceiveMessage,this,&ConnectorToServer::signal_receiveMessage,Qt::AutoConnection);
    connect(recognizeSystem,&RecognizeSystem::sigShowServerDataList,this,&ConnectorToServer::showServerList);
    connect (recognizeSystem,&RecognizeSystem::sigSetVersion,versionContainer,&VersionContainer::setServerVersionData);
    //connect(recognizeSystem,&RecognizeSystem::sigAnswerQueryToDB,this,&ConnectorToServer::slot_AnswerQueryToDB);

    connect(recognizeSystem,&RecognizeSystem::sigAnswerQueryToDB_ListInstructors,this,&ConnectorToServer::slot_AnswerQueryToDB_ListInstructors);
    connect(recognizeSystem,&RecognizeSystem::sigAnswerQueryToDB_ListGroups,this,&ConnectorToServer::slot_AnswerQueryToDB_ListGroups);
    connect(recognizeSystem,&RecognizeSystem::sigAnswerQueryToDB_ListTrainees,this,&ConnectorToServer::slot_AnswerQueryToDB_ListTrainees);
    connect(recognizeSystem,&RecognizeSystem::sigAnswerQueryToDB_ListComputers,this,&ConnectorToServer::slot_AnswerQueryToDB_ListComputers);
    connect(recognizeSystem,&RecognizeSystem::sigAnswerQueryToDB_ListClassrooms,this,&ConnectorToServer::slot_AnswerQueryToDB_ListClassrooms);

    connect(recognizeSystem,&RecognizeSystem::sigAnswerQueryToDB_ListTasksAMMforTrainee,this,&ConnectorToServer::slot_AnswerQueryToDB_ListTasksAMMforTrainee);
    connect(recognizeSystem,&RecognizeSystem::sigAnswerQueryToDB_ListTasksFIMforTrainee,this,&ConnectorToServer::slot_AnswerQueryToDB_ListTasksFIMforTrainee);

    connect(recognizeSystem,&RecognizeSystem::sigAnswerQueryTasksXML_FIM,this,&ConnectorToServer::slot_AnswerQueryTasksXML_FIM);
    connect(recognizeSystem,&RecognizeSystem::sigAnswerQueryTasksXML_AMM,this,&ConnectorToServer::slot_AnswerQueryTasksXML_AMM);

    connect(client,&TCPClient::signal_ConnectedToServer,this,&ConnectorToServer::signal_ConnectedToServer,Qt::AutoConnection);

    connect(recognizeSystem,&RecognizeSystem::sigNotify,notifyController,&NotifyController::showWarning,Qt::AutoConnection);

    connect(recognizeSystem,&RecognizeSystem::sigHashReady,this,&ConnectorToServer::slot_HashReady);
}

void ConnectorToServer::createObjects()
{
    connectionThread = new QThread;

    client = new TCPClient;
    client->moveToThread(connectionThread);

    dataParser = new DataParser;    

    sendSystem = new SendSystem;
    sendSystem->moveToThread(connectionThread);

    recognizeSystem = new RecognizeSystem;
    recognizeSystem->moveToThread(connectionThread);

    notifyController = new NotifyController;
    versionContainer = new VersionContainer;
    versionSelectWidget = new VersionSelectWidget(parentWidget);
    versionSelectWidget->initialize(sendSystem,versionContainer,notifyController, recognizeSystem);

    connectionThread->start();
    connectionThread->setPriority(QThread::HighestPriority);
}

void ConnectorToServer::clearListModelDB()
{
    listInstructors.clear();
    listGroups.clear();
    listTrainees.clear();
    listComputers.clear();
    listClassrooms.clear();
    mapTasksAMM.clear();
    mapTasksFIM.clear();

    listTaskFimArray.clear();
    listTaskAmmArray.clear();
}

SendSystem *ConnectorToServer::getSendSystem() const
{
    return sendSystem;
}
