/*****************************************************************************
 * $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$
 ****************************************************************************/

#ifdef PYTHON_BINDING

#include "PythonHotPlugAction.h"
#include "PythonHotPlugActionExtension.h"

#include "ActionWidget.h"
#include "Application.h"
#include "Log.h"

#include <TransformEngine.h>
#include <VariantDataModel.h>

namespace camitk {

// ------------------- Constructor -------------------
PythonHotPlugAction::PythonHotPlugAction(PythonHotPlugActionExtension* extension, const VariantDataModel& data) : HotPlugAction(extension, data) {
    pythonExtension = extension;

    TransformEngine transformEngine;
    QJsonObject dataObject = data.getValue().toJsonObject();

    // determine python script name and other values
    pythonName = transformEngine.transformToString("$lowerSnakeCase(name)$", dataObject);
    noGui = (dataObject["gui"].toString() == "No GUI");
}

// ------------------- init -------------------
bool PythonHotPlugAction::init() {
    // call the init() function in python
    PythonHotPlugActionExtension::PythonCallStatus status = pythonExtension->callPython(this, "init");
    // Returns true when either everything went well or the init() method is missing in the python script
    return (status == PythonHotPlugActionExtension::PythonCallStatus::SUCCESS
            || status == PythonHotPlugActionExtension::PythonCallStatus::MISSING_FUNCTION);
}

// ------------------- getPythonName -------------------
QString PythonHotPlugAction::getPythonName() {
    return pythonName;
}

// ------------------- getWidget -------------------
QWidget* PythonHotPlugAction::getWidget() {
    if (noGui) {
        // this won't generate an error when the parameterChanged() method is missing in the python script (only an info message)
        pythonExtension->callPython(this, "targetDefined");
        return nullptr;
    }

    // Get UI, then call targetDefined
    if (actionWidget == nullptr) {
        // create default widget
        QWidget* defaultWidget = Action::getWidget();

        return defaultWidget;
    }
    else {
        // this won't generate an error when the parameterChanged() method is missing in the python script (only an info message)
        pythonExtension->callPython(this, "targetDefined");

        ActionWidget* defaultActionWidget = dynamic_cast<ActionWidget*>(actionWidget);
        if (defaultActionWidget != nullptr) {
            // this is a default action widget, make sure the widget has updated targets
            defaultActionWidget->update();
        }
        return actionWidget;
    }
}

// ------------------- apply -------------------
Action::ApplyStatus PythonHotPlugAction::apply() {
    // set waiting cursor
    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));

    // call python and check the results
    PythonHotPlugActionExtension::PythonCallStatus status = pythonExtension->callPython(this, "process");
    Action::ApplyStatus applyStatus;
    if (status == PythonHotPlugActionExtension::PythonCallStatus::SUCCESS) {
        applyStatus = Action::SUCCESS;
    }
    else {
        // process() method is missing or something went wrong
        applyStatus = Action::ERROR;
        // callPython will only use INFO level for these two errors,
        // but in this specific case, the user should know → send a warning
        if (status == PythonHotPlugActionExtension::PythonCallStatus::NOT_A_FUNCTION) {
            CAMITK_ERROR_ALT("Error during call to method process() of action '" + getName() + "': " + "Python script '" + getPythonName() + ".py" + "' has symbol 'process' but it is not a function. Expecting 'def process(self:camitk.Action):'");
        }
        else {
            if (status == PythonHotPlugActionExtension::PythonCallStatus::MISSING_FUNCTION) {
                CAMITK_ERROR_ALT("Error during call to method process() of action '" + getName() + "': " + "Python script '" + getPythonName() + ".py" + "' missing function 'process(self)'. Expecting 'def process(self:camitk.Action):'");
            }
        }
    }

    // restore normal cursor
    QApplication::restoreOverrideCursor();

    return applyStatus;
}

// ---------------------- parameterChangedEvent ----------------------------
void PythonHotPlugAction::parameterChangedEvent(QString parameterName) {
    // this won't generate an error when the parameterChanged() method is missing in the python script (only an info message)
    pythonExtension->callPython(this, "parameterChanged", parameterName);
}

} // namespace camitk

#endif // PYTHON_BINDING