/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2025 Univ. Grenoble Alpes, CNRS, Grenoble INP - UGA, TIMC, 38000 Grenoble, France
 *
 * Visit http://camitk.imag.fr for more information
 *
 * This file is part of CamiTK.
 *
 * CamiTK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * CamiTK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $CAMITK_LICENCE_END$
 ****************************************************************************/

#include "MonitoringGuiManager.h"

#include "MonitoringDialog.h"
#include "MonitoringDriver.h"
#include <iostream>

#include <QApplication>

//--------------- Constructor ---------------------------------
MonitoringGuiManager::MonitoringGuiManager() {
    Q_INIT_RESOURCE(MonitoringGuiIcons);
    driver = new MonitoringDriver(this);
    dialog = new MonitoringDialog(this);
    monitoringManager = nullptr;
    driver->init();
    dialog->init();
    dialog->show();
    lastRefreshTime = 0;
}

//--------------- Destructor ---------------------------------
MonitoringGuiManager::~MonitoringGuiManager() {
    if (driver) {
        delete driver;
        driver = nullptr;
    }
    if (dialog) {
        delete dialog;
        dialog = nullptr;
    }
    if (monitoringManager) {
        delete monitoringManager;
        monitoringManager = nullptr;
    }
    Q_CLEANUP_RESOURCE(MonitoringGuiIcons);
}

//--------------- getDialog ---------------------------------
MonitoringDialog* MonitoringGuiManager::getDialog() {
    return dialog;
}

//--------------- getDriver ---------------------------------
MonitoringDriver* MonitoringGuiManager::getDriver() {
    return driver;
}

//--------------- getMonitoringManager ---------------------------------
MonitoringManager* MonitoringGuiManager::getMonitoringManager() {
    return monitoringManager;
}


//--------------- doOneStep ---------------------------------
bool MonitoringGuiManager::doOneStep() {
    if (monitoringManager->checkStop()) {
        std::cout << tr("Simulation finished: the simulation is finished (Stopping Criterion reached).").toStdString() << std::endl;
        driver->stopTimer();
        return false;
    }
    else {

        // As this method is called by a timer, it could happen that the motor
        // has not finished one step of computation when the timer starts
        // the method again. This results in a strange state.
        // waitingForFinish act as a flag to say "wait, wait, we are
        // already computing a step, we can't do many at the same time,
        // take your chance next time".
        // That allows the timer to be regulated by the motor computation time.
        static bool waitingToFinish = false;

        if (waitingToFinish) {
            return false; // bye bye, we are too busy at the moment, we haven't done anything
        }

        waitingToFinish = true;

        // if t is ok, play it

        // update cursor
        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));

        // show the progress
        //TODO

        // do simulation steps until the next refresh time is reached
        monitoringManager->doMove();

        // update cursor
        QApplication::restoreOverrideCursor();

        //emit changed only if we have to refresh
        if (monitoringManager->getCurrentTime() >= lastRefreshTime + monitoringManager->getRefresh()) {
            emit changed();
            lastRefreshTime = monitoringManager->getCurrentTime();
        }
        // release the flag, so that next time this method is called,
        // a new step could be computed
        waitingToFinish = false;
        // update view
        dialog->updateSimulation();
        return true; // bye bye, we have done one step
    }
}

//--------------- simulate ---------------------------------
void MonitoringGuiManager::simulate() {
    if (!driver->isTimerActive()) {
        // timer wasn't active, action to be done = launch the timer
        driver->startTimer();
    }
    else {
        // timer is active, action to be done = play one step
        doOneStep();
    }
}

//--------------- simulateOneStep ---------------------------------
void MonitoringGuiManager::simulateOneStep() {
    // force one step to be done
    if (!monitoringManager->checkStop()) {
        while (!doOneStep())
            ;
    }
    else {
        doOneStep(); // just to have the message box
    }
}

//--------------- pause ---------------------------------
void MonitoringGuiManager::pause() {
    driver->stopTimer();
}

//--------------- rewind ---------------------------------
void MonitoringGuiManager::rewind() {
    pause();
    monitoringManager->rewind();
    lastRefreshTime = 0;
    emit changed();
    dialog->updateSimulation();
}

//--------------- reload ---------------------------------
void MonitoringGuiManager::reload() {
    pause();
    monitoringManager->reload(false);
    lastRefreshTime = 0;
    emit reconnectPml();
    dialog->updateAll();
}



//--------------- loadMmlInFile ---------------------------------
bool MonitoringGuiManager::loadMmlInFile(QString fileName) {
    if (monitoringManager) {
        delete monitoringManager;
    }

    monitoringManager = MonitoringManagerFactory::createManager(fileName.toStdString().c_str());
    if (monitoringManager != nullptr) {
        monitoringManager->init();
        dialog->updateAll();
        return true;
    }
    else {
        return false;
    }
}

//--------------- saveMmlOutFile ---------------------------------
bool MonitoringGuiManager::saveMmlOutFile(QString fileName) {
    monitoringManager->writeOutput(fileName.toUtf8().constData());
    return true;
}

//--------------- saveCsvFile ---------------------------------
bool MonitoringGuiManager::saveCsvFile(QString fileName) {
    monitoringManager->writeCsv(fileName.toUtf8().constData());
    return true;
}


//--------------- saveMmlInFile ---------------------------------
bool MonitoringGuiManager::saveMmlInFile(QString fileName) {
    monitoringManager->saveMmlIn(fileName.toUtf8().constData());
    return true;
}


//--------------- updateDt ---------------------------------
void MonitoringGuiManager::updateDt(double dt) {
    monitoringManager->setDt(dt);
}

//--------------- updateRefresh ---------------------------------
void MonitoringGuiManager::updateRefresh(double refresh) {
    monitoringManager->setRefresh(refresh);
}

//--------------- updatePml ---------------------------------
void MonitoringGuiManager::updatePml(QString fileName) {
    monitoringManager->setPmlFileName(fileName.toUtf8().constData());
}

//--------------- updateLml ---------------------------------
void MonitoringGuiManager::updateLml(QString fileName) {
    monitoringManager->setLmlFileName(fileName.toUtf8().constData());
}







