#include <QMessageBox>
#include <QScreen>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QSlider>
#include <QCheckBox>
#include <QSpinBox>
#include <QDesktopWidget>
#include <Q3DInputHandler>
#include <QCustom3DLabel>

#include "QFitsView3D.h"
#include "QFitsWidget3D.h"
#include "QFitsMainWindow.h"
#include "QFitsViewingTools.h"
#include "QFitsSingleBuffer.h"
#include "QFitsCubeSpectrum.h"
#include "fits.h"

static bool isOpenGLES()
{
#if defined(QT_OPENGL_ES_2)
    return true;
#elif (QT_VERSION < QT_VERSION_CHECK(5, 3, 0))
    return false;
#else
    return QOpenGLContext::currentContext()->isOpenGLES();
#endif
}

//------------------------------------------------------------------------------
//         QFits3DScatter
//------------------------------------------------------------------------------
QFits3DScatter::QFits3DScatter() : Q3DScatter() {
}

void QFits3DScatter::mouseMoveEvent(QMouseEvent *e) {
    if (e->buttons() != Qt::RightButton) {
        emit setBrightnessContrast(e);
    } else {
        Q3DScatter::mouseMoveEvent(e);
    }
}

//------------------------------------------------------------------------------
//         QFitsView3D
//------------------------------------------------------------------------------
QFitsView3D::QFitsView3D(QFitsWidget3D *parent)
    : QFitsBaseView(parent),
      myParent(parent),
      scatterWindow(NULL),
      m_volume(NULL),
      m_slicingX(false),
      m_slicingY(false),
      m_slicingZ(false),
      m_sliceSliderX(NULL),
      m_sliceSliderY(NULL),
      m_sliceSliderZ(NULL),
      m_sliceImageX(NULL),
      m_sliceImageY(NULL),
      m_sliceImageZ(NULL)
{
    ;

    //
    // setup 3D-Scatter (QWindow)
    //
    scatterWindow = new QFits3DScatter();
    if (!scatterWindow->hasContext()) {
        QMessageBox msgBox;
        msgBox.setText("Couldn't initialize the OpenGL context.");
        msgBox.exec();
        // how to implementd return -1 ?
    }

    scatterWindow->activeTheme()->setType(Q3DTheme::ThemeStoneMoss);
//    scatterWindow->activeTheme()->setGridEnabled(false);
    scatterWindow->setShadowQuality(QAbstract3DGraph::ShadowQualityNone);
    scatterWindow->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetIsometricRight);
    scatterWindow->setOrthoProjection(true);
    scatterWindow->activeTheme()->setBackgroundEnabled(false);

    // Only allow zooming at the center and limit the zoom to 200% to avoid clipping issues
    static_cast<Q3DInputHandler *>(scatterWindow->activeInputHandler())->setZoomAtTargetEnabled(false);
    scatterWindow->scene()->activeCamera()->setMaxZoomLevel(200.0f);

    if (!isOpenGLES()) {
        scatterWindow->axisX()->setSegmentCount(5);
        scatterWindow->axisY()->setSegmentCount(5);
        scatterWindow->axisZ()->setSegmentCount(5);
        m_volume = new QCustom3DVolume;
        m_volume->setScalingAbsolute(false);

        m_volume->setSliceFrameGaps(QVector3D(0.01f, 0.01f, 0.01f));
        m_volume->setSliceFrameThicknesses(QVector3D(0.0025f, 0.0025f, 0.0025f));
        m_volume->setSliceFrameWidths(QVector3D(0.0025f, 0.0025f, 0.0025f));
        m_volume->setDrawSliceFrames(false);

        handleSlicingChanges();

        scatterWindow->addCustomItem(m_volume);
    } else {
        // OpenGL ES2 doesn't support 3D textures, so show a warning label instead
        QCustom3DLabel *warningLabel = new QCustom3DLabel(
                    "QCustom3DVolume is not supported with OpenGL ES2",
                    QFont(),
                    QVector3D(0.0f, 0.5f, 0.0f),
                    QVector3D(1.5f, 1.5f, 0.0f),
                    QQuaternion());
        warningLabel->setPositionAbsolute(true);
        warningLabel->setFacingCamera(true);
        scatterWindow->addCustomItem(warningLabel);
    }

    //
    // setup 3D-Scatter (QWidget)
    //
    QWidget *scatterWidget = QWidget::createWindowContainer(scatterWindow);

    //
    //Layout
    //
    QSize screenSize = scatterWindow->screen()->size();
    scatterWidget->setMaximumSize(screenSize);
    scatterWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    scatterWidget->setFocusPolicy(Qt::StrongFocus);

    QHBoxLayout *hLayout = new QHBoxLayout(this);
    hLayout->setContentsMargins(0, 0, 0, 0);
    QVBoxLayout *vLayoutLeft  = new QVBoxLayout(),
                *vLayoutRight = new QVBoxLayout();
    hLayout->addWidget(scatterWidget, 1);
    hLayout->addLayout(vLayoutLeft);
    hLayout->addLayout(vLayoutRight);

    QWidget *xWidget = new QWidget();
    QCheckBox *sliceXCheckBox = new QCheckBox(xWidget);
    sliceXCheckBox->setText(QStringLiteral("Slice X"));
    sliceXCheckBox->setChecked(false);
    sliceXCheckBox->adjustSize();
    m_sliceSliderX = new QSlider(Qt::Horizontal, xWidget);
    m_sliceSliderX->setGeometry(sliceXCheckBox->width(), 0, 200-sliceXCheckBox->width(), sliceXCheckBox->height());
    m_sliceSliderX->setMinimum(0);
    m_sliceSliderX->setMaximum(1024);
    m_sliceSliderX->setValue(512);
    m_sliceSliderX->setEnabled(true);
    xWidget->adjustSize();
    xWidget->setFixedSize(xWidget->size());

    QWidget *yWidget = new QWidget();
    QCheckBox *sliceYCheckBox = new QCheckBox(yWidget);
    sliceYCheckBox->setText(QStringLiteral("Slice Y"));
    sliceYCheckBox->setChecked(false);
    sliceYCheckBox->adjustSize();
    m_sliceSliderY = new QSlider(Qt::Horizontal, yWidget);
    m_sliceSliderY->setGeometry(sliceYCheckBox->width(), 0, 200-sliceYCheckBox->width(), sliceYCheckBox->height());
    m_sliceSliderY->setMinimum(0);
    m_sliceSliderY->setMaximum(1024);
    m_sliceSliderY->setValue(512);
    m_sliceSliderY->setEnabled(true);
    yWidget->adjustSize();
    yWidget->setFixedSize(yWidget->size());

    QWidget *zWidget = new QWidget();
    QCheckBox *sliceZCheckBox = new QCheckBox(zWidget);
    sliceZCheckBox->setText(QStringLiteral("Slice Z"));
    sliceZCheckBox->setChecked(false);
    sliceZCheckBox->adjustSize();
    m_sliceSliderZ = new QSlider(Qt::Horizontal, zWidget);
    m_sliceSliderZ->setGeometry(sliceZCheckBox->width(), 0, 200-sliceZCheckBox->width(), sliceZCheckBox->height());
    m_sliceSliderZ->setMinimum(0);
    m_sliceSliderZ->setMaximum(1024);
    m_sliceSliderZ->setValue(512);
    m_sliceSliderZ->setEnabled(true);
    zWidget->adjustSize();
    zWidget->setFixedSize(zWidget->size());

    m_sliceImageX = new QLabel(this),
    m_sliceImageY = new QLabel(this),
    m_sliceImageZ = new QLabel(this);
    m_sliceImageX->setFrameShape(QFrame::Box);
    m_sliceImageY->setFrameShape(QFrame::Box);
    m_sliceImageZ->setFrameShape(QFrame::Box);
    m_sliceImageX->setScaledContents(true);
    m_sliceImageY->setScaledContents(true);
    m_sliceImageZ->setScaledContents(true);
    m_sliceImageX->setMinimumSize(QSize(200, 200));
    m_sliceImageX->setMaximumSize(QSize(200, 200));
    m_sliceImageY->setMinimumSize(QSize(200, 200));
    m_sliceImageY->setMaximumSize(QSize(200, 200));
    m_sliceImageZ->setMinimumSize(QSize(200, 200));
    m_sliceImageZ->setMaximumSize(QSize(200, 200));

//    QCheckBox *preserveOpacityCheckBox = new QCheckBox(this);
//    preserveOpacityCheckBox->setText(QStringLiteral("Preserve opacity"));
//    preserveOpacityCheckBox->setChecked(false);

//    QCheckBox *useHighDefShaderCheckBox = new QCheckBox(this);
//    useHighDefShaderCheckBox->setText(QStringLiteral("Use HD shader"));
//    useHighDefShaderCheckBox->setChecked(true);

//    QCheckBox *drawSliceFramesCheckBox = new QCheckBox(this);
//    drawSliceFramesCheckBox->setText(QStringLiteral("Draw slice frames"));
//    drawSliceFramesCheckBox->setChecked(false);

    vLayoutLeft->addWidget(zWidget);
    vLayoutLeft->addWidget(m_sliceImageZ, 0, Qt::AlignRight | Qt::AlignBottom);
    vLayoutLeft->addWidget(yWidget);
    vLayoutLeft->addWidget(m_sliceImageY, 1, Qt::AlignRight | Qt::AlignTop);

    vLayoutRight->addWidget(xWidget);
    vLayoutRight->addWidget(m_sliceImageX, 1, Qt::AlignLeft | Qt::AlignTop);

    connect(sliceXCheckBox, &QCheckBox::stateChanged,
            this, &QFitsView3D::sliceX);
    connect(sliceYCheckBox, &QCheckBox::stateChanged,
            this, &QFitsView3D::sliceY);
    connect(sliceZCheckBox, &QCheckBox::stateChanged,
            this, &QFitsView3D::sliceZ);
    connect(fitsMainWindow->mytoolbar->limitZCheckBox, &QCheckBox::stateChanged,
            this, &QFitsView3D::limitZ);
    connect(fitsMainWindow->mytoolbar->limitSliderZ, &QSlider::valueChanged,
            this, &QFitsView3D::limitZ);
    connect(m_sliceSliderX, &QSlider::valueChanged,
            this, &QFitsView3D::adjustSliceX);
    connect(m_sliceSliderY, &QSlider::valueChanged,
            this, &QFitsView3D::adjustSliceY);
    connect(m_sliceSliderZ, &QSlider::valueChanged,
            this, &QFitsView3D::adjustSliceZ);
    connect(fitsMainWindow->mytoolbar->limitSpinboxZ, SIGNAL(valueChanged(int)), this, SLOT(limitZ()));
//    connect(preserveOpacityCheckBox, &QCheckBox::stateChanged,
//            this, &QFitsView3D::setPreserveOpacity);
//    connect(useHighDefShaderCheckBox, &QCheckBox::stateChanged,
//            this, &QFitsView3D::setUseHighDefShader);
    connect(fitsMainWindow->mytoolbar->alphaMultiplierSlider, &QSlider::valueChanged,
            this, &QFitsView3D::adjustAlphaMultiplier);
    connect(fitsMainWindow->mytoolbar->drawSliceFramesCheckBox, &QCheckBox::stateChanged,
            this, &QFitsView3D::setDrawSliceFrames);
    connect(scatterWindow, &QFits3DScatter::setBrightnessContrast,
            this, &QFitsView3D::updateBrightnessContrast);
    connect(this, &QFitsView3D::updateMagnifier,
            fitsMainWindow->viewingtools->magnifier, &QFitsMag::setDirectPixmap);
    connect(scatterWindow, &QFits3DScatter::queriedGraphPositionChanged,
            this, &QFitsView3D::updateSpectrum);
    connect(fitsMainWindow->mytoolbar->limitZCheckBox, &QCheckBox::stateChanged,
            this, &QFitsView3D::setData);

    show();
}

QFitsView3D::~QFitsView3D() {
}

void QFitsView3D::limitZ() {
    setData();

    // Rerender image labels
    adjustSliceX(m_sliceSliderX->value());
    adjustSliceY(m_sliceSliderY->value());
    adjustSliceZ(m_sliceSliderZ->value());
}

void QFitsView3D::setData() {
    QVector<uchar> *m_lowDetailData;
    double n1, n2, n3, m;

    n1 = work.Naxis(1);
    n2 = work.Naxis(2);
    n3 = work.Naxis(3);

    if (fitsMainWindow->mytoolbar->limitSpinboxZ->isEnabled()) {
        int n3min, n3max,
            spinboxVal = fitsMainWindow->mytoolbar->limitSpinboxZ->value(),
            sliderVal = fitsMainWindow->mytoolbar->limitSliderZ->value();
        n3min = sliderVal - spinboxVal / 2;
        if (n3min < 1) n3min = 1;
        n3max = n3min + spinboxVal;
        if (n3max > work.Naxis(3)) {
            n3max = work.Naxis(3);
            n3min = n3max - spinboxVal;
            if (n3min < 1) n3min = 1;
        }

        m_lowDetailData = new QVector<uchar>(work.Naxis(1) * work.Naxis(2) * (n3max-n3min+1));
        uchar *ldata = m_lowDetailData->data();
        memcpy(ldata, work.i1data + work.Naxis(1) * work.Naxis(2) * (n3min-1), work.Naxis(1) * work.Naxis(2) * (n3max-n3min+1));

        scatterWindow->axisX()->setRange(0, work.Naxis(1));
        scatterWindow->axisY()->setRange(0, work.Naxis(2));
        scatterWindow->axisZ()->setRange(0, n3max-n3min+1);

        n3 = n3max-n3min+1;

        myParent->getMyBuffer()->setCubeMode(DisplayCubeLinemap);
        myParent->getMyBuffer()->setLineWidth(n3/2, QFV::Default);
        myParent->getMyBuffer()->setCubeCenter((n3max + n3min) / 2, QFV::Default);

        fitsMainWindow->spectrum->update();
    } else {
        m_lowDetailData = new QVector<uchar>(work.Nelements());
        uchar *ldata = m_lowDetailData->data();
        memcpy(ldata, work.i1data, work.Nelements());

        scatterWindow->axisX()->setRange(0, work.Naxis(1));
        scatterWindow->axisY()->setRange(0, work.Naxis(2));
        scatterWindow->axisZ()->setRange(0, work.Naxis(3));

        myParent->getMyBuffer()->setCubeMode(DisplayCubeSingle);
        myParent->getMyBuffer()->setLineWidth(1, QFV::Default);
        myParent->getMyBuffer()->setCubeCenter(work.Naxis(3) / 2, QFV::Default);

        fitsMainWindow->spectrum->update();
    }

    m_sliceSliderX->setMaximum(n1);
    m_sliceSliderY->setMaximum(n2);
    m_sliceSliderZ->setMaximum(n3);
    m_sliceSliderX->setValue(n1 / 2);
    m_sliceSliderY->setValue(n2 / 2);
    m_sliceSliderZ->setValue(n3 / 2);

    scatterWindow->axisX()->setRange(0, n1);
    scatterWindow->axisY()->setRange(0, n2);
    scatterWindow->axisZ()->setRange(0, n3);

    m_sliceIndexX = n1 / 2;
    m_sliceIndexY = n2 / 2;
    m_sliceIndexZ = n3 / 2;

    m = std::max(n1, std::max(n2, n3));

    m_sliceImageZ->setFixedSize(200. * n1 / m, 200. * n2 / m);
    m_sliceImageY->setFixedSize(200. * n1 / m, 200. * n3 / m);
    m_sliceImageX->setFixedSize(200. * n3 / m, 200. * n2 / m);

    m_volume->setTextureFormat(QImage::Format_Indexed8);
    m_volume->setPreserveOpacity(false);

    m_volume->setTextureWidth(work.Naxis(1));
    m_volume->setTextureHeight(work.Naxis(2));
    m_volume->setTextureDepth((int)n3);

    m_volume->setTextureData(m_lowDetailData);

    m_volume->setScaling(
                QVector3D(scatterWindow->axisX()->max() - scatterWindow->axisX()->min(),
                          scatterWindow->axisY()->max() - scatterWindow->axisY()->min(),
                          scatterWindow->axisZ()->max() - scatterWindow->axisZ()->min()));
    m_volume->setPosition(
                QVector3D((scatterWindow->axisX()->max() + scatterWindow->axisX()->min()) / 2.0f,
                          (scatterWindow->axisY()->max() + scatterWindow->axisY()->min()) / 2.0f,
                          (scatterWindow->axisZ()->max() + scatterWindow->axisZ()->min()) / 2.0f));

    scatterWindow->setAspectRatio(std::max(n1, n3) / n2);

    handleSlicingChanges();
}

void QFitsView3D::handleSlicingChanges() {
    if (m_volume) {
        if (m_slicingX || m_slicingY || m_slicingZ) {
            // Only show slices of selected dimensions
            //! [8]
            m_volume->setAlphaMultiplier(100.);
            m_volume->setDrawSlices(true);
            //! [8]
            m_volume->setSliceIndexX(m_slicingX ? m_sliceIndexX : -1);
            m_volume->setSliceIndexY(m_slicingY ? m_sliceIndexY : -1);
            m_volume->setSliceIndexZ(m_slicingZ ? m_sliceIndexZ : -1);
        } else {
            // Show slice frames for all dimenstions when not actually slicing
//            if (alphaMultiplierSlider)
            adjustAlphaMultiplier(fitsMainWindow->mytoolbar->alphaMultiplierSlider->value());
            m_volume->setDrawSlices(false);
            m_volume->setSliceIndexX(m_sliceIndexX);
            m_volume->setSliceIndexY(m_sliceIndexY);
            m_volume->setSliceIndexZ(m_sliceIndexZ);
        }
    }
}

void QFitsView3D::updateBrightnessContrast(QMouseEvent* event) {
    if (event->buttons() == Qt::RightButton) {
        // do nothing
    } else if (event->buttons() == Qt::LeftButton) {
        // moved + left button: change colormap
            myParent->getMyBuffer()->setBrightnessContrast((int)((float)(event->x()) / (float)width() * 1000.),
                                                                      (int)((float)(event->y()) / (float)height() * 1000.));
            adjustSliceX(m_sliceSliderX->value());
            adjustSliceY(m_sliceSliderY->value());
            adjustSliceZ(m_sliceSliderZ->value());
    } else {
        scatterWindow->scene()->setGraphPositionQuery(event->pos());
        QPoint epos = mapToGlobal(event->pos());
        QPixmap p = QApplication::screens().at(0)->grabWindow(QApplication::desktop()->winId(), epos.x() - 15, epos.y() - 15, 30, 30);
        emit updateMagnifier(p);
    }
}

// TODO: optimize, we can actually gain a lot if we instantly fill data to the QVector<uchar>
//       and get rid of the flip(2) and rot90 by default
void QFitsView3D::newData() {
    myParent->getMyBuffer()->getDpData()->fvalue->normub(work,
                                                         myParent->getMyBuffer()->getImageMinValue(),
                                                         myParent->getMyBuffer()->getImageMaxValue(),
                                                         myParent->getMyBuffer()->getImageScalingMethod());

    dpint64 n1, n2, n3, m;

    n1 = work.Naxis(1);
    n2 = work.Naxis(2);
    n3 = work.Naxis(3);

    work.resize((n1 + ((4 - n1 % 4) % 4)), n2, n3);

    if (myParent->getMyBuffer()->getFlipX())
        work.flip(1);
    if (!myParent->getMyBuffer()->getFlipY())
        work.flip(2);
    if (myParent->getMyBuffer()->getRotation() != 90) {
        work.rot90(myParent->getMyBuffer()->getRotation());
    }

    fitsMainWindow->mytoolbar->limitSliderZ->setMaximum(n3);
    fitsMainWindow->mytoolbar->limitSliderZ->setValue(n3 / 2);
    fitsMainWindow->mytoolbar->limitSpinboxZ->setMaximum(n3);

    setData();

    updateColourtable();
    adjustSliceLabels();
}

void QFitsView3D::updateColourtable() {
    // add alpha channel to our colortable
    QVector<QRgb> ct = myParent->getMyBuffer()->getImage()->colorTable();
    colortable.resize(ct.size());
    for (int i = 0; i < ct.size(); i++) {
        QRgb oldColor = ct.at(i);
        colortable[i] = qRgba(qRed(oldColor), qGreen(oldColor), qBlue(oldColor), i);
    }

    m_volume->setColorTable(colortable);

    handleSlicingChanges();
}

void QFitsView3D::adjustSliceLabels() {
    adjustSliceX(m_sliceSliderX->value());
    adjustSliceY(m_sliceSliderY->value());
    adjustSliceZ(m_sliceSliderZ->value());
}

void QFitsView3D::adjustSliceX(int value) {
    if (m_volume) {
        m_sliceIndexX = value; // / (1024 / m_volume->textureWidth());
        if (m_sliceIndexX == m_volume->textureWidth()) {
            m_sliceIndexX--;
        }
        if (m_volume->sliceIndexX() != -1) {
            m_volume->setSliceIndexX(m_sliceIndexX);
        }
        float mult = m_volume->alphaMultiplier();
        m_volume->setAlphaMultiplier(100.);
        m_sliceImageX->setPixmap(
                    QPixmap::fromImage(m_volume->renderSlice(Qt::XAxis, m_sliceIndexX)));
        m_volume->setAlphaMultiplier(mult);
    }
}

void QFitsView3D::adjustSliceY(int value) {
    if (m_volume) {
        m_sliceIndexY = value; // / (1024 / m_volume->textureHeight());
        if (m_sliceIndexY == m_volume->textureHeight())
            m_sliceIndexY--;
        if (m_volume->sliceIndexY() != -1)
            m_volume->setSliceIndexY(m_sliceIndexY);
        float mult = m_volume->alphaMultiplier();
        m_volume->setAlphaMultiplier(100.);
        m_sliceImageY->setPixmap(
                    QPixmap::fromImage(m_volume->renderSlice(Qt::YAxis, m_sliceIndexY)));
        m_volume->setAlphaMultiplier(mult);
    }
}

void QFitsView3D::adjustSliceZ(int value) {
    if (m_volume) {
        m_sliceIndexZ = value; // / (1024 / m_volume->textureDepth());
        if (m_sliceIndexZ == m_volume->textureDepth())
            m_sliceIndexZ--;
        if (m_volume->sliceIndexZ() != -1)
            m_volume->setSliceIndexZ(m_sliceIndexZ);
        float mult = m_volume->alphaMultiplier();
        m_volume->setAlphaMultiplier(100.);
        m_sliceImageZ->setPixmap(
                    QPixmap::fromImage(m_volume->renderSlice(Qt::ZAxis, m_sliceIndexZ)));
        m_volume->setAlphaMultiplier(mult);
//        scatterWindow->scene()->activeCamera()->setTarget(QVector3D(0.,0.,(((double)value / m_sliceSliderZ->maximum()) - 0.5) * 2.));
    }
}

void QFitsView3D::sliceX(int enabled) {
    m_slicingX = enabled;
    handleSlicingChanges();
}

void QFitsView3D::sliceY(int enabled) {
    m_slicingY = enabled;
    handleSlicingChanges();
}

void QFitsView3D::sliceZ(int enabled) {
    m_slicingZ = enabled;
    handleSlicingChanges();
}

void QFitsView3D::setPreserveOpacity(bool enabled) {
    if (m_volume) {
        m_volume->setPreserveOpacity(enabled);

        // Rerender image labels
        adjustSliceX(m_sliceSliderX->value());
        adjustSliceY(m_sliceSliderY->value());
        adjustSliceZ(m_sliceSliderZ->value());
    }
}

void QFitsView3D::setUseHighDefShader(bool enabled) {
    if (m_volume) {
        m_volume->setUseHighDefShader(enabled);
    }
}

void QFitsView3D::adjustAlphaMultiplier(int value) {
    if (m_volume) {
        float mult;
        if (value > 100)
            mult = float(value - 99) / 2.0f;
        else
            mult = float(value) / float(500 - value * 4);
        m_volume->setAlphaMultiplier(mult);
//        QString labelFormat = QStringLiteral("Alpha multiplier: %1");
//        m_alphaMultiplierLabel->setText(labelFormat.arg(
//                                        QString::number(m_volume->alphaMultiplier(), 'f', 3)));

        // Rerender image labels
        if (m_sliceSliderX) {
            adjustSliceX(m_sliceSliderX->value());
        }
        if (m_sliceSliderY) {
            adjustSliceY(m_sliceSliderY->value());
        }
        if (m_sliceSliderZ) {
            adjustSliceZ(m_sliceSliderZ->value());
        }
    }
}

void QFitsView3D::setDrawSliceFrames(int enabled) {
    if (m_volume)
        m_volume->setDrawSliceFrames(enabled);
}

void QFitsView3D::updateSpectrum(const QVector3D &pos) {
    if (pos.x() >= -1.0 && pos.x() <= 1.0 && pos.y() >= -1.0 && pos.y() <= 1.0) {
        fitsMainWindow->spectrum->setCentre((pos.x() + 1.) / 2. * work.Naxis(1), (pos.y() + 1.) / 2. * work.Naxis(2));
    }
//    dp_output("QueriedGraphPosition: %f %f %f", pos.x(), pos.y(), pos.z());
}


// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// OLD: FROM VTK
// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//void QFitsView3D::updateScaling() {
//    scalingDirty = true;
//    if (this->isVisible()) {
//        // wenn mal average angezeigt wird -->uncomment
//        //main_view->plotwidget->plotter->setYRange(myParent->getMyBuffer()->min, myParent->getMyBuffer()->max);

//       newData();
//    }
//}

//void QFitsView3D::mouseReleaseEvent(QMouseEvent* event) {
//    switch(event->button())
//    {
//        case Qt::LeftButton:
//            break;
//        default:
//            break;
//    }
//}

//void QFitsView3D::calcZoomedRanges(int *x1, int *x2, int *y1, int *y2, int *z1, int *z2) {
//    QFitsSingleBuffer *sb = myParent->getMyBuffer();
//    if (sb->getFirstView3D()) {
//        sb->setFirstView3D(false);

//        if ((sb->getWidthVisible() == -1) && (sb->getHeightVisible() == -1)) {
//            sb->setWidthVisible(sb->Naxis(1));
//            sb->setHeightVisible(sb->Naxis(2));
//        }

//        // this buffer has been viewed the first time in 3D or has been loaded directly from command line
//        // if the total spatial area is bigger than 10'000 pixels scale it down
//        double area = sb->getWidthVisible() * sb->getHeightVisible();
//        if (area > 10000.) {
//            // set area to max. 10000 pixels
//            sb->setWidthVisible(sb->getWidthVisible() * 100. / sqrt(area));
//            sb->setHeightVisible(sb->getHeightVisible() * 100. / sqrt(area));
//        }

//        calcZoomedVisibleArea();
//    }

//    double  xCen = sb->getXcenter(),
//            yCen = sb->getYcenter();

//    sb->transCoordImage2Widget(&xCen, &yCen, sb->getZoomFactor_3Dwire());

//    *x1 = xCen - sb->getWidthVisible() / 2.;
//    if (*x1 < 1) {
//        *x1 = 1;
//    }
//    *x2 = *x1 + sb->getWidthVisible() - 1;
//    if (*x2 > sb->Naxis(1)) {
//        *x2 = sb->Naxis(1);
//        *x1 = *x2 - sb->getWidthVisible() + 1;
//        if (*x1 < 1) {
//            *x1 = 1;
//        }
//    }

//    *y1 = yCen - sb->getHeightVisible() / 2;
//    if (*y1 < 1) {
//        *y1 = 1;
//    }
//    *y2 = *y1 + sb->getHeightVisible() - 1;
//    if (*y2 > sb->Naxis(2)) {
//        *y2 = sb->Naxis(2);
//        *y1 = *y2 - sb->getHeightVisible() + 1;
//        if (*y1 < 1) {
//            *y1 = 1;
//        }
//    }

//    *z1 = (int)(sb->getCubeCenter(QFV::Wavelength) - sb->getLineWidth(QFV::Wavelength) + 0.5);
//    *z2 = (int)(sb->getCubeCenter(QFV::Wavelength) + sb->getLineWidth(QFV::Wavelength) + 0.5);

//    if (*z1 < 1) {
//        *z1 = 1;
//    }
//    if (*z2 > sb->Naxis(3)) {
//        *z2 = sb->Naxis(3);
//    }

//    sb->setXcenter(*x1+(int)((*x2-*x1)/2.+.5));
//    sb->setYcenter(*y1+(int)((*y2-*y1)/2.+.5));
//    sb->setWidthVisible(*x2-*x1+1);
//    sb->setHeightVisible(*y2-*y1+1);

//    fitsMainWindow->updateTotalVisibleRect();

//    // wenn man in View3D-modus im spectrum-fenster "C" drückt ohne die Maus zu
//    // bewegen, wird ein subspectrum von brei
//te 3 ausgewählt, dies wird erst
//    // angezeigt, wenn die maus bewegt wird... update() oder repaint() wird
//    // nicht ausgeführt
//    fitsMainWindow->spectrum->update();
//    fitsMainWindow->mytoolbar->setCube3D_zmin(QString::number(*z1, 'g', 4));
//    fitsMainWindow->mytoolbar->setCube3D_zmax(QString::number(*z2, 'g', 4));
//}

//void QFitsView3D::newData2() {
//    myParent->getMyBuffer()->setDirty(true);
//    scalingDirty = true;

//    update();
//}

//void QFitsView3D::updateZRange3D(double min, double max) {
//    zmin = min;
//    zmax = max;
//}

//void QFitsView3D::updateData() {
//    QFitsSingleBuffer *sb = myParent->getMyBuffer();
//    if (isVisible() && (sb != NULL) && (sb->getDpData()->type == typeFits)) {
//        QReadLocker locker(&buffersLock);

//        Fits *f = sb->getDpData()->fvalue;
//        if (f != NULL) {
//            // undo any possibly applied rotation and flipping
//            if (sb->getFlipX()) {
//                emit flipX();
//            }
//            if (sb->getFlipY()) {
//                emit flipY();
//            }
//            while (sb->getRotation() != 0) {
//                emit decRot();
//            }

//            // calculate dimensions of desired subcube
//            int x1, x2, y1, y2, z1, z2;
//            calcZoomedRanges(&x1, &x2, &y1, &y2, &z1, &z2);

//            // update ranges of axes
//            double ranges[6];
//            ranges[0] = x1;
//            ranges[1] = x2;
//            ranges[2] = y1;
//            ranges[3] = y2;
//            // flip z-axis for correct display (longest wave length is furthest)
//            ranges[4] = zmax;
//            ranges[5] = zmin;

//            // take into account WCS if available
//            double crpix, crval, cdelt;

//            if (f->GetFloatKey("CRPIX1", &crpix)) {
//                if (f->GetFloatKey("CRVAL1", &crval)) {
//                    if (f->GetFloatKey("CDELT1", &cdelt)) {
//                        ranges[0] = crval + cdelt*(ranges[0] - crpix);
//                        ranges[1] = crval + cdelt*(ranges[1] - crpix);
//                    }
//                }
//            }

//            if (f->GetFloatKey("CRPIX2", &crpix)) {
//                if (f->GetFloatKey("CRVAL2", &crval)) {
//                    if (f->GetFloatKey("CDELT2", &cdelt)) {
//                        ranges[2] = crval + cdelt*(ranges[2] - crpix);
//                        ranges[3] = crval + cdelt*(ranges[3] - crpix);
//                    }
//                }
//            }

//            // ranges[4] and ranges[5] don't have to be converted here, this is
//            // already done in Toolbar.cpp

//            dp_debug("RANGES: %d %d   %d %d   %d %d", ranges[0], ranges[1], ranges[2], ranges[3], ranges[4], ranges[5]);
//            axes->SetRanges(ranges);

//            if (scalingDirty) {
//                // extract desired subcube
//                QReadLocker locker(&buffersLock);
//                f->extractRange(subcube, x1, x2, y1, y2, z1, z2);

//                // converts Fits from double to unsigned char (if it is double)
//                myParent->calculateScaling(&subcube);

//                fitsMainWindow->mytoolbar->updateImageMinMax(sb);

//                scalingDirty = false;
//            } else {
//                // extract desired subcube
//                Fits tmp;
//                QReadLocker locker(&buffersLock);
//                f->extractRange(tmp, x1, x2, y1, y2, z1, z2);

//                // convert Fits eventually from double to unsigned char (if it is double)
//                tmp.normub(subcube, sb->getSpecPhysMinY(), sb->getSpecPhysMaxY());
//            }

//            newColourtable();

//            // flip data in z-axis for correct display (longest wave length is furthest)
//            subcube.flip(3);

//            if (initialized) {
//                // refocus camera to the center of the subcube
//                camera->SetFocalPoint((double)subcube.Naxis(1)/2, (double)subcube.Naxis(2)/2, (double)subcube.Naxis(3)/2);
//            }

//            sb->setDirty(false);

//            fitsMainWindow->setMagnifierCenterPos(0, 0);
//        }
//    } else {
//        sb->setDirty(true);
//    }
//}

//void QFitsView3D::paintEvent(QPaintEvent *e) {
//    QFitsSingleBuffer *sb = myParent->getMyBuffer();
//    if ((sb != NULL) && (sb->getDpData()->type == typeFits)) {
//        Fits *f = sb->getDpData()->fvalue;
//        if (f == NULL) {
//            return;
//        }

//        // if the dimensions of the subcube to be displayed changed,
//        // extract the corresponding subcube and center it
//        bool wasUpdated = false;
//        if (sb->getDirty() || scalingDirty || colourtableDirty) {
//            updateData();
//            wasUpdated = true;
//        }
//bool write = false;
//if (!write) {
//    dp_debug("INIT SIZE: %d %d %d", subcube.Naxis(1), subcube.Naxis(2), subcube.Naxis(3));
//     FILE *fh = fopen("gaga.data", "w");
//     int ss = subcube.Naxis(1)*subcube.Naxis(2)*subcube.Naxis(3);
//     int c = 0;
//     while (c < ss) {
//         putc( subcube.i1data[c], fh );
//         c++;
//     }
//     fclose(fh);
//    write = true;
//}
//        // point Fits-cube to vtk-structure
//        importer->SetWholeExtent(0, subcube.Naxis(1)-1,
//                                 0, subcube.Naxis(2)-1,
//                                 0, subcube.Naxis(3)-1);
//        importer->SetDataExtentToWholeExtent();
//        importer->SetImportVoidPointer(subcube.i1data);
//        importer->Update();

//        if (wasUpdated) {
//            //updateAxes();
//            wasUpdated = false;
//        }

//        if (!initialized) {
//            previousBuffer = myParent->getBufferIndex();
//            sb->setCamSettings(new cameraSettings());
//            ResetCamera(false, true, true);

//            initialized = true;
//        } else {
//            if (previousBuffer != myParent->getBufferIndex()) {
//                // buffer changed by one way or the other

//                // copy camera-settings to previousBuffer.camera-settings
//                myParent->getBuffer(previousBuffer)->getCamSettings()->getSettings(camera);

//                // create new camera settings
//                if (sb->getCamSettings() == NULL) {
//                    sb->setCamSettings(new cameraSettings());
//                    ResetCamera(false, true, true);
//                } else {
//                    // copy currentBuffer.camera-settings to camera-settings
//                    sb->getCamSettings()->setSettings(camera);
//                    updateColourtable();
//                    ResetCamera(false, false, false);
//                }
//                previousBuffer = myParent->getBufferIndex();
//            }
//        }

//        this->QVTKWidget::paintEvent(e);

//        fitsMainWindow->updateTotalVisibleRect();
//    }
//}

//void QFitsView3D::keyPressEvent( QKeyEvent *e ) {
//    fitsMainWindow->main_view->keyPressEvent(e);
//}

//void QFitsView3D::newColourtable() {
//    if (isVisible() && colourtableDirty) {

//        // delete old colorTransferFunction
//        colorTransferFunction->RemoveAllPoints();

//        // create new colorTransferFunction
//        int i = 0;
//        QRgb color;
//        for (i = 0; i < 256; ++i) {
//            color = myParent->getMyBuffer()->getImage()->color(i);
//            colorTransferFunction->AddRGBPoint(i, 1./(i+1) * qRed(color),
//                                                  1./(i+1) * qGreen(color),
//                                                  1./(i+1) * qBlue(color));
//        }

//        if (initialized) {
//            iren->Render();
//        }

//        colourtableDirty = false;
//    }
//}

//void QFitsView3D::enterEvent(QEvent *e)
//{
//    setFocus();
//    myParent->enterBuffer();
//}

//void QFitsView3D::leaveEvent (QEvent *e)
//{
//    myParent->leaveBuffer();
//}

// slot: called when rectangle in TotalView is moved
//void QFitsView3D::setImageCenter(double x, double y) {
//    QFitsSingleBuffer *sb = myParent->getMyBuffer();
//    if (isVisible()) {
//        sb->setXcenter(x);
//        sb->setYcenter(y);

//        fitsMainWindow->updateTotalVisibleRect();

//        scalingDirty = true;
//        newData();
//    }
//}

//void QFitsView3D::calcZoomedVisibleArea() {
//    QFitsSingleBuffer *sb = myParent->getMyBuffer();

//    double zoomFactor = sb->getZoomFactor_3Dwire();
//    if (zoomFactor > 1.) {
//        // > 100%
//        sb->setWidthVisible(sb->Naxis(1) / zoomFactor);
//        sb->setHeightVisible(sb->Naxis(2) / zoomFactor);
//    } else {
//        // = 100% (can't be smaller than 100%)
//        sb->setWidthVisible(sb->Naxis(1));
//        sb->setHeightVisible(sb->Naxis(2));
//    }
//}

//void QFitsView3D::applyZoom() {
//    QFitsSingleBuffer *sb = myParent->getMyBuffer();
//    if (sb != NULL) {
//        calcZoomedVisibleArea();

//        // calculate new size and recalculate distance of camera
//        updateData();
//        ResetCamera(false, false, false);

//        newData2();
//    }
//}
