/*****************************************************************************
 * $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 "EditAnatomicalInformation.h"

// CamiTK includes
#include <Property.h>
#include <ActionWidget.h>
#include <TransformationManager.h>
#include <Log.h>







// This action process ImageComponent, include is required
#include <ImageComponent.h>
#include <TransformationExplorer.h>


using namespace camitk;

// -------------------- init --------------------
void EditAnatomicalInformation::init() {
    // Add initialization if required
    //
    // Note: use the "classMembers" field of the Edit Anatomical Information action in
    // the .camitk JSON file to declare additional private,
    // public, or signal/slot members.
    TransformationExplorer* transfoExplorer = dynamic_cast<TransformationExplorer*>(Application::getViewer("Transformation Explorer"));
    if (transfoExplorer != nullptr) {
        connect(transfoExplorer, &TransformationExplorer::currentFrameChanged, this, &EditAnatomicalInformation::setCurrentFrame);
    }
    currentFrame = nullptr;
    myWidget = nullptr;
}

// -------------------- setCurrentFrame --------------------
void EditAnatomicalInformation::setCurrentFrame(const FrameOfReference* fr) {
    currentFrame = fr;

    if (myWidget == nullptr) { // In case this is called by a connect before UI init
        return;
    }

    if (currentFrame == nullptr) {
        // Disable the UI
        updateUiContent();
        return;
    }

    anatomicalOrientation = fr->getAnatomicalOrientation();
    if (anatomicalOrientation.isUnknown()) { // Unknown orientation
        setParameterValue("Orientation", 0);
    }
    else if (anatomicalOrientation.get3LetterCode() != "") { // Three-letter code (e.g. RAI)
        QStringList orientationEnumValues = getProperty("Orientation")->getAttribute("enumNames").toStringList();
        if (orientationEnumValues.contains(anatomicalOrientation.get3LetterCode())) {
            setParameterValue("Orientation", orientationEnumValues.indexOf(anatomicalOrientation.get3LetterCode()));
        }
    }
    else { // Custom orientation
        setParameterValue("Orientation", 1);
    }
    // Hide Component-related UI
    ui.componentLabel->setVisible(false);
    ui.imageFrameChoiceCombo->setVisible(false);
    updateUiContent();
}

// -------------------- updateUiContent --------------------
void EditAnatomicalInformation::updateUiContent() {
    blockSignals(true);
    if (currentFrame == nullptr) {
        ui.nameEdit->setDisabled(true);
        ui.orientationCombo->setDisabled(true);
        ui.xMinEdit->setDisabled(true);
        ui.yMinEdit->setDisabled(true);
        ui.zMinEdit->setDisabled(true);
        ui.xMaxEdit->setDisabled(true);
        ui.yMaxEdit->setDisabled(true);
        ui.zMaxEdit->setDisabled(true);
        ui.imageFrameChoiceCombo->setVisible(false);
        ui.nameEdit->setToolTip("");
    }
    else {
        ui.nameEdit->setDisabled(false);
        ui.orientationCombo->setDisabled(false);

        ui.orientationCombo->blockSignals(true);
        // Update UI content
        ui.nameEdit->setText(currentFrame->getName());
        ui.nameEdit->setToolTip("Uuid: <i>" + currentFrame->getUuid().toString() + "</i>");
        if (anatomicalOrientation.isUnknown()) { // Unknown
            ui.orientationCombo->setCurrentIndex(0);
            ui.xMinEdit->setDisabled(true);
            ui.yMinEdit->setDisabled(true);
            ui.zMinEdit->setDisabled(true);
            ui.xMaxEdit->setDisabled(true);
            ui.yMaxEdit->setDisabled(true);
            ui.zMaxEdit->setDisabled(true);
            ui.xMinEdit->setText("min X");
            ui.yMinEdit->setText("min Y");
            ui.zMinEdit->setText("min Z");
            ui.xMaxEdit->setText("max X");
            ui.yMaxEdit->setText("max Y");
            ui.zMaxEdit->setText("max Z");
        }
        else if (anatomicalOrientation.get3LetterCode().isEmpty()) { // custom
            ui.orientationCombo->setCurrentIndex(1);
            ui.xMinEdit->setDisabled(false);
            ui.yMinEdit->setDisabled(false);
            ui.zMinEdit->setDisabled(false);
            ui.xMaxEdit->setDisabled(false);
            ui.yMaxEdit->setDisabled(false);
            ui.zMaxEdit->setDisabled(false);
            ui.xMinEdit->setText(anatomicalOrientation.getMinLabel(0));
            ui.yMinEdit->setText(anatomicalOrientation.getMinLabel(1));
            ui.zMinEdit->setText(anatomicalOrientation.getMinLabel(2));
            ui.xMaxEdit->setText(anatomicalOrientation.getMaxLabel(0));
            ui.yMaxEdit->setText(anatomicalOrientation.getMaxLabel(1));
            ui.zMaxEdit->setText(anatomicalOrientation.getMaxLabel(2));
        }
        else { // three-letter code
            ui.orientationCombo->setCurrentText(anatomicalOrientation.get3LetterCode());
            ui.xMinEdit->setDisabled(true);
            ui.yMinEdit->setDisabled(true);
            ui.zMinEdit->setDisabled(true);
            ui.xMaxEdit->setDisabled(true);
            ui.yMaxEdit->setDisabled(true);
            ui.zMaxEdit->setDisabled(true);
            ui.xMinEdit->setText(anatomicalOrientation.getMinLabel(0));
            ui.yMinEdit->setText(anatomicalOrientation.getMinLabel(1));
            ui.zMinEdit->setText(anatomicalOrientation.getMinLabel(2));
            ui.xMaxEdit->setText(anatomicalOrientation.getMaxLabel(0));
            ui.yMaxEdit->setText(anatomicalOrientation.getMaxLabel(1));
            ui.zMaxEdit->setText(anatomicalOrientation.getMaxLabel(2));
        }
        ui.orientationCombo->blockSignals(false);
    }
    blockSignals(false);
}

// -------------------- process --------------------
Action::ApplyStatus EditAnatomicalInformation::process() {

    // Apply the orientation
    // Get an owning pointer for the selected Frame (make sure it is still valid)
    std::shared_ptr<FrameOfReference> frame = TransformationManager::getFrameOfReferenceOwnership(currentFrame);

    if (frame != nullptr) {
        // Get new values from the UI
        if (ui.orientationCombo->currentText() == "Custom") {
            anatomicalOrientation.setLabels(0, ui.xMinEdit->text(), ui.xMaxEdit->text());
            anatomicalOrientation.setLabels(1, ui.yMinEdit->text(), ui.yMaxEdit->text());
            anatomicalOrientation.setLabels(2, ui.zMinEdit->text(), ui.zMaxEdit->text());
        }
        frame->setAnatomicalOrientation(anatomicalOrientation);
        frame->setName(ui.nameEdit->text());
        refreshApplication();
        return SUCCESS;
    }
    else {
        return Action::ERROR;
    }

}

// -------------------- targetDefined --------------------
void EditAnatomicalInformation::targetDefined() {
    if (getTargets().isEmpty()) {
        return;
    }
    Component* target = getTargets().last();
    if (target == nullptr) {
        return;
    }
    if (dynamic_cast<ImageComponent*>(target) == nullptr) {
        setParameterValue("Data Image Frame", false);
        setCurrentFrame(target->getFrame());
    }
    else {
        setParameterValue("Data Image Frame", true);
        setCurrentFrame(dynamic_cast<ImageComponent*>(target)->getDataFrame());

        ui.imageFrameChoiceCombo->setCurrentIndex(0); // Content is "Data Frame"
        ui.imageFrameChoiceCombo->setVisible(true);

    }
    ui.componentLabel->setText(target->getName());
    ui.componentLabel->setVisible(true);
}

// -------------------- parameterChanged --------------------
void EditAnatomicalInformation::parameterChanged(QString parameterName) {

}

// -------------------- getUI --------------------
QWidget* EditAnatomicalInformation::getUI() {
    // Instantiate and manage the custom GUI from file SetAnatomicalTransformation.ui
    if (myWidget == nullptr) {
        myWidget = new QWidget();
        ui.setupUi(myWidget);
        // Init values
        ui.orientationCombo->addItems(getProperty("Orientation")->getAttribute("enumNames").toStringList());

        // Connect widgets
        connect(ui.applyButton, &QPushButton::clicked, this, &EditAnatomicalInformation::process);
        connect(ui.resetButton, &QPushButton::clicked, [&]() {
            if (currentFrame != nullptr) {
                anatomicalOrientation = currentFrame->getAnatomicalOrientation();
                updateUiContent();
            }
        });
        connect(ui.orientationCombo, &QComboBox::currentTextChanged, [&](QString orientationName) {
            if (orientationName == "Unknown") { // Empty the current label
                anatomicalOrientation.setUnkown();
            }
            else if (orientationName == "Custom") { // Fill the label text with "Custom"
                anatomicalOrientation.setLabels(0, "low X", "high X");
                anatomicalOrientation.setLabels(1, "low Y", "high Y");
                anatomicalOrientation.setLabels(2, "low Z", "high Z");
            }
            else { // Fill the label text from the selected 3-letter code
                anatomicalOrientation.setOrientation(orientationName);
            }
            updateUiContent();
        });
        // Disable the UI after creating it
        currentFrame = nullptr;
        updateUiContent();
    }

    return myWidget;
}
