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

#include <MedicalImageViewer.h>
#include <RendererWidget.h>
#include <InteractiveGeometryViewer.h>
#include <Property.h>
#include <Application.h>
#include <SingleImageComponent.h>
#include <Log.h>

using namespace camitk;

// --------------- Constructor -------------------
WorkingWhenSleepingRandom::WorkingWhenSleepingRandom(ActionExtension* extension) : Action(extension) {
    numberOfWindow = 300;
    // Setting name, description and input component
    setName("Working When Sleeping (Random)");
    setDescription("This action generates a random exploration of slice sagittal, coronal and axial viewers.");
    setComponentClassName("ImageComponent");

    // Setting classification family and tags
    setFamily("Tutorial");
    addTag("Working When Sleeping");

    // Setting the action's parameters
    addParameter(new Property("Random Maximum Step", 3, tr("Max Degree of rotation."), "degree"));
    addParameter(new Property("Number Of Steps", numberOfWindow, tr("Number of change steps."), ""));
}

// --------------- destructor -------------------
WorkingWhenSleepingRandom::~WorkingWhenSleepingRandom() {
    // Do not do anything yet.
    // Delete stuff if you create stuff
    // (except if you use smart pointers of course !!)
}

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

    for (Component* comp : getTargets()) {
        ImageComponent* input = dynamic_cast<ImageComponent*>(comp);
        process(input);
    }

    return SUCCESS;
}

void WorkingWhenSleepingRandom::process(ImageComponent* comp) {
    // Get the parameters
    int randomMaximumStep = property("Random Maximum Step").toInt();
    numberOfWindow = property("Number Of Steps").toInt();
    // Getting the input image
    vtkSmartPointer<vtkImageData> inputImage  = comp->getImageData();
    int dims[3];
    inputImage->GetDimensions(dims);

    // Getting the Viewer
    MedicalImageViewer* myMedicalImageViewer = dynamic_cast<MedicalImageViewer*>(Application::getViewer("Medical Image Viewer"));
    if (myMedicalImageViewer != nullptr) {
        myMedicalImageViewer->setVisibleViewer(MedicalImageViewer::VIEWER_ALL);
    }
    else {
        CAMITK_WARNING(tr("Cannot find \"Medical Image Viewer\". This viewer is mandatory for running this action."))
        return;
    }

    // Getting the Camera of the 3DViewer
    RendererWidget* myRendererWidget = dynamic_cast<InteractiveGeometryViewer*>(Application::getViewer("3D Viewer"))->getRendererWidget();
    vtkCamera* myCamera = myRendererWidget->getActiveCamera();

    // Getting the three images slices
    SingleImageComponent* mySingleImageComponent[3] = {comp->getSagittalSlices(), comp->getCoronalSlices(), comp->getAxialSlices()};

    int currentSlice[3] = {0, 0, 0};

    for (unsigned int n = 0; n < (unsigned) numberOfWindow; n++) {
        // modify 3DViewer Camera
        myRendererWidget->rotateCamera(abs(rand()) % (randomMaximumStep + 1), 0);
        myRendererWidget->setActiveCamera(myCamera);
        myRendererWidget->refresh();

        // modify the current sagittal, coronal, axial slices
        for (unsigned int i = 0; i < 3; i++) {
            if (mySingleImageComponent[i] != nullptr) {
                mySingleImageComponent[i]->setSlice((currentSlice[i] += abs(rand()) % (randomMaximumStep + 1)) % dims[i]);
                mySingleImageComponent[i]->refresh();
            }
        }

        camitk::Application::setProgressBarValue(100 * n / numberOfWindow);

        // Refresh the Viewers ....
        myMedicalImageViewer->refresh();
        // In order to see the change in the viewers, the initial idea was to call
        // Application::processEvents();
        // but, as explained in the Qt documentation:
        // > In the event that you are running a local loop which calls this function continuously,
        // > without an event loop, the DeferredDelete events will not be processed. This can affect
        // > the behaviour of widgets, e.g. QToolTip, that rely on DeferredDelete events to function
        // > properly. An alternative would be to call sendPostedEvents() from within that local loop.
        Application::sendPostedEvents();
    }
}


