#include <QMessageBox>
#include <QThread>
#include <QTimer>
#include "instructorsandtraineeswidget.h"
#include "ui_instructorsandtraineeswidget.h"
#include "dialogauthorization.h"
#include "dialogsettings.h"
#include "specialmessagebox.h"
#include "hashtools.h"


const QString InstructorsAndTraineesWidget::languageENG = "en_EN";
const QString InstructorsAndTraineesWidget::languageRUS = "ru_RU";


InstructorsAndTraineesWidget::InstructorsAndTraineesWidget(QWidget *parent) :
    QWidget(parent),    
    waitAnimationWidget(nullptr),
    connectorToServer(nullptr),
    viewerTrainees(nullptr),
    viewerInstructors(nullptr),
    messangerWidget(nullptr),
    messangerController(nullptr),
    dlgTasksCommon(nullptr),
    adminMode(false),
    loginInstructorLoggedInLocal(QStringLiteral("")),
    nameInstructorLoggedInLocal(QStringLiteral("")),
    idInstructorLoggedInLocal("0"),
    language(languageENG),
    flSettingsServerIsChanged(false),
    flTryConnectToServer(false),
    cntTryConnectToServer(0),
    ui(new Ui::InstructorsAndTraineesWidget)
{
    ui->setupUi(this);

    //Пока не нужно
    ui->btnTasksCommon->setVisible(false);

    qDebug() << "InstructorsAndTraineesWidget init thread ID " << QThread::currentThreadId();

    ui->widget_Control->setObjectName("widgetControl");

    registerMetaType();    

    updateMyStyleSheet();

    setLanguageInterfase();

    connectorToServer = new ConnectorToServer(this);
    connect(connectorToServer, &ConnectorToServer::sigLoginResult, this, &InstructorsAndTraineesWidget::slot_checkLoginResult);
    connect(connectorToServer, &ConnectorToServer::sigDeLoginResult, this, &InstructorsAndTraineesWidget::slot_checkDeLoginResult);
    connect(connectorToServer,&ConnectorToServer::signal_AnswerDocsChanged,this, &InstructorsAndTraineesWidget::slot_AnswerDocsChanged);

    messangerController = new MessangerController(connectorToServer, this);

    viewerTrainees = new ViewerTrainees(connectorToServer, messangerController, this);
    viewerInstructors = new ViewerInstructors(connectorToServer, this);
    connect(this, &InstructorsAndTraineesWidget::signal_NeedUpdateUI, viewerTrainees, &ViewerTrainees::slot_NeedUpdateUI);
    connect(this, &InstructorsAndTraineesWidget::signal_NeedUpdateUI, viewerInstructors, &ViewerInstructors::slot_NeedUpdateUI);

    connect(connectorToServer, &ConnectorToServer::signal_ConnectedToServer, this, &InstructorsAndTraineesWidget::slot_ConnectedToServer);

    connect(viewerTrainees, &ViewerTrainees::signal_traineeSelected, this, &InstructorsAndTraineesWidget::slot_traineeSelected);
    connect(viewerInstructors, &ViewerInstructors::signal_instructorSelected, this, &InstructorsAndTraineesWidget::slot_instructorSelected);

    viewerTrainees->clearSelection();
    viewerInstructors->clearSelection();

    //Размещение
    ui->verticalLayout_Trainees->addWidget(viewerTrainees);
    ui->verticalLayout_Instructors->addWidget(viewerInstructors);

    ui->groupBox_Messenger->setMinimumHeight(600);

    ui->groupBox_Messenger->setMaximumWidth(500);
    ui->groupBox_Messenger->setMinimumWidth(500);

    ui->groupBox_Instructors->setMinimumHeight(200);
    ui->groupBox_Instructors->setMaximumHeight(300);

    ui->groupBox_Trainees->setMinimumHeight(400);

    ui->groupBox_Trainees->setMinimumWidth(600);
    ui->groupBox_Instructors->setMinimumWidth(600);


    //Доступность кнопок
    ui->btnAuthorizationInstructor->setEnabled(false);
    ui->btnEditorTrainees->setEnabled(false);
    ui->btnEditorInstructors->setEnabled(false);
    ui->btnPersonalCard->setEnabled(false);

    waitAnimationWidget = new WaitAnimationWidget;
    QMovie *movie = new QMovie(":/resources/icons/762.gif");
    waitAnimationWidget->setParent(this);
    waitAnimationWidget->initialize(movie,this);

    ui->btnConnectionToServer->click();
}

InstructorsAndTraineesWidget::~InstructorsAndTraineesWidget()
{
    if(authorizationIsCompleted())
        deAuthorizationInstructor(loginInstructorLoggedInLocal);

    if(dlgTasksCommon)
        dlgTasksCommon->close();

    delete messangerController;
    delete viewerInstructors;
    delete viewerTrainees;
    delete connectorToServer;

    waitAnimationWidget->hideWithStop();
    delete waitAnimationWidget;

    delete ui;
}

QString InstructorsAndTraineesWidget::getLanguage()
{
    return language;
}

void InstructorsAndTraineesWidget::changeEvent(QEvent *event)
{
    // В случае получения события изменения языка приложения
    if (event->type() == QEvent::LanguageChange)
    {// переведём окно заново
        ui->retranslateUi(this);

        updateLabelLoggedInInstructor(loginInstructorLoggedInLocal, nameInstructorLoggedInLocal);
        updateLabelServer();
    }
}

void InstructorsAndTraineesWidget::resizeEvent(QResizeEvent *event)
{
    QSize size = event->size();
    waitAnimationWidget->resize(size);
}

void InstructorsAndTraineesWidget::updateMyStyleSheet()
{
    QString styleSheet = loadStyleSheet();
    styleSheet = styleSheet.replace("\n", "");

    this->setStyleSheet(styleSheet);
}

QString InstructorsAndTraineesWidget::loadStyleSheet()
{
    QString fileName = "./resources/css/styleSheetMain.css";
    QFile styleSheetFile(fileName);
    if (!styleSheetFile.open(QFile::ReadOnly | QFile::Text))
    {
        SpecialMessageBox(this, SpecialMessageBox::TypeSpecMsgBox::critical, tr("The file could not be opened ") + fileName).exec();
        return QStringLiteral("");
    }
    else
    {
        QByteArray byteArray = styleSheetFile.readAll();
        styleSheetFile.close();

        QString style = byteArray;
        return style;
    }
}

void InstructorsAndTraineesWidget::slot_LanguageChanged(QString language)
{
    qtLanguageTranslator.load(QString(QStringLiteral("translations/InstructorsAndTraineesWidget_")) + language, QStringLiteral("."));
    qApp->installTranslator(&qtLanguageTranslator);

    emit signal_LanguageChanged(language);
}

void InstructorsAndTraineesWidget::slot_UpdateStyleSheet()
{
    updateMyStyleSheet();
}

void InstructorsAndTraineesWidget::slot_checkLoginResult(ServerAuthorization *serverAuth)
{
    if (serverAuth->Result)
    {
        loginInstructorLoggedInLocal = serverAuth->Login;
        nameInstructorLoggedInLocal = serverAuth->ClientName;
        idInstructorLoggedInLocal = serverAuth->Id;

        if(loginInstructorLoggedInLocal == QStringLiteral("admin"))
            adminMode = true;
        else
            adminMode = false;

        viewerInstructors->setAdminMode(adminMode);
        viewerTrainees->setAdminMode(adminMode);
        viewerInstructors->setAuthComplited(true);
        viewerTrainees->setAuthComplited(true);

        ui->btnEditorTrainees->setEnabled(true);
        if(adminMode)
            ui->btnEditorInstructors->setEnabled(true);

        emit signal_NeedUpdateUI(true, true);

        updateLabelLoggedInInstructor(serverAuth->Login, serverAuth->ClientName);
        connectorToServer->setLoginName(nameInstructorLoggedInLocal);

        messangerController->setUserLocalGUI_ID(serverAuth->Id.toInt());

        connectorToServer->sendQueryTasksXML("fim");
        connectorToServer->sendQueryTasksXML("amm");

        viewerTrainees->activate();
        viewerInstructors->activate();
    }
    else
    {
        ui->btnAuthorizationInstructor->setChecked(false);
        SpecialMessageBox(this, SpecialMessageBox::TypeSpecMsgBox::critical, tr("Instructor authorization.") + "\n" + tr("Invalid login or password!")).exec();
    }
}

void InstructorsAndTraineesWidget::slot_checkDeLoginResult(ServerDeAuthorization *serverDeAuth)
{
    if (serverDeAuth->Result)
    {
        loginInstructorLoggedInLocal = QStringLiteral("");
        nameInstructorLoggedInLocal = QStringLiteral("");
        adminMode = false;

        viewerInstructors->setAdminMode(adminMode);
        viewerTrainees->setAdminMode(adminMode);
        viewerInstructors->setAuthComplited(false);
        viewerTrainees->setAuthComplited(false);

        ui->btnEditorTrainees->setEnabled(false);
        ui->btnEditorInstructors->setEnabled(false);
        ui->btnPersonalCard->setEnabled(false);

        updateLabelLoggedInInstructor("","");
    }
    else
    {        
        ui->btnAuthorizationInstructor->setChecked(true);
        SpecialMessageBox(this, SpecialMessageBox::TypeSpecMsgBox::critical, tr("Instructor deauthorization") + "\n" + tr("Error!")).exec();
    }
}

void InstructorsAndTraineesWidget::slot_ConnectedToServer(bool state)
{
    if(state)
    {//Сервер подключен
        ui->btnConnectionToServer->setEnabled(false);
        ui->btnAuthorizationInstructor->setEnabled(true);

        ui->lblDBisConnected->setPixmap(QPixmap(QStringLiteral(":/resources/icons/circleGreen.png")));

        updateLabelLoggedInInstructor(loginInstructorLoggedInLocal, nameInstructorLoggedInLocal);

        flTryConnectToServer = false;
        cntTryConnectToServer = 0;
        waitAnimationWidget->hideWithStop();

        updateLabelServer();

        ui->btnAuthorizationInstructor->click();
    }
    else
    {//Сервер отключен
        //ui->btnConnectionToServer->setEnabled(true);
        ui->btnAuthorizationInstructor->setEnabled(false);
        ui->btnAuthorizationInstructor->setChecked(false);
        ui->lblDBisConnected->setPixmap(QPixmap(QStringLiteral(":/resources/icons/circleGray.png")));

        viewerInstructors->setAuthComplited(false);
        viewerTrainees->setAuthComplited(false);

        ui->btnEditorTrainees->setEnabled(false);
        ui->btnEditorInstructors->setEnabled(false);
        ui->btnPersonalCard->setEnabled(false);

        viewerTrainees->deactivate();
        viewerInstructors->deactivate();

        messangerController->deleteAllWidgets();

        loginInstructorLoggedInLocal = "";
        nameInstructorLoggedInLocal = "";

        updateLabelLoggedInInstructor(loginInstructorLoggedInLocal, nameInstructorLoggedInLocal);


        if(flTryConnectToServer)
        {
            if(cntTryConnectToServer < 10)
            {
                cntTryConnectToServer++;
                QTimer::singleShot(1000, this, SLOT(slot_ConnectToServer()));
            }
            else
            {
                flTryConnectToServer = false;
                cntTryConnectToServer = 0;
                ui->btnConnectionToServer->setEnabled(true);
                waitAnimationWidget->hideWithStop();
            }
        }
        else
        {
            flTryConnectToServer = false;
            cntTryConnectToServer = 0;
            ui->btnConnectionToServer->setEnabled(true);
        }

        if(!flSettingsServerIsChanged)
        {
            if(!flTryConnectToServer)
                SpecialMessageBox(this, SpecialMessageBox::TypeSpecMsgBox::warningClose, tr("The server is not available!")).exec();
        }
        else
            flSettingsServerIsChanged = false;


        updateLabelServer();
    }
}

void InstructorsAndTraineesWidget::slot_traineeSelected(int id_trainee)
{
    ui->btnPersonalCard->setEnabled(false);
    viewerInstructors->clearSelection();

    /*Messanger*/
    messangerController->deleteWidget(messangerWidget);
    if(id_trainee)
    {
        Trainee trainee = connectorToServer->getTrainee(id_trainee);
        if(trainee.getID())
        {
            messangerWidget = messangerController->newWidget(this, &trainee, ui->verticalLayout_Messenger);
            ui->btnPersonalCard->setEnabled(true);
        }
    }
}

void InstructorsAndTraineesWidget::slot_instructorSelected(int id_instructor)
{
    ui->btnPersonalCard->setEnabled(false);
    viewerTrainees->clearSelection();

    /*Messanger*/
    messangerController->deleteWidget(messangerWidget);
    if(id_instructor && id_instructor != idInstructorLoggedInLocal.toInt())
    {
        Instructor instructor = connectorToServer->getInstructor(id_instructor);
        if(instructor.getID())
            messangerWidget = messangerController->newWidget(this, &instructor, ui->verticalLayout_Messenger);
    }
}

void InstructorsAndTraineesWidget::slot_AnswerDocsChanged()
{
    viewerTrainees->getAmmTasksWidgetCommon()->setDocsActualed(false);
}

void InstructorsAndTraineesWidget::slot_ConnectToServer()
{
    updateLabelServer();
    connectorToServer->SetConnectToServer();
}

bool InstructorsAndTraineesWidget::authorizationInstructorDialog(QWidget* parent)
{
    DialogAuthorization dlg(parent);
    dlg.setWindowTitle(tr("Instructor authorization"));
    dlg.setWindowFlags(dlg.windowFlags() & ~Qt::WindowContextHelpButtonHint);
    dlg.setStyleSheet(this->styleSheet());
#ifdef PROJECT_TYPE_DEBUG
    dlg.setLogin("admin");
    dlg.setPassword("admin");
#endif

    do
    {
        switch( dlg.exec() )
        {
        case QDialog::Accepted:
        {
            QString login = dlg.getLogin();
            QString password = dlg.getPassword();

            // Вычисление MD5 хэша
            password = HashTools::hashingMD5string(password);

            connectorToServer->sendAuthorizationInstructorLocal(login, password);

            return true;
        }
        case QDialog::Rejected:
            return false;
        default:
            return false;
        }
    }
    while(true);

    return false;
}

bool InstructorsAndTraineesWidget::deAuthorizationInstructor(QString login)
{
    connectorToServer->sendDeAuthorizationInstructorLocal(login);
    return true;
}

bool InstructorsAndTraineesWidget::authorizationIsCompleted()
{
    if(loginInstructorLoggedInLocal == QStringLiteral(""))
        return false;
    else
        return true;
}

void InstructorsAndTraineesWidget::on_btnConnectionToServer_clicked()
{
    waitAnimationWidget->showWithPlay();

    ui->btnConnectionToServer->setEnabled(false);

    flTryConnectToServer = true;
    cntTryConnectToServer = 1;

    updateLabelServer();

    QTimer::singleShot(1000, this, SLOT(slot_ConnectToServer()));
}

void InstructorsAndTraineesWidget::on_btnAuthorizationInstructor_clicked()
{
    bool stateIsChecked = ui->btnAuthorizationInstructor->isChecked();

    if(stateIsChecked)
    {//Авторизация Инструктора локальная (Администратора)
        if(authorizationInstructorDialog(this))
        {
            connect(connectorToServer,&ConnectorToServer::signal_UpdateDB,viewerInstructors,&ViewerInstructors::slot_NeedUpdateUI);
            connect(connectorToServer,&ConnectorToServer::signal_UpdateDB,viewerTrainees,&ViewerTrainees::slot_NeedUpdateUI);
            connect(connectorToServer,&ConnectorToServer::signal_reInitMessangerByUsers,messangerController,&MessangerController::slot_reinitMessangers);
        }
        else
            ui->btnAuthorizationInstructor->setChecked(false);
    }
    else
    {//ДеАвторизация Инструктора локальная (Администратора)
        if(authorizationIsCompleted())
        {
            if(deAuthorizationInstructor(loginInstructorLoggedInLocal))
            {
                disconnect(connectorToServer,&ConnectorToServer::signal_UpdateDB,viewerInstructors,&ViewerInstructors::slot_NeedUpdateUI);
                disconnect(connectorToServer,&ConnectorToServer::signal_UpdateDB,viewerTrainees,&ViewerTrainees::slot_NeedUpdateUI);
                disconnect(connectorToServer,&ConnectorToServer::signal_reInitMessangerByUsers,messangerController,&MessangerController::slot_reinitMessangers);

                viewerTrainees->deactivate();
                viewerInstructors->deactivate();

                messangerController->deleteAllWidgets();
            }
            else
                ui->btnAuthorizationInstructor->setChecked(true);
        }
    }
}

void InstructorsAndTraineesWidget::updateLabelLoggedInInstructor(QString login, QString name)
{
    if(authorizationIsCompleted())
    {
        QString nameLoggedInInstructor = QString("%1 (%2)").arg(name, login);
        ui->lblLoggedInInstructor->setText(nameLoggedInInstructor);
        if(loginInstructorLoggedInLocal == QStringLiteral("admin"))
            ui->lblLoggedIn->setPixmap(QPixmap(QStringLiteral(":/resources/icons/admin.png")));
        else
            ui->lblLoggedIn->setPixmap(QPixmap(QStringLiteral(":/resources/icons/instructor.png")));
    }
    else
    {
        ui->lblLoggedInInstructor->setText(tr("none"));
        ui->lblLoggedIn->setPixmap(QPixmap(QStringLiteral(":/resources/icons/circleGray.png")));
    }
}

void InstructorsAndTraineesWidget::updateLabelServer()
{
    if(!connectorToServer)
        return;

    if(flTryConnectToServer)
    {
        ui->lblServer->setText(tr("Connection attempt") + QString(" %1 ").arg(cntTryConnectToServer) + "...");
    }
    else
    {
        if(connectorToServer->getIsConnected())
        {
            ServerSettings serverSettings = connectorToServer->getServerSettings();
            ui->lblServer->setText(tr("connected") + " " + serverSettings.Address + " : " +serverSettings.Port);
        }
        else
            ui->lblServer->setText(tr("not connected"));
    }
}

void InstructorsAndTraineesWidget::setLanguageInterfase()
{
    ServerSettings settings;
    DialogSettings::loadSettings(&settings);

    if(settings.Language == "ENG")
    {
        qtLanguageTranslator.load(QString("translations/InstructorsAndTraineesWidget_") + languageENG, ".");
        language = languageENG;
    }
    else
    {
        qtLanguageTranslator.load(QString("translations/InstructorsAndTraineesWidget_") + languageRUS, ".");
        language = languageRUS;
    }

    qApp->installTranslator(&qtLanguageTranslator);

    emit signal_LanguageChanged(language);
}

void InstructorsAndTraineesWidget::on_btnSettings_clicked()
{
    DialogSettings dlg(connectorToServer, (loginInstructorLoggedInLocal != ""), this);
    dlg.setWindowFlags(dlg.windowFlags() & ~Qt::WindowContextHelpButtonHint);

    connect(&dlg, &DialogSettings::signal_LanguageChanged, this, &InstructorsAndTraineesWidget::slot_LanguageChanged);
    connect(&dlg, &DialogSettings::signal_UpdateStyleSheet, this, &InstructorsAndTraineesWidget::slot_UpdateStyleSheet);


    switch( dlg.exec() )
    {
    case QDialog::Accepted:
    {
        language = dlg.getSettings().Language;

        if(dlg.settingsServerIsChanged())
        {
            SpecialMessageBox(this, SpecialMessageBox::TypeSpecMsgBox::warningClose, tr("Server settings have been changed. Please reconnect to the server.")).exec();

            flSettingsServerIsChanged = true;

            if(authorizationIsCompleted())
                deAuthorizationInstructor(loginInstructorLoggedInLocal);

            connectorToServer->StopConnectToServer();
        }

        break;
    }
    case QDialog::Rejected:
        break;
    default:
        break;
    }    
}

void InstructorsAndTraineesWidget::on_btnEditorTrainees_clicked()
{
    this->viewerTrainees->on_btnEditorTrainees_clicked();
}

void InstructorsAndTraineesWidget::on_btnEditorInstructors_clicked()
{
    this->viewerInstructors->on_btnEditorInstructors_clicked();
}

void InstructorsAndTraineesWidget::on_btnPersonalCard_clicked()
{
    this->viewerTrainees->on_btnPersonalCard_clicked();
}

void InstructorsAndTraineesWidget::on_btnTasksCommon_clicked()
{
    AMMtasksWidget* ammTasksWidgetCommon = viewerTrainees->getAmmTasksWidgetCommon();
    FIMtasksWidget* fimTasksWidgetCommon = viewerTrainees->getFimTasksWidgetCommon();

    if(!ammTasksWidgetCommon || !fimTasksWidgetCommon)
        return;

    dlgTasksCommon = new DialogTasksCommon(connectorToServer, ammTasksWidgetCommon, fimTasksWidgetCommon, this);
    dlgTasksCommon->exec();

    ammTasksWidgetCommon->setParent(this);
    fimTasksWidgetCommon->setParent(this);

    if(dlgTasksCommon)
    {
        delete dlgTasksCommon;
        dlgTasksCommon = nullptr;
    }
}
