/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2024 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$
 ****************************************************************************/

// Local
#include "ShowFrame.h"

#include <ActionWidget.h>
#include <Property.h>
#include <InteractiveGeometryViewer.h>

using namespace camitk;

// --------------- constructor -------------------
ShowFrame::ShowFrame(ActionExtension* extension) : Action(extension) {
    setName("Show Frame");
    setDescription(tr("Show/Hide the 3D axes representation of the selected component's frame, i.e., it's local coordinate system."));
    setComponentClassName("Component");

    // Setting classification family and tags
    setFamily("View");
    addTag(tr("Frame"));
    addTag(tr("Coordinates"));
    addTag(tr("Visualization"));

    comp = nullptr;
    addParameter(new Property(tr("Show Frame"), true,
                              tr("Show/Hide the component frame in the 3D viewer"), ""));

    Property* frameSize = new Property(tr("Frame Size (%)"), 10,
                                       tr("Size of the frame in percentage of the image size"), "");
    frameSize->setAttribute("minimum", 1);
    frameSize->setAttribute("maximum", 100);
    frameSize->setAttribute("singleStep", 1);
    addParameter(frameSize);

    setAutoUpdateProperties(true);
}

// --------------- getWidget -------------------
QWidget* ShowFrame::getWidget() {
    // invert only if the component has changed and the widget was already visible or it is the first time the widget is shown
    bool invert = (Action::getWidget()->isVisible() && comp == getTargets().last()) || comp == nullptr;

    // update the frame visibility depending on getTargets().last();
    comp = getTargets().last();

    // when the QAction is clicked and widget is shown → automatically invert the visibility
    double frameSize = getFrameSize();
    comp->getFrameAxisActor()->SetTotalLength(frameSize, frameSize, frameSize);
    bool currentVisibility = comp->getFrameVisibility("3D Viewer");
    if (invert) {
        currentVisibility = !currentVisibility;
    }
    comp->setFrameVisibility("3D Viewer", currentVisibility);
    blockAutoUpdate = true;
    setProperty("Show Frame", currentVisibility);
    blockAutoUpdate = false;
    // force refresh of the 3D viewer only
    InteractiveGeometryViewer* default3DViewer = dynamic_cast<InteractiveGeometryViewer*>(Application::getViewer("3D Viewer"));
    if (default3DViewer != nullptr) {
        default3DViewer->refresh();
    }

    // hide the apply button as this action has autoUpdateProperties set to true
    dynamic_cast<ActionWidget*>(Action::getWidget())->setButtonVisibility(false);

    return Action::getWidget();
}

// ---------------------- event ----------------------------
bool ShowFrame::event(QEvent* e) {
    if (!blockAutoUpdate && comp != nullptr && e->type() == QEvent::DynamicPropertyChange) {
        e->accept();
        QDynamicPropertyChangeEvent* changeEvent = dynamic_cast<QDynamicPropertyChangeEvent*>(e);

        if (!changeEvent) {
            return false;
        }

        double frameSize = getFrameSize();
        comp->getFrameAxisActor()->SetTotalLength(frameSize, frameSize, frameSize);
        comp->setFrameVisibility("3D Viewer", property("Show Frame").toBool());
        Application::refresh();

        return true;
    }

    // this is important to continue the process if the event is a different one
    return QObject::event(e);
}

// --------------- getFrameSize -------------------
double ShowFrame::getFrameSize() {
    double percentage = property("Frame Size (%)").toDouble() / 100.0;
    double boundingDim = 1.0;

    InteractiveGeometryViewer* default3DViewer = dynamic_cast<InteractiveGeometryViewer*>(Application::getViewer("3D Viewer"));

    if (default3DViewer != nullptr) {
        double sceneBounds[6];
        default3DViewer->getBoundsOfSelected(sceneBounds);
        boundingDim = sqrt(pow(sceneBounds[1] - sceneBounds[0], 2.0) + pow(sceneBounds[3] - sceneBounds[2], 2.0) + pow(sceneBounds[5] - sceneBounds[4], 2.0));
    }

    return percentage * boundingDim;
}

// -------------------- getQAction --------------------
QAction* ShowFrame::getQAction(Component* target) {
    QAction* myQAction = Action::getQAction();
    if (target != nullptr) {
        // make sure the status is visible
        myQAction->setEnabled(true);
        myQAction->setCheckable(true);
        // update visibility GUI
        myQAction->setChecked(target->getFrameVisibility("3D Viewer"));
    }

    return myQAction;
}

// --------------- apply -------------------
Action::ApplyStatus ShowFrame::apply() {
    return SUCCESS;
}

