#include "coremanager.h"

CoreManager::CoreManager(QObject *parent) :
    QObject(parent),
    isRecovery(false)
{
    client = new TCPClient;
    dataParser = new DataParser;
    dataParserOutput = new DataParserOutput;
    updateController = new UpdateController;
    recognizeSystem = new RecognizeSystem;
    screenChecker = new ScreenChecker;
    externalExecuter = new ExternalExecuter;
    sendSystem = new SendSystem;
    hashComparer = new HashComparer;
    versionContainer = new VersionContainer;
    resourceManager = new ResourceManager;
    postProcessorSystem = new PostProcessorSystem;
}

void CoreManager::initialize(WidgetManager *widgetManager,QThread *workerThread)
{
    this->workerThread = workerThread;
    this->widgetManager = widgetManager;

    client->moveToThread(workerThread);
    dataParser->moveToThread(workerThread);
    dataParserOutput->moveToThread(workerThread);
    sendSystem->moveToThread(workerThread);
    updateController->moveToThread(workerThread);
    recognizeSystem->moveToThread(workerThread);
    postProcessorSystem->moveToThread(workerThread);
    hashComparer->moveToThread(workerThread);
//    versionContainer->moveToThread(workerThread); //проверить работоспособность
//    resourceManager->moveToThread(workerThread);  //проверить работоспособность

    workerThread->start();
    //workerThread->setPriority(QThread::HighestPriority);

    binding();
    initializeSystems();
    initializeWidgets();

    loadStaticData();
}

void CoreManager::start()
{
     checkAppAvailable();
}

void CoreManager::loadStaticData()
{
    ServerSettings *currentSettings = dataParser->getClientSettings();
    setLanguage(currentSettings->Language);
    setLocalVersion();
    externalExecuter->setIsAutoStart(currentSettings->isAutoStart);
    bool appAvailable = externalExecuter->findApp();
    widgetManager->setAppAvailable(appAvailable);
    emit sigSetLoadSettings(currentSettings);
}

void CoreManager::binding()
{
    connect(recognizeSystem,&RecognizeSystem::sigAnimationActivated,widgetManager,&WidgetManager::slotActivateLoadAnimation,Qt::AutoConnection);

    connect(this,&CoreManager::sigInitializeClient,client,&TCPClient::initialize,Qt::AutoConnection);
    connect(this,&CoreManager::sigSetConnect,client,&TCPClient::setConnect,Qt::AutoConnection);
    connect(this,&CoreManager::sigSendCommand,sendSystem,&SendSystem::sendPacketType,Qt::AutoConnection);
    connect(this,&CoreManager::sigSendCheckUpdate,sendSystem,&SendSystem::sendCheckHash,Qt::AutoConnection);
    connect(this,&CoreManager::sigSendXMLAnswer,sendSystem,&SendSystem::xmlAnswer,Qt::AutoConnection);
    connect(this,&CoreManager::sigSendAutorization,sendSystem,&SendSystem::sendClientAutorization);
    connect(this,&CoreManager::sigSendUpdateToServer,updateController,&UpdateController::checkCanUpdate,Qt::AutoConnection);
    connect(this,&CoreManager::sigGetConnected,client,&TCPClient::getIsConnected);
    connect(this,&CoreManager::sigCalculateHash,updateController,&UpdateController::calculateCommonHash);

    connect(this,&CoreManager::sigSetLoadSettings,widgetManager,&WidgetManager::slotSetLoadSettings,Qt::AutoConnection);

    connect(postProcessorSystem,&PostProcessorSystem::sigCallUpdateList,this,&CoreManager::callUpdateList,Qt::AutoConnection);
    connect(postProcessorSystem,&PostProcessorSystem::sigSocketDisabled,this,&CoreManager::lostConnection,Qt::AutoConnection);
    connect(postProcessorSystem,&PostProcessorSystem::sigServerBlocked,this,&CoreManager::serverBlocked,Qt::AutoConnection);
    connect(postProcessorSystem,&PostProcessorSystem::sigStartCompare,hashComparer,&HashComparer::CompareDeltas,Qt::AutoConnection);
    connect(postProcessorSystem,&PostProcessorSystem::sigSaveLoginData,this,&CoreManager::checkLoginResult,Qt::AutoConnection);

    connect(versionContainer,&VersionContainer::sigSetServerVersion,this,&CoreManager::setServerVersion,Qt::AutoConnection);

    connect(recognizeSystem,&RecognizeSystem::sigUpdateBytesAvailable,this,&CoreManager::calcUpdateProgress,Qt::AutoConnection);
    connect(recognizeSystem,&RecognizeSystem::sigLoadComplete,this,&CoreManager::loadComplete,Qt::AutoConnection);
    connect(recognizeSystem,&RecognizeSystem::sigNeedUpdate,this,&CoreManager::checkNeedUpdate,Qt::AutoConnection);
    connect(recognizeSystem,&RecognizeSystem::sigCheckUpdate,this,&CoreManager::checkUpdate,Qt::AutoConnection);
    connect(recognizeSystem,&RecognizeSystem::sigdRecalculateHashOnServerState,this,&CoreManager::recalculateState,Qt::AutoConnection);

    connect(hashComparer,&HashComparer::sigCallCheck,this,&CoreManager::checkUpdate);
    connect(hashComparer,&HashComparer::sigHaveDelta,this,&CoreManager::checkUpdateInfo);

    connect(updateController,&UpdateController::sigUpdateComplete,widgetManager,&WidgetManager::setCompeteState,Qt::AutoConnection);
    connect(updateController->getHashCalculator(),&FastHashCalculator::sigSendHashInfo,widgetManager->getMainWindow(),&MainWindow::updateInitInformation,Qt::AutoConnection);

    connect(client,&TCPClient::sigConnectionState,widgetManager,&WidgetManager::setConnectionState,Qt::AutoConnection);
    connect(client,&TCPClient::sigServerDisconnect,widgetManager,&WidgetManager::setServerDisconnectState,Qt::AutoConnection);

    connect(sendSystem,&SendSystem::sigSend,this,&CoreManager::calcUpdateProgress,Qt::AutoConnection);

    connect(sendSystem,&SendSystem::sigGetXmlAnswer,dataParserOutput,&DataParserOutput::xmlAnswer_notify,Qt::DirectConnection);
}

void CoreManager::initializeSystems()
{
    updateController->initialize(versionContainer,dataParserOutput,sendSystem);
    screenChecker->initialize(dataParserOutput,widgetManager->getMainWindow()->getDisplayLayout());
    hashComparer->initialize(versionContainer,widgetManager->getUpdateWidget());
    postProcessorSystem->initialize(dataParserOutput,hashComparer,versionContainer,updateController);
    dataParser->initialize(postProcessorSystem);
    recognizeSystem->initialize(dataParser,versionContainer,postProcessorSystem);
    resourceManager->painting();

    emit sigCalculateHash();
    emit sigInitializeClient(recognizeSystem,sendSystem);

    screenChecker->check();

    emit sigSetConnect(dataParser->getClientSettings());
}

void CoreManager::initializeWidgets()
{
    widgetManager->getMainWindow()->initialize(resourceManager);
    widgetManager->getWaitAnimationWidget()->initialize(resourceManager);
    widgetManager->getUpdateWidget()->setVersionContainer(versionContainer);

    connect(widgetManager->getUpdateWidget(),&UpdateNotifyWidget::sigLoadToServerBehaviour,this,&CoreManager::loadToServer,Qt::AutoConnection);
    connect(widgetManager->getUpdateWidget(),&UpdateNotifyWidget::sigUndoCurrentChanges,this,&CoreManager::undoCurrentChanges,Qt::AutoConnection);
    connect(widgetManager->getUpdateWidget(),&UpdateNotifyWidget::sigStartUnityClient,this,&CoreManager::startUnityClient,Qt::AutoConnection);

    connect(widgetManager->getEntryWidget(),&EntryWidget::sigTryLogin,this,&CoreManager::tryLogin,Qt::AutoConnection);
    connect(widgetManager->getEntryWidget(),&EntryWidget::sigSaveServerSettings,this,&CoreManager::saveServerSettingsWithConnect,Qt::AutoConnection);

    connect(widgetManager->getInstructorButtonGroupWiget(),&InstructorButtonGroupWidget::sigLoadToServer,this,&CoreManager::loadToServer, Qt::AutoConnection);
    connect(widgetManager->getInstructorButtonGroupWiget(),&InstructorButtonGroupWidget::sigUndoCurrentChanges,this,&CoreManager::undoCurrentChanges, Qt::AutoConnection);
    connect(widgetManager->getInstructorButtonGroupWiget(),&InstructorButtonGroupWidget::sigStartUnityClient,this,&CoreManager::startUnityClient, Qt::AutoConnection);

    connect(widgetManager->getCommonButtonGroupWidget(),&CommonButtonGroupWidget::sigSendPacket,sendSystem,&SendSystem::sendPacketType,Qt::AutoConnection);
    connect(widgetManager->getCommonButtonGroupWidget(),&CommonButtonGroupWidget::sigStartUnityClient,this,&CoreManager::startUnityClient,Qt::AutoConnection);

    connect(widgetManager->getMainWindow(),&MainWindow::sigChangeLanguage,this,&CoreManager::setLanguage,Qt::AutoConnection);
    connect(widgetManager->getMainWindow(),&MainWindow::sigShowUpdateInfo,this,&CoreManager::checkUpdateInfo,Qt::AutoConnection);
    connect(widgetManager->getMainWindow(),&MainWindow::sigExit,this,&CoreManager::exit,Qt::AutoConnection);
    connect(widgetManager->getMainWindow(),&MainWindow::sigTryLogin,this,&CoreManager::tryLogin,Qt::AutoConnection);
    connect(widgetManager->getMainWindow(),&MainWindow::sigStartOffline,this,&CoreManager::startOffline,Qt::AutoConnection);

}

RecognizeSystem *CoreManager::getRecognizeSystem() const
{
    return recognizeSystem;
}

void CoreManager::callUpdateList()
{
    emit sigSendXMLAnswer(cmd_GetServerHash);
}

void CoreManager::lostConnection()
{
    widgetManager->setLostConnectionState();
}

void CoreManager::serverBlocked()
{
     widgetManager->getMainWindow()->serverBlocked();
}

void CoreManager::setServerVersion(StreamingVersionData *version)
{
    widgetManager->getMainWindow()->setServerVersion(version);
}

void CoreManager::setLocalVersion()
{
    ServerSettings *currentSettings = dataParser->getClientSettings();
    StreamingVersionData *version = new StreamingVersionData;
    version->setName(currentSettings->LocalVersionName);
    version->setIsChangeable(currentSettings->versionData.getIsChangeable());

    versionContainer->setLocalVersionData(version);
    widgetManager->getMainWindow()->setClientVersionName(versionContainer->getLocalVersion());
}

void CoreManager::checkLoginResult(ServerAuthorization *auth)
{
    if (auth->Result)
    {
        widgetManager->activateLoadingAnimation(true);
        checkAccessType(auth->AccessType);
        dataParserOutput->createAuthData(auth);
        setLocalVersion();
        widgetManager->setLoginSuccess();
        widgetManager->getMainWindow()->setClientVersionName(versionContainer->getLocalVersion());
    }
    else
    {
        widgetManager->setLoginFailed();
    }
}

void CoreManager::tryLogin()
{
    if (!client->getIsConnected())
    {
         widgetManager->getMainWindow()->showConnectionEmpty();
         return;
    }

    widgetManager->getEntryWidget()->showLoginWidget(false);
    ClientAutorization *auth = widgetManager->getEntryWidget()->getAuthData();
    dataParserOutput->createAuthMessage(auth);
    emit sigSendAutorization();
}

void CoreManager::checkUpdate()
{
    widgetManager->activateLoadingAnimation(true);
    emit sigSendCheckUpdate();
    widgetManager->getMainWindow()->setInlineDebug(tr("Проверка обновлений..."));
}

void CoreManager::recalculateState()
{
    widgetManager->activateLoadingAnimation(true);
    widgetManager->getMainWindow()->setInlineDebug(tr("Пересчет хэша на сервере..."));
}

void CoreManager::checkAccessType(const QString& accessType)
{
    if (accessType == traineeTypeName)
    {
        checkUpdate();
    }
    else
    {
        emit sigSendXMLAnswer(cmd_CheckVersionList);
    }
}

void CoreManager::checkUpdateInfo()
{
    fileCountForUpdate = hashComparer->getFileUpdateCount();
    widgetManager->showUpdateInfo();
}

void CoreManager::checkNeedUpdate(bool isNeedUpdate,quint64 size, quint64 fileCount,quint64 deleteCount)
{
    filesLoaded = 0;
    fileCountForUpdate = fileCount;
    QString availableSizeText;

    if (isNeedUpdate && isRecovery)
    {
        widgetManager->setRecoveryState();
    }
    else if(isNeedUpdate)
    {
        widgetManager->setNeedUpdateState(size,fileCount,deleteCount);
        setLocalVersion();
    }
    else
    {
        widgetManager->setLastVersionState();
        checkAutoStart();
        dataParserOutput->changeVersion(versionContainer->getServerVersionData());
        setLocalVersion();
    }

    widgetManager->activateLoadingAnimation(false);
}

void CoreManager::calcUpdateProgress()
{
    filesLoaded++;
    float value = 100 / ((float)fileCountForUpdate / filesLoaded);
    widgetManager->getCommonButtonGroupWidget()->updateProgressBar(value);
}

void CoreManager::checkAutoStart()
{
    if (externalExecuter->getIsAutoStart())
    {
        startUnityClient();
    }
}

void CoreManager::startUnityClient()
{
    externalExecuter->callApp();
    emit sigSendXMLAnswer(cmd_Disable);
}

VersionContainer *CoreManager::getVersionContainer() const
{
    return versionContainer;
}

void CoreManager::loadComplete()
{
    widgetManager->setLoadCompleteState();
    externalExecuter->findApp();
    externalExecuter->setIsAutoStart(widgetManager->getMainWindow()->getIsAutoStart());
    dataParserOutput->changeVersion(versionContainer->getServerVersionData());
    setLocalVersion();
    checkAutoStart();
    widgetManager->getMainWindow()->setClientVersionName(versionContainer->getLocalVersion());
}

void CoreManager::loadToServer()
{
    widgetManager->setSendFileToServerState();
    widgetManager->activateLoadingAnimation(true);
    emit sigSendUpdateToServer();
}

void CoreManager::undoCurrentChanges()
{
    isRecovery = true;
    widgetManager->setUndoCurrentChangesState();
    emit sigSendCheckUpdate();
    emit sigSendCommand(PacketType::TYPE_UPDATE);
    //тут был таймер
    isRecovery = false;

    widgetManager->activateLoadingAnimation(false);
}

void CoreManager::startOffline()
{
    QString username = "offlineUser";
    QString password = "000000";

    dataParserOutput->createAuthDataOffline(username,password);
    startUnityClient();
}

void CoreManager::saveServerSettingsWithConnect()
{
    widgetManager->activateLoadingAnimation(true);
    EntryWidget *entryWidget = widgetManager->getEntryWidget();

    entryWidget->isActive(false);
    ServerSettings *settings = entryWidget->getServerSettings();
    settings->LocalVersionName = dataParser->getClientSettings()->LocalVersionName;
    dataParserOutput->createServerSettings(settings);

    if(client->getIsConnected())
    {
        emit sigSendXMLAnswer(cmd_Disable);
        client->setDisconnect();
        entryWidget->showLoginWidget(true);
        widgetManager->getMainWindow()->showOfflineButton(true);
        widgetManager->activateLoadingAnimation(false);
    }

    emit sigSetConnect(settings);
}

void CoreManager::checkAppAvailable()
{
    bool isAvailable = externalExecuter->findApp();
    widgetManager->setAppAvailable(isAvailable);
}

void CoreManager::setLanguage(const QString& language)
{
    if (language == "RUS")
    {
        translator.load("QtLanguage_ru_RU",".");
    }
    else if(language == "ENG")
    {
        translator.load("QtLanguage_eng_EN",".");
    }
    qApp->installTranslator(&translator);

    dataParserOutput->saveClientSettings(language,widgetManager->getMainWindow()->getIsAutoStart());
}

void CoreManager::exit()
{
    emit sigSendXMLAnswer(cmd_Disable);
    client->disconnect();

    workerThread->quit();
    workerThread->wait();

    delete workerThread;
}

ResourceManager *CoreManager::getResourceManager() const
{
    return resourceManager;
}

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