/*****************************************************************************
 * $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 "ImagePicking.h"
#include <ImageComponent.h>
#include <Application.h>
#include <InteractiveSliceViewer.h>
#include <Log.h>
using namespace camitk;

// Qt
#include <QPushButton>
#include <QVBoxLayout>

// -------------------- ImagePicking --------------------
ImagePicking::ImagePicking(ActionExtension* extension) : Action(extension) {
    setName("Basic Image Picking");
    // NOTE try to call setEmbedded(false) to see the difference
    setDescription("Tutorial action that retrieve pixel information from the image");
    setComponentClassName("ImageComponent");

    setFamily("Tutorial");
    addTag("Picking");
    addTag("Image Processing");

    //-- widget lazy instantiation
    informationFrame = nullptr;
    isConnected = false;
}

// --------------- getWidget -------------------
QWidget* ImagePicking::getWidget() {
    if (!informationFrame) {
        //-- the frame
        informationFrame = new QFrame();
        informationFrame->setFrameShape(QFrame::StyledPanel);
        informationFrame->setFrameShadow(QFrame::Sunken);
        informationFrame->setLineWidth(3);

        //-- the information label
        informationLabel = new QLabel();
        informationLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);

        //-- the vertical layout, put every GUI elements in it
        auto* informationFrameLayout = new QVBoxLayout();
        informationFrameLayout->addWidget(informationLabel);

        //-- set the layout for the action widget
        informationFrame->setLayout(informationFrameLayout);

    }

    CAMITK_TRACE("Connecting viewers signals to automatically apply this action at each user picking")
    if (!isConnected && Application::getViewer("Axial Viewer") != nullptr) {
        //-- run the action every time a picking is done in the axial/sagittal or coronal planes
        QObject::connect(Application::getViewer("Axial Viewer"), SIGNAL(selectionChanged()), this, SLOT(apply()));
        QObject::connect(Application::getViewer("Coronal Viewer"), SIGNAL(selectionChanged()), this, SLOT(apply()));
        QObject::connect(Application::getViewer("Sagittal Viewer"), SIGNAL(selectionChanged()), this, SLOT(apply()));
        isConnected = true;
    }

    return informationFrame;
}

// --------------- apply -------------------
Action::ApplyStatus ImagePicking::apply() {

    if (informationFrame != nullptr) {
        // set waiting cursor (not really needed here as the action is very fast, but after all this is a demo)
        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
    }

    // get the last selected image component
    ImageComponent* imageComponent = dynamic_cast<ImageComponent*>(getTargets().last());
    // NOTE it is not needed to check for nullptr pointer after this dynamic_cast: this action
    // has declared to be able to process ImageComponent (see the setComponent(..) in the constructor),
    // therefore it is only called using getTargets() that are compatible with ImageComponent

    // get the last picked pixel index
    int i, j, k;
    imageComponent->getLastPixelPicked(&i, &j, &k);

    // check validity
    if (i != -1 && j != -1 && k != -1) {
        // retrieve information
        double pixelValue;
        pixelValue = imageComponent->getImageData()->GetScalarComponentAsDouble(i, j, k, 0);
        // Retrieve coordinates in data frame and world frame
        double x, y, z;
        imageComponent->getLastPointPickedDataFrame(&x, &y, &z);
        double xw, yw, zw;
        imageComponent->getLastPointPickedWorldFrame(&xw, &yw, &zw);

        // NOTE if this was a colored image, this would be the red value (the last parameter
        // of GetScalarComponentAsDouble is the index of the color component)

        // update the information label
        if (informationFrame != nullptr) {
            informationLabel->setText("<b>Selected Component:</b> " + imageComponent->getName() + "<br/>"
                                      + "<b>Pixel coordinates:</b> (" + QString("%1").arg(i, 3) + ","
                                      + QString("%1").arg(j, 3) + "," + QString("%1").arg(k, 3) + ")<br/>"
                                      + "<b>Coordinates (Data Frame):</b> (" + QString("%1").arg(x, 3) + ","
                                      + QString("%1").arg(y, 3) + "," + QString("%1").arg(z, 3) + ")<br/>"
                                      + "<b>Coordinates (World Frame):</b> (" + QString("%1").arg(xw, 3) + ","
                                      + QString("%1").arg(yw, 3) + "," + QString("%1").arg(zw, 3) + ")<br/>"
                                      + "<b>Pixel value:</b> " + QString("%1").arg(pixelValue, 5)
                                     );
        }
        else {
            // or just print it out if there is no widget
            CAMITK_INFO(tr("Selected Component: \"%1\"\n"
                           "- Pixel coordinates: (%2,%3,%4)\n"
                           "- Pixel value: %5").arg(imageComponent->getName(), QString::number(i), QString::number(j), QString::number(k), QString::number(pixelValue)))
        }

    }

    if (informationFrame != nullptr) {
        if (informationFrame->isVisible()) {
            // restore the normal cursor
            QApplication::restoreOverrideCursor();
        }
        else {
            // disconnect
            CAMITK_TRACE("Disconnecting viewers signals.")
            if (Application::getViewer("Axial Viewer") != nullptr) {
                //-- disconnect the automatic run of the action every time a picking is done in the axial/sagittal or coronal planes
                QObject::disconnect(Application::getViewer("Axial Viewer"), SIGNAL(selectionChanged()), this, SLOT(apply()));
                QObject::disconnect(Application::getViewer("Coronal Viewer"), SIGNAL(selectionChanged()), this, SLOT(apply()));
                QObject::disconnect(Application::getViewer("Sagittal Viewer"), SIGNAL(selectionChanged()), this, SLOT(apply()));
                isConnected = false;
            }
        }
    }
    return SUCCESS;
}
