/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2018 Univ. Grenoble Alpes, CNRS, TIMC-IMAG UMR 5525 (GMCAO)
 *
 * 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$
 ****************************************************************************/


// -- Application Fancy stuff
#include "FancyMainWindow.h"

#include <Application.h>
#include <ImageComponent.h>

// -- Qt stuff
#include <SliderSpinBoxWidget.h>
#include <QFrame>
#include <QLayout>
#include <QStackedLayout>
#include <QToolBar>

// ------------- constructor -----------------
FancyMainWindow::FancyMainWindow() : MainWindow("Fancy") {
    mainWidget = new QWidget;
    ui.setupUi(mainWidget);

    //-- actions of the File menu
    ui.openButton->setIcon(QPixmap(":/fileOpen"));
    ui.openButton->setShortcut(QKeySequence::Open);
    ui.dial->show();

    // add the medical image viewer
    visibility = MedicalImageViewer::VIEWER_AXIAL;
    ui.viewer->addWidget(MedicalImageViewer::getInstance()->getWidget(this));
    // hide slide bar and modify the color and background
    InteractiveViewer::getAxialViewer()->setSideFrameVisible(false);
    InteractiveViewer::getAxialViewer()->setGradientBackground(false);
    InteractiveViewer::getAxialViewer()->setBackgroundColor(ui.dial->palette().background().color());
    InteractiveViewer::getSagittalViewer()->setSideFrameVisible(false);
    InteractiveViewer::getSagittalViewer()->setGradientBackground(false);
    InteractiveViewer::getSagittalViewer()->setBackgroundColor(ui.dial->palette().background().color());
    InteractiveViewer::getCoronalViewer()->setSideFrameVisible(false);
    InteractiveViewer::getCoronalViewer()->setGradientBackground(false);
    InteractiveViewer::getCoronalViewer()->setBackgroundColor(ui.dial->palette().background().color());
    InteractiveViewer::getArbitraryViewer()->setSideFrameVisible(false);
    InteractiveViewer::getArbitraryViewer()->setGradientBackground(false);
    InteractiveViewer::getArbitraryViewer()->setBackgroundColor(ui.dial->palette().background().color());

    // add the 3D small little viewer
    viewer3D = InteractiveViewer::getNewViewer("Fancy 3D Viewer", camitk::InteractiveViewer::GEOMETRY_VIEWER);
    ui.viewer3DLayout->addWidget(viewer3D->getWidget(this));
    viewer3D->setSideFrameVisible(false);
    viewer3D->setGradientBackground(false);
    viewer3D->setBackgroundColor(ui.dial->palette().background().color());
    viewer3D->getToolBar()->hide();

    updateAngleSlider(ui.xAngledial, ui.xAngleValue);
    updateAngleSlider(ui.yAngledial, ui.yAngleValue);
    updateAngleSlider(ui.zAngledial, ui.zAngleValue);
    showAngleDials(false);

    connect(ui.openButton, SIGNAL(clicked()), this, SLOT(fancyFileOpen()));
    connect(ui.axial, SIGNAL(clicked()), this, SLOT(layoutChanged()));
    connect(ui.coronal, SIGNAL(clicked()), this, SLOT(layoutChanged()));
    connect(ui.saggital, SIGNAL(clicked()), this, SLOT(layoutChanged()));
    connect(ui.abstract, SIGNAL(clicked()), this, SLOT(layoutChanged()));
    connect(ui.xAngledial, SIGNAL(valueChanged(int)), this, SLOT(xAngleDialValueChanged(int)));
    connect(ui.yAngledial, SIGNAL(valueChanged(int)), this, SLOT(yAngleDialValueChanged(int)));
    connect(ui.zAngledial, SIGNAL(valueChanged(int)), this, SLOT(zAngleDialValueChanged(int)));
    connect(ui.dial, SIGNAL(valueChanged(int)), this, SLOT(dialValueChanged(int)));

    layoutChanged();

    setCentralWidget(mainWidget);
}

// ------------- destructor -----------------
FancyMainWindow::~FancyMainWindow() {
    delete mainWidget;
}

// ------------- fancyFileOpen -----------------
void FancyMainWindow::fancyFileOpen() {
    Application::getAction("Close All")->trigger(this);
    Application::getAction("Open")->trigger(this);
    refresh();
}

// -------------------- updateAngleSlider --------------------
void FancyMainWindow::updateAngleSlider(QDial* dial, QLabel* label) {
    dial->blockSignals(true);
    dial->setMinimum(0);
    dial->setMaximum(360);
    dial->blockSignals(false);

    if (label == ui.xAngleValue) {
        label->setText("X : <tt>" + QString("%1").arg(dial->value(), 3) + "</tt>" + 0x00B0);
    }
    else if (label == ui.yAngleValue) {
        label->setText("Y : <tt>" + QString("%1").arg(dial->value(), 3) + "</tt>" + 0x00B0);
    }
    else if (label == ui.zAngleValue) {
        label->setText("Z : <tt>" + QString("%1").arg(dial->value(), 3) + "</tt>" + 0x00B0);
    }

    label->update();
}

// -------------------- updateDialSlider --------------------
void FancyMainWindow::updateDialSlider() {
    int currentSliceId, minSliceId, maxSliceId;
    currentSliceId = minSliceId = maxSliceId = 0;

    if (visibility == MedicalImageViewer::VIEWER_ARBITRARY) {
        currentSliceId = ui.dial->value();
        minSliceId = 0;
        maxSliceId = 360;
    }
    else {
        Component* comp = NULL;

        if (Application::getTopLevelComponents().size() > 0) {
            ImageComponent* comp = dynamic_cast<ImageComponent*>(Application::getTopLevelComponents().last());

            if (comp) {
                if (visibility == MedicalImageViewer::VIEWER_AXIAL) {
                    currentSliceId = comp->getAxialSlices()->getSlice();
                    maxSliceId = comp->getAxialSlices()->getNumberOfSlices();
                }
                else if (visibility == MedicalImageViewer::VIEWER_CORONAL) {
                    currentSliceId = comp->getCoronalSlices()->getSlice();
                    maxSliceId = comp->getCoronalSlices()->getNumberOfSlices();
                }
                else {
                    currentSliceId = comp->getSagittalSlices()->getSlice();
                    maxSliceId = comp->getSagittalSlices()->getNumberOfSlices();
                }
            }
        }
    }

    ui.dial->blockSignals(true);
    ui.dial->setMinimum(minSliceId);
    ui.dial->setMaximum(maxSliceId);
    ui.dial->setValue(currentSliceId);
    ui.dial->blockSignals(false);

    ui.slideValue->setText(QString("%1").arg((currentSliceId + 1), 3) + "/" + QString("%1").arg(maxSliceId, 3));
    ui.slideValue->update();
}

// -------------------- showAngleDials --------------------
void FancyMainWindow::showAngleDials(bool isShown) {
    ui.xAngledial->setVisible(isShown);
    ui.xAngleValue->setVisible(isShown);
    ui.yAngledial->setVisible(isShown);
    ui.yAngleValue->setVisible(isShown);
    ui.zAngledial->setVisible(isShown);
    ui.zAngleValue->setVisible(isShown);
}

// -------------------- layoutChanged --------------------
void FancyMainWindow::layoutChanged() {
    if (ui.axial->isChecked()) {
        visibility = MedicalImageViewer::VIEWER_AXIAL;
    }
    else if (ui.saggital->isChecked()) {
        visibility = MedicalImageViewer::VIEWER_SAGITTAL;
    }
    else if (ui.coronal->isChecked()) {
        visibility = MedicalImageViewer::VIEWER_CORONAL;
    }
    else {
        visibility = MedicalImageViewer::VIEWER_ARBITRARY;
    }

    MedicalImageViewer::getInstance()->setVisibleViewer(visibility);

    ui.dial->show();
    ui.slideValue->show();

    showAngleDials(visibility == MedicalImageViewer::VIEWER_ARBITRARY);
    refresh();
}

// -------------------- xAngleDialValueChanged --------------------
void FancyMainWindow::xAngleDialValueChanged(int value) {
    InteractiveViewer::getArbitraryViewer()->xAngleChanged(value);
    updateAngleSlider(ui.xAngledial, ui.xAngleValue);
    refresh();
}

// -------------------- yAngleDialValueChanged --------------------
void FancyMainWindow::yAngleDialValueChanged(int value) {
    InteractiveViewer::getArbitraryViewer()->yAngleChanged(value);
    updateAngleSlider(ui.yAngledial, ui.yAngleValue);
    refresh();
}

// -------------------- zAngleDialValueChanged --------------------
void FancyMainWindow::zAngleDialValueChanged(int value) {
    InteractiveViewer::getArbitraryViewer()->zAngleChanged(value);
    updateAngleSlider(ui.zAngledial, ui.zAngleValue);
    refresh();
}

// -------------------- dialValueChanged --------------------
void FancyMainWindow::dialValueChanged(int value) {
    getVisibleViewer()->sliderChanged(value);
    updateDialSlider();
    refresh();
}

// -------------------- refreshView --------------------
void FancyMainWindow::refresh() {
    getVisibleViewer()->refresh();

    // force visualization of arbitrary slice in 3D
    if (Application::getTopLevelComponents().size() > 0) {
        ImageComponent* comp = dynamic_cast<ImageComponent*>(Application::getTopLevelComponents().last());

        if (comp) {
            comp->getAxialSlices()->setVisibility(viewer3D, true);
            comp->getSagittalSlices()->setVisibility(viewer3D, true);
            comp->getCoronalSlices()->setVisibility(viewer3D, true);
            comp->getArbitrarySlices()->setVisibility(viewer3D, true);
        }
    }

    viewer3D->refresh();
    updateDialSlider();
}

// -------------------- getVisibleViewer --------------------
InteractiveViewer* FancyMainWindow::getVisibleViewer() {
    InteractiveViewer* visibleViewer = NULL;
    switch (visibility) {
        case MedicalImageViewer::VIEWER_AXIAL:
            visibleViewer = InteractiveViewer::getAxialViewer();
            break;
        case MedicalImageViewer::VIEWER_CORONAL:
            visibleViewer = InteractiveViewer::getCoronalViewer();
            break;
        case MedicalImageViewer::VIEWER_SAGITTAL:
            visibleViewer = InteractiveViewer::getSagittalViewer();
            break;
        default: // arbitrary (and... 3D!)
            visibleViewer = InteractiveViewer::getArbitraryViewer();
            break;
    }
    return visibleViewer;
}
