#include <QApplication>
#include <QFileDialog>
#include <QMessageBox>
#include <QWidget>
#include <QFrame>
#include <QSpinBox>
#include <QComboBox>
#include <QPushButton>
#include <QToolButton>
#include <QSlider>
#include <QtPrintSupport/QPrinter>
#include <QProgressBar>
#include <QValidator>
#include <QRadioButton>
#include <QPainter>
#include <QLineEdit>
#include <QButtonGroup>
#include <QInputDialog>
#include <QString>
#include <QLayout>
#include <QFileInfo>
#include <QClipboard>
#include <QToolTip>
#include <QCursor>
#include <QListView>
#include <QToolBar>
#include <QTimer>
#include <QDesktopServices>
#include <QUrl>
#include <QMenuBar>
#include <QDragEnterEvent>
#include <QMimeData>
#include <QFileSystemWatcher>
#include <QMap>

#include <gsl/gsl_math.h>

#include "QFitsMainWindow.h"
#include "QFitsMainView.h"
#include "QFitsSingleBuffer.h"
#include "QFitsMultiBuffer.h"
#include "QFitsWidget1D.h"
#include "QFitsWidget2D.h"
#ifdef HAS_VTK
#include "QFitsWidget3D.h"
#include "QFitsView3D.h"
#endif
#include "QFitsView2D.h"
#include "QFitsViewingTools.h"
#include "QFitsCubeSpectrum.h"
#include "QFitsWedge.h"
#include "QFitsMarkers.h"
#include "QFitsToolBar.h"
#include "QFitsHeaderView.h"
#include "RGBDialog.h"
#include "events.h"
#include "imred.h"
#include "galfit.h"
#include "lut.h"
#include "dpuser.h"
#include "dpuser_utils.h"
#include "dpuser.yacchelper.h"
#include "dpstringlist.h"
#include "astrolib.h"
#include "qtdpuser.h"
#include "qt_mainwindow.h"
#include "dialogs.h"
#include "QFitsTools.h"
#include "QFitsWidgetWiregrid.h"
#include "QFitsWidgetContour.h"

extern "C" {
#include "resources/telescope.xpm"
}

#ifdef HAS_PLPLOT
extern PLDLLIMPEXP_DATA( PLStream * ) plsc;
#endif /* HAS_PLPLOT */

#ifdef LBT
#include "lbt.h"
#endif /* LBT */

extern int DPQuestion;

QFitsMainWindow::QFitsMainWindow(QWidget *parent) : QMainWindow(parent) {
    actualSB                    = NULL;
    centralWavelength           = 2.16611;
    bufferChangedByKey          = false;
    overrideSet                 = false;
    zoomCorr_spectrumVisible    = false;
    zoomCorr_wedgeVisible       = false;
    zoomCorr_ComboZoomTriggered = false;
    viewingTools_width          = 154;
    toolbar_height              = 30;
    init_colormaps();
    main_view = new QFitsMainView(this);
    if (menuBar()->height() > 0) toolbar_height = menuBar()->height();
    else if (statusBar()->height() > 0) toolbar_height = statusBar()->height(); // macos

    viewingTools_width = (fontMetrics().ascent() + fontMetrics().descent()) * 8.9 + 4;
    viewingTools_width = (viewingTools_width / 2) * 2;
    main_view->setGeometry(viewingTools_width,
                           menuBar()->height() + 60,
                           width() - viewingTools_width,
                           height() - (menuBar()->height() + 60));
    main_view->setMinimumHeight(100);

    // Create some dialog boxes
    imagedisplay = new ImageDisplay(this);
    imagedisplay->hide();
    cubeDisplayDialog = new CubeDisplayDialog(this);
    cubeDisplayDialog->hide();
    plotoptions = new PlotOptionsDialog(this);
    plotoptions->hide();
    about = new About(this);
    connect(about->PixmapLabel, SIGNAL(doubleClicked()),
            main_view, SLOT(playTetris()));
    about->hide();
    dphelp = new DpHelp(this);
    dphelp->hide();
    rgbdialog = new RGBDialog(this);
    rgbdialog->hide();
    combinedialog = new dpCombineDialog(this);
    combinedialog->hide();
    mpfitdialog = new dpMpfitDialog(this);
    mpfitdialog->hide();
    preferences = new QFitsPrefDialog(this);
    preferences->hide();
    blinkdialog = new BlinkDialog(this);
    blinkdialog->hide();
    headerView = new QFitsHeaderView(this);
    headerView->hide();
#ifdef LBT
    luciMaskAlign = new dpLuciMaskAlignDialog(this);
    luciMaskAlign->hide();
#endif /* LBT */
    watchdir = new dpWatchdirDialog(this);
    watchdir->hide();
    galfit = new dpGalfitDialog(this);
    galfit->hide();
    blinkTimer = new QTimer();
    connect(blinkTimer, SIGNAL(timeout()),
            this, SLOT(blinkTimerTimeout()));
    spectrum = new QFitsCubeSpectrum(this);
    spectrum->hide();
    spectrum->setMinimumSize(100, 150);

#ifdef HAS_PLOTTING
    plplotWindow = new dpPlplotWindow(NULL);
    plplotWindow->hide();
#endif /* HAS_PLOTTING */

#ifdef HAS_PLPLOT
    for (int i = 0; i < 10; i++) {
        pg2plplotWindow[i] = new dpPg2PlplotWindow(i);
        pg2plplotWindow[i]->hide();
    }

    extern PLDLLIMPEXP_DATA( PLStream * ) plsc;
#endif /* HAS_PLPLOT */

    dpuser_widget = new qtdpuser(this);
    dpuser_widget->setGeometry(0, height() - 100, width(), 100);

//    dpuserthread.start();

    scriptEditor = new MainWindow();
    scriptEditor->hide();

    // The Dock to the left (position info, magnifier, total, plot)
    viewingtools = new QFitsViewingTools(this, viewingTools_width);
    viewingtools->move(0, menuBar()->height() + 60);

    toolsWidget = new QFitsToolsWidget(this);
//    toolsWidget->setFixedWidth(220);
//    toolsWidget->hide();

    hsplitter = new QSplitter(Qt::Horizontal, this);
    hsplitter->addWidget(viewingtools);
    hsplitter->addWidget(main_view);
    hsplitter->setGeometry(0, 0, width(), 1000);
    hsplitter->setChildrenCollapsible(false);
    hsplitter->setHandleWidth(1);

    QSplitter *vsplitter = new QSplitter(Qt::Vertical, this);
    vsplitter->addWidget(hsplitter);
    vsplitter->addWidget(spectrum);
    vsplitter->addWidget(dpuser_widget);
    vsplitter->setChildrenCollapsible(false);

    splitter = new QSplitter(Qt::Horizontal, this);
    splitter->addWidget(vsplitter);
    splitter->addWidget(toolsWidget);
    splitter->setChildrenCollapsible(false);
    splitter->setHandleWidth(1);

    toolsWidget->setSplitter(splitter);

    if (settings.showTools == 2) {
        toolsWidget->setFloating();
    }

    scalingMethods = new QActionGroup(this);
    scalingMethods->setExclusive(true);
    scalingMethods->addAction("Linear")->setCheckable(true);
    scalingMethods->addAction("Logarithmic")->setCheckable(true);
    scalingMethods->addAction("Square root")->setCheckable(true);

    // toolbars
    mytoolbar = new QFitsToolBar(this);
    mytoolbar->setGeometry(0, menuBar()->height(), width(), 60);
    connect(mytoolbar, SIGNAL(orientationChanged()),
            this, SLOT(updateOrientation()));

    // Set up the menu bar
    QMenu *file = menuBar()->addMenu("&File");
    file->addAction("Open...", this, SLOT(LoadClicked()), Qt::CTRL+Qt::Key_O);
    file->addAction("Import...", this, SLOT(ImportClicked()));
    file->addAction("Reload", this, SLOT(reloadImage()), Qt::CTRL+Qt::Key_R);
    file->addAction("Save as FITS...", main_view, SLOT(saveFits()), Qt::CTRL+Qt::Key_S);
    file->addAction("Save as image...", main_view, SLOT(saveImage()), QKeySequence("Ctrl+Shift+S"));
    file->addSeparator();
    file->addAction("Watch directory...", watchdir, SLOT(updateandshow()));
    file->addSeparator();
    file->addAction("Print...", main_view, SLOT(printImage()));

    menu_displayFitsHeader = new QAction("Display FITS Header...", this);
    menu_displayFitsHeader->setShortcut(Qt::CTRL+Qt::Key_H);
    connect(menu_displayFitsHeader, SIGNAL(triggered()),
            this, SLOT(DisplayFITSHeader()));
    file->addAction(menu_displayFitsHeader);

    file->addSeparator();
    file->addAction("RGB Image Creator...", this, SLOT(showRGBDialog()));
    file->addAction("Image Combine Dialog...", this, SLOT(showCombineDialog()));
    file->addAction("Function fitting...", this, SLOT(showMpfitDialog()));
    file->addAction("Galfit...", galfit, SLOT(updateandshow()));
#ifdef HAS_PLOTTING
    file->addAction("Plotting...", this, SLOT(showPlottingDialog()));
#endif /* HAS_PLOTTING */

    file->addSeparator();
    file->addAction("Exit", this, SLOT(close()), Qt::CTRL+Qt::Key_Q);
    connect(file, SIGNAL(aboutToShow()),
            this, SLOT(adaptFileMenu()));

    QMenu *edit = menuBar()->addMenu("&Edit");
    edit->addAction("Copy", this, SLOT(copyImage()), Qt::CTRL+Qt::Key_C);
    edit->addAction("Paste", this, SLOT(pasteImage()), Qt::CTRL+Qt::Key_V);

    scaling = menuBar()->addMenu("&Scale");
    scaling->addActions(scalingMethods->actions());
    scaling->actions().first()->setChecked(true);
    connect(scalingMethods, SIGNAL(triggered(QAction *)),
            this, SLOT(scalingTriggered(QAction *)));

//#ifdef HAS_VTK
// wie ???
//    connect(mytoolbar->scalingActions, SIGNAL(triggered(QAction *)),
//            main_view->cube3d->cubeViewer, SLOT(scalingTriggered(QAction *)));
//#endif

    map = menuBar()->addMenu("&Colourmap");
    mapActions = new QActionGroup(map);
    mapActions->setExclusive(true);

    for (type_colormap::iterator iter = mapcolors.begin();
                                                iter != mapcolors.end(); iter++)
    {
        mapActions->addAction((*iter).first)->setCheckable(true);
    }

    for (int i = 0; i < mapActions->actions().size(); i++) {
        if (mapActions->actions().at(i)->iconText() == "gray")
            map->addAction(mapActions->actions().at(i));
    }
    for (int i = 0; i < mapActions->actions().size(); i++) {
        if (mapActions->actions().at(i)->iconText() == "bb") {
            map->addAction(mapActions->actions().at(i));
            mapActions->actions().at(i)->setChecked(true);
        }
    }
    for (int i = 0; i < mapActions->actions().size(); i++) {
        if (mapActions->actions().at(i)->iconText() == "rainbow")
            map->addAction(mapActions->actions().at(i));
    }
    for (int i = 0; i < mapActions->actions().size(); i++) {
        if (mapActions->actions().at(i)->iconText() == "red")
            map->addAction(mapActions->actions().at(i));
    }
    for (int i = 0; i < mapActions->actions().size(); i++) {
        if (mapActions->actions().at(i)->iconText() == "green")
            map->addAction(mapActions->actions().at(i));
    }
    for (int i = 0; i < mapActions->actions().size(); i++) {
        if (mapActions->actions().at(i)->iconText() == "blue")
            map->addAction(mapActions->actions().at(i));
    }
    for (int i = 0; i < mapActions->actions().size(); i++) {
        if (mapActions->actions().at(i)->iconText() == "sauron")
            map->addAction(mapActions->actions().at(i));
    }

    map->addSeparator();
    invertAction = map->addAction("invert");
    invertAction->setCheckable(true);
    connect(invertAction, SIGNAL(triggered(bool)),
            main_view, SLOT(setInvertColormap(bool)));
    map->addSeparator();
    map->addAction("more...", this, SLOT(moreColormaps()))->setCheckable(false);

    connect(mapActions, SIGNAL(triggered(QAction *)),
            main_view, SLOT(setColormap(QAction *)));

    morecolourmaps = new moreColourmaps(this);
    morecolourmaps->hide();

    zoom = menuBar()->addMenu("&Zoom");
    zoom->addAction("Fit window");
    zoom->addAction("Fit width");
    zoom->addAction("Fit height");
    zoom->addSeparator();
    zoom->addAction("3.125%");
    zoom->addAction("6.25%");
    zoom->addAction("12.5%");
    zoom->addAction("25%");
    zoom->addAction("50%");
    zoom->addAction("100%");
    zoom->addAction("200%");
    zoom->addAction("400%");
    zoom->addAction("800%");
    zoom->addAction("1600%");
    zoom->addAction("3200%");
    connect(zoom, SIGNAL(triggered(QAction *)),
            this, SLOT(menuZoomTriggered(QAction *)));

    options = menuBar()->addMenu("&Options");
    options->addAction("Image Display...", imagedisplay, SLOT(show()));
    options->addAction("Cube Display...", cubeDisplayDialog, SLOT(show()));
    options->addAction("Plot Options...", plotoptions, SLOT(show()));
    options->addSeparator();
    options->addAction("Preferences...", preferences, SLOT(exec()));


    imred = menuBar()->addMenu("&ImRed");

    imfilter = imred->addMenu("Create Filter");
    imfilter->addAction("Gauss...");
    imfilter->addAction("Ellipse...");
    imfilter->addAction("Moffat...");
    imfilter->addAction("Airy...");
    connect(imfilter, SIGNAL(triggered(QAction *)),
            this, SLOT(imfilterTriggered(QAction *)));

    imcube = imred->addMenu("Analysis");
    imcube->addAction("Velocity map...");
    imcube->addAction("Correlation map...");
    imcube->addAction("3D pseudo longslit...");
    imcube->addAction("Evaluate Velocity map...");
    imcube->addAction("2D cut...");
    imcube->addAction("Elliptical profile...");
    imcube->addAction("Statistics (on region)...");
    connect(imcube, SIGNAL(triggered(QAction *)),
            this, SLOT(imcubeTriggered(QAction *)));

    spectral = imred->addMenu("Spectral scale");
    spectral->addAction("Switch to velocity...");
    spectral->addAction("Switch to wavelength...");
    connect(spectral, SIGNAL(triggered(QAction *)),
            this, SLOT(spectralTriggered(QAction *)));

    userMenu = imred->addMenu("User");
    connect(userMenu, SIGNAL(aboutToShow()),
            this, SLOT(fillUserMenu()));
    connect(userMenu, SIGNAL(triggered(QAction *)),
            this, SLOT(userMenuTriggered(QAction *)));

    imred->addAction("Smooth...");
    imred->addAction("Smooth subtract...");
    imred->addAction("Rotate...");
    imred->addAction("Shift...");
    imred->addAction("Crop...");
    imred->addAction("Resize...");
    imred->addAction("Rebin...");
    imred->addAction("Flip X");
    imred->addAction("Flip Y");
    imred->addAction("Flip Z");
    imred->addAction("Create PSF...");
    imred->addAction("Wiener filter...");
    imred->addAction("Lucy deconvolve...");
    imred->addAction("Voronoi Tesselation...");
    imred->addAction("Arithmetics (Image)...");
    imred->addAction("Arithmetics (Number)...");
    imred->addAction("Clear blank values...");
    imred->addAction("Mark positions...");
    connect(imred, SIGNAL(triggered(QAction *)),
            this, SLOT(imredTriggered(QAction *)));

    QMenu *dpuser = menuBar()->addMenu("&DPUSER");
    dpuser->addAction("Send Interrupt", this, SLOT(dpuserInterrupt()));
    dpuser->addAction("Change directory...", this, SLOT(dpuserChangeDirectory()));
    dpuser->addAction("Execute script...", this, SLOT(dpuserExecuteScript()));
    dpuser->addAction("Script Editor...", scriptEditor, SLOT(show()));
    dpuser->addSeparator();
    dpuser->addAction("Copy history to clipboard", this, SLOT(dpuserCopyHistory()));
#ifdef LBT
    dpuser->addSeparator();
    dpuser->addAction("LUCI Mask Align...", luciMaskAlign, SLOT(show()));
#endif

    // Build View-Menu
    view = menuBar()->addMenu("&View");
    viewActions = new QActionGroup(view);
    viewActions->setExclusive(true);
    viewActions->addAction("Image")->setCheckable(true);
    viewActions->actions().first()->setChecked(true);
    viewActions->addAction("Wiregrid")->setCheckable(true);
    viewActions->addAction("Contour")->setCheckable(true);
    viewActions->addAction("Table")->setCheckable(true);
#ifdef HAS_VTK
    viewActions->addAction("3D Cube")->setCheckable(true);
#endif
    view->addActions(viewActions->actions());
    connect(view, SIGNAL(triggered(QAction *)),
            this, SLOT(viewTriggered(QAction *)));
    connect(view, SIGNAL(aboutToShow()),
            this, SLOT(fillViewMenu()));

    nextBufferAction = new QAction("Next Buffer", this);
    nextBufferAction->setShortcut(QKeySequence::MoveToNextWord);
    connect(nextBufferAction, SIGNAL(triggered()), this, SLOT(moveToNextBuffer()));
    addAction(nextBufferAction);
    previousBufferAction = new QAction("Previous Buffer", this);
    previousBufferAction->setShortcut(QKeySequence::MoveToPreviousWord);
    connect(previousBufferAction, SIGNAL(triggered()), this, SLOT(moveToPreviousBuffer()));
    addAction(previousBufferAction);

    buffer = menuBar()->addMenu("&Buffer");
    connect(buffer, SIGNAL(aboutToShow()),
            this, SLOT(fillBufferMenu()));
    connect(buffer, SIGNAL(triggered(QAction *)),
            this, SLOT(buffersTriggered(QAction *)));
    fillBufferMenu();

    windows = menuBar()->addMenu("&Window");
    windows->addAction("Viewing Tools")->setCheckable(true);
    windows->addAction("DPUSER - The Next Generation")->setCheckable(true);
    windows->addAction("Spectrum")->setCheckable(true);
    windows->addAction("Tools")->setCheckable(true);
    windows->addSeparator();
    windows->addAction("Remove Grid");
    windows->addAction("Grid 2x1");
    windows->addAction("Grid 2x2");
    connect(windows, SIGNAL(triggered(QAction *)),
            this, SLOT(windowsTriggered(QAction *)));
    connect(windows, SIGNAL(aboutToShow()),
            this, SLOT(updateWindowsMenu()));

    help = menuBar()->addMenu("&Help");
    help->addAction("About", about, SLOT(show()));
//    help->addAction("DpHelp", dphelp, SLOT(show()));
    help->addSeparator();
    help->addAction("&Introduction");
    help->addAction("&Functions");
    help->addAction("&Procedures");
    help->addSeparator();
QAction *aa = help->addAction("Check for updates...");
aa->setEnabled(false);
    connect(help, SIGNAL(triggered(QAction *)),
            this, SLOT(helpTriggered(QAction *)));

    progressbar = new QProgressBar(statusBar());
    statusBar()->addPermanentWidget(progressbar);
    progressbar->setFixedSize(100, progressbar->height());

    QLabel *mpelabel = new QLabel(statusBar());
    mpelabel->setToolTip("<center>Max Planck Institute for Extraterrestrial "
                         "Physics</center>");
    mpelabel->setPixmap(QIcon(":/logo-MPE-bw.svg").pixmap(progressbar->height(), progressbar->height()));
    statusBar()->addPermanentWidget(mpelabel);

    statusBar()->showMessage("Welcome to QFitsView");
    connect(dpuser_widget, SIGNAL(statusbartext(const QString &)),
            statusBar(), SLOT(showMessage(const QString &)));
    connect(dpuser_widget, SIGNAL(dpuserExited()),
            this, SLOT(close()));
    connect(spectrum->getPlotter(), SIGNAL(statusbartext(const QString &)),
            statusBar(), SLOT(showMessage(const QString &)));

    connect(spectrum, SIGNAL(statisticsChanged()),
            main_view, SLOT(slotRedoManualSpectrum()));

    if (settings.showViewingTools == 0)
        viewingtools->hide();
    if (settings.showViewingTools == 2) {
    }

    if (settings.showDpuser == 0)
        dpuser_widget->hide();
    if (settings.showDpuser == 2) {
    }

    if (settings.showTools == 0)
        toolsWidget->hide();

    emptyTool = new QWidget(this);
    toolsWidget->addWidget(emptyTool);

    fitter2d = new QFits2dFit(this);
    fitter2d->setWindowTitle("Object fit");
    toolsWidget->addWidget(fitter2d);
    toolsWidget->setFixedWidth(fitter2d->size().width());
//    fitter2d->setParent(toolsWidget);
//    fitter2d->hide();

    markposDialog = new imRedMarkpos(this);
    markposDialog->hide();

    toolsWidget->addWidget(markposDialog);

    connect(plotoptions->CutsWidth, SIGNAL(valueChanged(int)),
            viewingtools->cuts_plot, SLOT(setCutsWidth(int)));
    connect(plotoptions->CutsStyle, SIGNAL(activated(int)),
            viewingtools->cuts_plot, SLOT(setCutsStyle(int)));
    connect(plotoptions->PlotTakeLimits, SIGNAL(toggled(bool)),
            viewingtools->cuts_plot, SLOT(setTakeLimits(bool)));

    connect(imagedisplay->spinboxBrightness, SIGNAL(valueChanged(int)),
            main_view, SLOT(setBrightness(int)));
    connect(imagedisplay->spinboxContrast, SIGNAL(valueChanged(int)),
            main_view, SLOT(setContrast(int)));
    connect(imagedisplay->buttonClose, SIGNAL(clicked()),
            this, SLOT(updateImageOptions()));

    connect(mytoolbar->cubeImageSlice, SIGNAL(valueChanged(int)),
            spectrum, SLOT(newSlice(int)));

    connect(preferences, SIGNAL(accepted()),
            headerView, SLOT(fontchanged()));
    connect(preferences, SIGNAL(accepted()),
            dpuser_widget, SLOT(fontchanged()));
    connect(preferences, SIGNAL(accepted()),
            scriptEditor, SLOT(fontchanged()));

    connect(&fsWatcher, SIGNAL(directoryChanged(const QString &)), this, SLOT(FileSystemChanged(const QString &)));

//#ifdef Q_WS_X11
    setWindowIcon(QPixmap((const char **)telescope_xpm));
//#else
//    setWindowIcon(QIcon(QPixmap((const char **)telescope_xpm)));
//#endif

    for (int i = 0; i < 10; i++) qpgplot_windows[i] = new QPgplotDialog(this, i);
//    qpgplot_windows->show();

    arrangeChildren();
    setAcceptDrops(true);

}

QFitsMainWindow::~QFitsMainWindow() {
    dpuser_widget->executeCommand("exit");
    dpuserthread.wait();
}

void QFitsMainWindow::closeEvent(QCloseEvent *e) {
    scriptEditor->close();
    combinedialog->close();
#ifdef HAS_PLOTTING
#ifdef HAS_PLPLOT
    plplotWindow->close();
    for (int i = 0; i < 10; i++) {
        pg2plplotWindow[i]->close();
    }
#endif /* HAS_PLPLOT */
#endif /* HAS_PLOTTING */
    QMainWindow::closeEvent(e);
}

void QFitsMainWindow::StartDpuser() {
    dpuserthread.start();
    connect(&dpuserthread, SIGNAL(dpuserProgress(const int &, const QString &)),
            this, SLOT(dpuserProgress(const int &, const QString &)));
    connect(&dpuserthread, SIGNAL(dpuserHelp(const QString &)),
            this, SLOT(dpuserHelp(const QString &)));
    connect(&dpuserthread, SIGNAL(dpuserVar(const std::string &)),
            this, SLOT(dpuserVar(const std::string &)), Qt::BlockingQueuedConnection);
    connect(&dpuserthread, SIGNAL(dpuserView(const std::string &)),
            this, SLOT(dpuserView(const std::string &)), Qt::BlockingQueuedConnection);
    connect(&dpuserthread, SIGNAL(dpuserCommand(const QString &, const QString &, const int &)),
            this, SLOT(dpuserCommand(const QString &, const QString &, const int &)), Qt::BlockingQueuedConnection);
    connect(&dpuserthread, SIGNAL(pgplotUpdate(const int &, const QImage &)),
            this, SLOT(updatePgplot(const int &, const QImage &)), Qt::BlockingQueuedConnection);
    connect(&dpuserthread, SIGNAL(pgplotUpdate(const int &, const int &, const int &)),
            this, SLOT(updatePgplot(const int &, const int &, const int &)), Qt::BlockingQueuedConnection);
}

std::string QFitsMainWindow::getCurrentBufferIndex() {
    return main_view->getCurrentBufferIndex();
}

QFitsBaseBuffer* QFitsMainWindow::getCurrentBuffer() {
    return main_view->getCurrentBuffer();
}

QFitsBaseBuffer* QFitsMainWindow::getBuffer(std::string i) {
    return main_view->getBuffer(i);
}

QFitsSingleBuffer* QFitsMainWindow::getMarkedSingleBuffer() {
    QFitsMultiBuffer *mb = dynamic_cast<QFitsMultiBuffer*>(getCurrentBuffer());
    if (mb != NULL)  {
        return mb->getMarkedSingleBuffer();
    }
    return NULL;
}

void QFitsMainWindow::dragEnterEvent(QDragEnterEvent *event) {
    if (event->mimeData()->hasUrls()) {
        event->acceptProposedAction();
    }
}

void QFitsMainWindow::dropEvent(QDropEvent *event) {
    if (event->mimeData()->hasUrls()) {
        QFileInfo finfo;
        foreach (QUrl url, event->mimeData()->urls()) {
            dpuser_widget->executeCommand("newbuffer \"" + url.toLocalFile() + "\"");
            finfo.setFile(url.toLocalFile());
            settings.lastOpenPath = finfo.absoluteDir().path();
            settings.lastOpenPath.replace("\\", "/");
        }
    } else {
        dpuser_widget->dropEvent(event);
    }
    event->accept();
}

void QFitsMainWindow::copyImage() {
    main_view->getCurrentBuffer()->copyImage();
}

void QFitsMainWindow::pasteImage() {
    if (QApplication::clipboard()->mimeData()->hasUrls()) {
        foreach (QUrl url, QApplication::clipboard()->mimeData()->urls()) {
            dpuser_widget->executeCommand("newbuffer \"" + url.toLocalFile() + "\"");
        }
    } else {
        dpuser_widget->paste();
    }
}

void QFitsMainWindow::resizeEvent(QResizeEvent *e) {
    if (!isMaximized()) {
        settings.width = width();
        settings.height = height();
        settings.maximized = false;
    } else {
        settings.maximized = true;
    }
    arrangeChildren();
}

// small utility function to return an appropriate Caption
QString QFitsMainWindow::createCaption(std::string bufferIndex, bool prepend) {
    QString rv, fname;

    if (prepend) {
        rv = "QFitsView - ";
    }
    rv += bufferIndex.c_str();

    if (main_view->bufferMap[bufferIndex]->getDpData()->type == typeFits) {
        fname = main_view->bufferMap[bufferIndex]->getDpData()->fvalue->getFileName();
    } else if (main_view->bufferMap[bufferIndex]->getDpData()->type == typeDpArr) {
        fname = main_view->bufferMap[bufferIndex]->getDpData()->dparrvalue->at(0)->getFileName();
    } else if (main_view->bufferMap[bufferIndex]->getDpData()->type == typeStrarr) {
        // dpStringList hasn't a file name...
        fname = "";
    } else {
        fname = "";
    }

    if (strlen(fname.toStdString().c_str()) > 0) {
        rv += " [";
        rv += fname;
        rv += "]";
    }

    return rv;
}

void QFitsMainWindow::keyPressEvent( QKeyEvent *e ) {
    QMainWindow::keyPressEvent(e);
}

bool QFitsMainWindow::headerVisible() {
    return headerView->isVisible();
}

//#ifdef HAS_VTK
void QFitsMainWindow::updateCubeSpectrumViewer() {
    spectrum->getPlotter()->doUpdate();
}
//#endif

void QFitsMainWindow::updateViewingtools() {
    viewingtools->refreshViews();
}

void QFitsMainWindow::updateWedge() {
    main_view->getWedge()->update();
}

void QFitsMainWindow::updateTools(int imageX, int imageY,
                                  int imageXnotRotFlip, int imageYnotRotFlip,
                                  bool updateTotal)
{
    if (viewingtools->isVisible()) {
        setMagnifierCenterPos(imageXnotRotFlip, imageYnotRotFlip);
        viewingtools->refreshPosInfo(imageX, imageY);
        if (updateTotal) {
            viewingtools->total->update();
        }
    }

    QFitsSingleBuffer *sb = getActualSB();
    if (spectrum->isVisible() &&
        (sb != NULL) &&
        (sb->getViewMode() != ViewTable))
    {
        spectrum->setCentre(imageX, imageY);
    }

    fitter2d->centre(imageXnotRotFlip, imageYnotRotFlip,
                     imageX, imageY);
}

void QFitsMainWindow::updateTotalVisibleRect() {
    if (main_view->hasGrid()) {
        if (main_view->grid->gridMap[main_view->grid->activeID] == dynamic_cast<QWidget*>(getActualSB())) {
            viewingtools->total->update();
        }
   } else {
        viewingtools->total->update();
    }
}

void QFitsMainWindow::setMagnifierCenterPos(int x, int y) {
    viewingtools->magnifier->setCenter(x, y);
}

void QFitsMainWindow::arrangeChildren() {
    QFont menuFont = menuBar()->font();
    int hhh = menuFont.pointSize();
    QFont theFont = QApplication::font();
    theFont.setPointSize(hhh);
    if (menuBar()->height() > 0) toolbar_height = menuBar()->height();
    else if (statusBar()->height() > 0) toolbar_height = statusBar()->height() / 1.5; // macos
    int toolbarHeight = 30/22.*2 * toolbar_height;
    if (toolbarHeight % 2 == 1) toolbarHeight++; // next even integer
    mytoolbar->setFont(theFont);
    mytoolbar->setGeometry(0, menuBar()->height(), width(), toolbarHeight);
    int xmain = 0;
    splitter->setGeometry(xmain,
                          menuBar()->height() + toolbarHeight,
                          width() - xmain,
                          height() - (menuBar()->height() + toolbarHeight + statusBar()->height()));
}

void QFitsMainWindow::updateBufferList() {
    for (auto var:main_view->bufferMap) {
        if (var.second->getDpData()->type == typeFits) {
            QReadLocker locker(&buffersLock);
            if (var.second->getDpData()->fvalue != NULL) {
                QFitsSingleBuffer *sb = dynamic_cast<QFitsSingleBuffer*>(getBuffer(var.first));
                if ((sb != NULL) && (sb->getDpData()->type == typeFits)) {
                    if (sb->getDpData()->fvalue != var.second->getDpData()->fvalue) {
                        sb->setDirty(true);
                    }
                } else {
                    main_view->addNewBuffer(var.first, new dpuserType(*var.second->getDpData()));
                }
            }
        } else if (var.second->getDpData()->type == typeDpArr) {
            QReadLocker locker(&buffersLock);
            if (var.second->getDpData()->dparrvalue != NULL) {
                QFitsMultiBuffer *mb = dynamic_cast<QFitsMultiBuffer*>(getBuffer(var.first));
                if (mb != NULL) {
                    if (mb->getDpData()->dparrvalue != var.second->getDpData()->dparrvalue) {
                        mb->setDirty(true);
                    }
                } else {
                    main_view->addNewBuffer(var.first, new dpuserType(*var.second->getDpData()));
                }
            }
        } else if (var.second->getDpData()->type == typeStrarr) {
            QReadLocker locker(&buffersLock);
            if (var.second->getDpData()->arrvalue != NULL) {
                QFitsSingleBuffer *sb = dynamic_cast<QFitsSingleBuffer*>(getBuffer(var.first));
                if (sb != NULL) {
                    if (sb->getDpData()->arrvalue != var.second->getDpData()->arrvalue) {
                        sb->setDirty(true);
                    }
                } else {
                    main_view->addNewBuffer(var.first, new dpuserType(*var.second->getDpData()));
                }
            }
        }
    }
}

void QFitsMainWindow::updateMenuScaling(int id) {
    int i;

    for (i = 0; i < 3; i++) {
        if (i != id) {
            scaling->actions().at(i)->setChecked(false);
        }
    }
    scaling->actions().at(id)->setChecked(true);
}

void QFitsMainWindow::imredClicked(int id) {
    std::string curBufIndex = main_view->getCurrentBufferIndex();
    QFitsSingleBuffer *sb = getActualSB();
    if ((sb != NULL) &&
        (sb->getDpData()->type == typeFits))
    {
        Fits *f = sb->getDpData()->fvalue;
        switch (id) {
            case 0:
                imRedSmooth::showDialog(this);
                break;
            case 1:
                imRedSmoothSubtract::showDialog(this);
                break;
            case 2:
                imRedRotate::showDialog(this);
                break;
            case 3:
                imRedShift::showDialog(this);
                break;
            case 7:
                dpuser_widget->executeCommand("flip " +
                                              QString(curBufIndex.c_str()) +
                                              ", 1");
                break;
            case 8:
                dpuser_widget->executeCommand("flip " +
                                              QString(curBufIndex.c_str()) +
                                              ", 2");
                break;
            case 9:
                dpuser_widget->executeCommand("flip " +
                                              QString(curBufIndex.c_str()) +
                                              ", 3");
                break;
            case 11:
                imRedWien::showDialog(this);
                break;
            case 12:
                imRedLucy::showDialog(this);
                break;
            case 14:
                imRedArithImage::showDialog(this);
                break;
            case 15:
                imRedArithNumber::showDialog(this);
                break;
            case 4:
                imRedCrop::showDialog(this);
                break;
            case 5:
                imRedResize::showDialog(this);
                break;
            case 10:
                imRedCreatePSF::showDialog(this);
                break;
            case 6:
                imRedRebin::showDialog(this);
                break;
            case 13:
                imRedVoronoi::showDialog(this);
                break;
            case 16:
                imRedCblank::showDialog(this);
                break;
            case 17:
                markposDialog->show();
                activateWindow();
                break;
            case 100:
                imFilterGauss::showDialog(this);
                break;
            case 101:
                imFilterEllipse::showDialog(this);
                break;
            case 102:
                imFilterMoffat::showDialog(this);
                break;
            case 103:
                imFilterAiry::showDialog(this);
                break;
            case 200:
                imRedVelmap::showDialog(this);
                break;
            case 201:
                imRedCorrmap::showDialog(this);
                break;
            case 202:
            case 204:
                imRedLongslit::showDialog(this);
                break;
            case 203:
                imRedEvalVelmap::showDialog(this);
                break;
            case 205:
                imRedEllipticalProfile::showDialog(this);
                break;
            case 206: {
                long x = 0, y = 0, n = 0;
                double total, average, stddev, median, meddev, flux_per_beam = 0.0, bmaj = 0.0, bmin = 0.0;
                char bunit[81];
                QString title;

                QFitsMarkers *m = sb->getSourceMarkers();
                if (m->hasSourceMarkers()) {
                    n = m->getSizeSource();
                    Fits dummy;
                    dummy.create(n, 1, R8);
                    if (!(buffersLock.tryLockForRead())) {
                        return;
                    }

                    for (int i = 0; i < n; i++) {
                        m->getMarkerSource(i, &x, &y);
                        if ((x >= 1) && (x <= sb->Naxis(1)) &&
                            (y >= 1) && (y <= sb->Naxis(2)))
                        {
                            dummy.r8data[i] =
                                f->ValueAt(f->F_I(x, y));
                        }
                    }
                    buffersLock.unlock();
                    dummy.recreate(n, 1);
                    total = dummy.get_flux();
                    average = dummy.get_avg();
                    stddev = dummy.get_stddev();
                    median = dummy.get_median();
                    meddev = dummy.get_meddev();
                    if (f->GetFloatKey("BMAJ", &bmaj) && f->GetFloatKey("BMIN", &bmin) && f->GetStringKey("BUNIT", bunit))
                        flux_per_beam = total / (2. * M_PI * bmaj * bmin / fabs(f->getCDELT(1)) / fabs(f->getCDELT(2)) / 8. / log(2.));
                    title = "Statistics on region";
                } else {
                    if (!(buffersLock.tryLockForRead())) {
                        return;
                    }
                    total = f->get_flux();
                    average = f->get_avg();
                    stddev = f->get_stddev();
                    median = f->get_median();
                    meddev = f->get_meddev();
                    n = f->Nelements();
                    buffersLock.unlock();
                    title = "Statistics on complete array";
                }
                QString info = QString("Number of pixels:  \t" + QString::number(n) + "\n" +
                        "Total value:       \t" + QString::number(total) + "\n" +
                        "Average value:     \t" + QString::number(average) + "\n" +
                        "Standard deviation:\t" + QString::number(stddev) + "\n" +
                        "Median value:      \t" + QString::number(median) + "\n" +
                        "Median deviation:  \t" + QString::number(meddev));
                if (flux_per_beam != 0.0) {
                    QString b = QString(bunit);
                    b = b.left(b.indexOf('/'));
                    info += "\n\nFlux per beam [" + b + "]:  \t" + QString::number(flux_per_beam);
                }
                QMessageBox::information(this, title, info);
            }
                break;
            case 300: {
                bool ok;
                double center = QInputDialog::getDouble(this, "QFitsView",
                                                        "Enter central wavelength",
                                                        centralWavelength,
                                                        0.0, 1e100, 10, &ok);
                if (ok) {
                    if (!(buffersLock.tryLockForRead())) return;

                    if (f != NULL) {
                        centralWavelength = center;
                        int na = 1;
                        if (f->Naxis(3) > 1) {
                            na = 3;
                        }
                        double crpix = f->getCRPIX(na);
                        double crval = f->getCRVAL(na);
                        double cdelt = f->getCDELT(na);
                        double xmin, xmax;
                        crpix = crpix + (center - crval) / cdelt;
                        cdelt = cdelt / center * 299792.458;
                        crval = 0.0;
                        f->SetFloatKey(("CRVAL" +
                                                   QString::number(na)).toStdString().c_str(),
                                                  0.0);
                        f->SetFloatKey(("CRPIX" +
                                                   QString::number(na)).toStdString().c_str(),
                                                  crpix);
                        f->SetFloatKey(("CDELT" +
                                                   QString::number(na)).toStdString().c_str(),
                                                  cdelt);
                        f->DeleteKey(("CD" + QString::number(na) + "_" +
                                                 QString::number(na)).toStdString().c_str());

                        if (na == 1) {
                            sb->setData();
                            sb->setXRange();
                        }
                        if (na == 3) {
                            spectrum->getPlotter()->setCrpix(crpix);
                            spectrum->getPlotter()->setCrval(crval);
                            spectrum->getPlotter()->setCdelt(cdelt);
                            sb->setXRange();
                            spectrum->update();
                        }
                    } else {
                    }
                    buffersLock.unlock();
                }
                }
                break;
            case 301: {
                bool ok;
                double center = QInputDialog::getDouble(this, "QFitsView",
                                                        "Enter central wavelength",
                                                        centralWavelength,
                                                        0.0, 1e100, 10, &ok);
                if (ok) {
                    if (!(buffersLock.tryLockForRead())) {
                        return;
                    }
                    if (f != NULL) {
                        centralWavelength = center;
                        int na = 1;
                        if (f->Naxis(3) > 1) {
                            na = 3;
                        }
                        double crpix = f->getCRPIX(na);
                        double crval = f->getCRVAL(na);
                        double cdelt = f->getCDELT(na);
                        crval = center;
                        crpix = crpix + (center - crval) / cdelt;
                        cdelt = cdelt * center / 299792.458;
                        f->SetFloatKey(("CRPIX" +
                                                   QString::number(na)).toStdString().c_str(),
                                                  crpix);
                        f->SetFloatKey(("CRVAL" +
                                                   QString::number(na)).toStdString().c_str(),
                                                  crval);
                        f->SetFloatKey(("CDELT" +
                                                   QString::number(na)).toStdString().c_str(),
                                                  cdelt);
                        f->DeleteKey(("CD" + QString::number(na) + "_" +
                                                 QString::number(na)).toStdString().c_str());
                        if (na == 1) {
                            sb->setData();
                            sb->setXRange();
                        }
                        if (na == 3) {
                            spectrum->getPlotter()->setCrpix(crpix);
                            spectrum->getPlotter()->setCrval(crval);
                            spectrum->getPlotter()->setCdelt(cdelt);
                            spectrum->getPlotter()->setXRange(sb->getSpecChannelMinX(),
                                                              sb->getSpecChannelMaxX());
                            spectrum->update();
                        }
                    } else {
                    }
                    buffersLock.unlock();
                }
                }
                break;
            default:
                break;
        }
    }
}

void QFitsMainWindow::menuZoomTriggered(QAction *action) {
    // keep Menu-Zoom in sync with Toolbar-Zoom
    mytoolbar->getActualZoomCombo()->setEditText(action->text());
    FitZoom fz;
    double zoomValue = mytoolbar->getZoomTextCombo(&fz);
    getCurrentBuffer()->zoomTextChanged(zoomValue, fz);
}

void QFitsMainWindow::imfilterTriggered(QAction *action) {
    imredClicked(imfilter->actions().indexOf(action) + 100);
}

void QFitsMainWindow::imcubeTriggered(QAction *action) {
    imredClicked(imcube->actions().indexOf(action) + 200);
}

void QFitsMainWindow::spectralTriggered(QAction *action) {
    imredClicked(spectral->actions().indexOf(action) + 300);
}

void QFitsMainWindow::imredTriggered(QAction *action) {
    imredClicked(imred->actions().indexOf(action) - 4);
}

void QFitsMainWindow::scalingTriggered(QAction *action) {
    int index = scaling->actions().indexOf(action);
    main_view->getCurrentBuffer()->setImageScalingMethod(index);
    updateMenuScaling(index);

#ifdef HAS_VTK
    QFitsSingleBuffer *sb = dynamic_cast<QFitsSingleBuffer*>(
                                                main_view->getCurrentBuffer());
    if (sb != NULL) {
        if (sb->getQFitsWidget3D() != NULL) {
            sb->getQFitsWidget3D()->cubeViewer->newData();
        }
    }
#endif
}

void QFitsMainWindow::moreColormaps() {
    morecolourmaps->show();
}

void QFitsMainWindow::helpClicked(int id) {
    switch (id) {
        case 0:
            about->show();
            break;
        case 1:
            dpuser_widget->executeCommand(QString("help"));
            break;
        case 2:
            dpuser_widget->executeCommand(QString("help functions"));
            break;
        case 3:
            dpuser_widget->executeCommand(QString("help procedures"));
            break;
        default:
            break;
    }
}

void QFitsMainWindow::updateWindowsMenu() {
    if (viewingtools->isVisible()) {
        windows->actions().at(0)->setChecked(true);
    } else {
        windows->actions().at(0)->setChecked(false);
    }
    if (dpuser_widget->isVisible()) {
        windows->actions().at(1)->setChecked(true);
    } else {
        windows->actions().at(1)->setChecked(false);
    }
    if (spectrum->isVisible()) {
        windows->actions().at(2)->setChecked(true);
    } else {
        windows->actions().at(2)->setChecked(false);
    }
    if (toolsWidget->isVisible()) {
        windows->actions().at(3)->setChecked(true);
    } else {
        windows->actions().at(3)->setChecked(false);
    }
}

void QFitsMainWindow::windowsTriggered(QAction *action) {
    if (action->iconText() == "Viewing Tools") {
        if (viewingtools->isVisible()) {
            viewingtools->hide();
        } else {
            viewingtools->show();
        }
    }
    if (action->iconText() == "DPUSER - The Next Generation") {
        if (dpuser_widget->isVisible()) {
            dpuser_widget->hide();
        } else {
            dpuser_widget->show();
        }
    }
    if (action->iconText() == "Spectrum") {
        if (spectrum->isVisible()) {
            spectrum->hide();
        } else {
            spectrum->show();
        }
    }
    if (action->iconText() == "Tools") {
        if (toolsWidget->isVisible()) {
            toolsWidget->hide();
        } else {
            toolsWidget->show();
        }
    }
    if (action->iconText() == "Remove Grid") {
        main_view->showMultiple(1);
    }
    if (action->iconText() == "Grid 2x1") {
        main_view->showMultiple(2);
    }
    if (action->iconText() == "Grid 2x2") {
        main_view->showMultiple(4);
    }
}

void QFitsMainWindow::helpTriggered(QAction *action) {
    if (action->iconText() == "Check for updates") {
//        checkForUpdates *d = new checkForUpdates(this);
//        d->exec();
    } else if (action->iconText() != "About") {
        QString help = "help";
        if (action->iconText() != "Introduction") {
            help += " " + action->iconText().toLower();
        }
        dpuser_widget->executeCommand(help);
    }
}

void QFitsMainWindow::showSpectrum(bool show) {
    if (show) {
        spectrum->show();
    } else {
        spectrum->hide();
    }
}

void QFitsMainWindow::updateScaling() {
    QFitsBaseBuffer *bb = getCurrentBuffer();
    bb->updateScaling();
    updateToolbar();
    viewingtools->cuts_plot->setLimits(bb->getSpecPhysMinY(), bb->getSpecPhysMaxY());
    bb->setYRange();
#ifdef HAS_VTK
    QFitsSingleBuffer *sb = dynamic_cast<QFitsSingleBuffer*>(
                                                main_view->getCurrentBuffer());
    if (sb != NULL) {
        if (sb->getViewMode() == View3D) {
            if (sb->getQFitsWidget3D() != NULL) {
                sb->getQFitsWidget3D()->cubeViewer->newData();
            }
        }
    }
#endif
}

void QFitsMainWindow::adaptFileMenu() {
    QFitsBaseBuffer *bb = getCurrentBuffer();
    QFitsSingleBuffer *sb = dynamic_cast<QFitsSingleBuffer*>(bb);
    if (sb != NULL) {
        menu_displayFitsHeader->setEnabled(true);
    } else {
        QFitsMultiBuffer *mb = dynamic_cast<QFitsMultiBuffer*>(bb);
        sb = mb->getMarkedSingleBuffer();
        if (sb != NULL) {
            menu_displayFitsHeader->setEnabled(true);
        } else {
            menu_displayFitsHeader->setEnabled(false);
        }
    }
}

void QFitsMainWindow::showRGBDialog() {
    rgbdialog->show();
}

void QFitsMainWindow::showCombineDialog() {
    combinedialog->show();
    combinedialog->raise();
}

void QFitsMainWindow::showMpfitDialog() {
    if (mpfitdialog->y->data->currentText() == "<none>") {
        mpfitdialog->y->data->populateAndSelect(getCurrentBuffer()->getBufferIndex().c_str());
        mpfitdialog->somethingChanged();
    }
    mpfitdialog->show();
    mpfitdialog->raise();
}

#ifdef HAS_PLOTTING
void QFitsMainWindow::showPlottingDialog() {
    plplotWindow->show();
    plplotWindow->replot();
}
#endif /* HAS_PLOTTING */

void QFitsMainWindow::updateImageOptions() {
    bool isChecked = imagedisplay->checkboxIgnoreValue->isChecked();
    double val = imagedisplay->lineeditIgnoreValue->text().toDouble();

    spectrum->setIgnore(isChecked, val);
    main_view->getCurrentBuffer()->setIgnore(isChecked, val);
}

void QFitsMainWindow::updateCubeOptions() {
    QFitsBaseBuffer *bb = getCurrentBuffer();

    if (cubeDisplayDialog->getButtonDisplaySingleChecked()) {
        bb->setCubeMode(DisplayCubeSingle, true);
    } else if (cubeDisplayDialog->getButtonDisplayAverageChecked()) {
        bb->setCubeMode(DisplayCubeAverage, true);
    } else if (cubeDisplayDialog->getButtonDisplayMedianChecked()) {
        bb->setCubeMode(DisplayCubeMedian, true);
    } else if (cubeDisplayDialog->getButtonDisplayLinemapChecked()) {
        bb->setCubeMode(DisplayCubeLinemap, true);
    } else {
        dp_debug("SOMETHING IS VERY WRONG HERE!");
    }

    CubeDisplayDialog *dlg = fitsMainWindow->cubeDisplayDialog;
    bb->setLinemapOptions(dlg->getCheckLinemapDoCont1Checked(),
                          dlg->getCheckLinemapDoCont2Checked(),
                          dlg->getLinemapCenterValue(),
                          dlg->getLinemapWidthValue(),
                          dlg->getLinemapCont1Value(),
                          dlg->getLinemapWidth1Value(),
                          dlg->getLinemapCont2Value(),
                          dlg->getLinemapWidth2Value());

    fitsMainWindow->mytoolbar->cubeImageSlice->setValue(dlg->getLinemapCenterValue());

    bb->updateCubeMode();
}

void QFitsMainWindow::updateLinemapInfo(int dummy) {
    QFitsSingleBuffer* sb = dynamic_cast<QFitsSingleBuffer*>(getCurrentBuffer());
    if (sb == NULL) {
        // Alex:  current buffer is QFitsMultiBuffer, think over handling here
        return;
    }
    if (sb->getDpData()->type == typeFits) {
        Fits *f = sb->getDpData()->fvalue;
        if (!(buffersLock.tryLockForRead())) {
            return;
        }
        if (f != NULL) {
            if (f->getCDELT(3) != 0.0) {
                double start_wavelength = f->getCRVAL(3) -
                                          f->getCDELT(3) * (f->getCRPIX(3) - 1.0) +
                                          f->getCDELT(3) * cubeDisplayDialog->getLinemapCenterValue();
                double width_wavelength = f->getCDELT(3) * cubeDisplayDialog->getLinemapWidthValue();
                char value[256];

                f->GetStringKey("CUNIT3", value);
                QString text;
                dpString fstring;
                fstring.sprintf("Center at %8.5f +- %8.5f %s", start_wavelength, width_wavelength, value);
                text = fstring.c_str();
                cubeDisplayDialog->setLinemapWavelengthSliderInformation(NULL, &text, NULL);
            } else {
                QString text1 = "1",
                        text2 = "No wavelength information available",
                        text3;
                dpString fstring;
                fstring.sprintf("%i", f->Naxis(3));
                text3 = fstring.c_str();
                cubeDisplayDialog->setLinemapWavelengthSliderInformation(&text1, &text2, &text3);
            }
        }
        buffersLock.unlock();
    }
}

void QFitsMainWindow::fillBufferMenu() {
    buffer->clear();
    bufferMenuList.clear();
    buffer->addAction("New")->setShortcut(Qt::CTRL+Qt::Key_N);
    buffer->addAction("New from file...")->setShortcut(QKeySequence("Ctrl+Shift+N"));
    buffer->addAction("Duplicate current")->setShortcut(Qt::CTRL+Qt::Key_D);
    buffer->addAction("Delete current")->setShortcut(Qt::CTRL+Qt::Key_W);
    if (blinkTimer->isActive()) {
        buffer->addAction("Stop blinking");
    } else {
        buffer->addAction("Blink buffers...");
    }
    buffer->addSeparator();

    int count = 0;
//    for (QMap<std::string, QFitsBaseBuffer*>::iterator i = main_view->bufferMap.begin(); i != main_view->bufferMap.begin(); i++) {
    for (auto var:main_view->bufferMap) {
//        if (main_view->bufferMap.)
        if ((var.second->getDpData()->type == typeFits) ||
            (var.second->getDpData()->type == typeDpArr) ||
            (var.second->getDpData()->type == typeStrarr))
        {
            if ((var.first != "") && (var.first.find("_") == std::string::npos)) {
                buffer->addAction(createCaption(var.first, false));
                bufferMenuList[count] = var.first;
                count++;
            }
        }
    }
}

void QFitsMainWindow::moveToNextBuffer() {
    bufferChangedByKey = true;
    fillBufferMenu();
    int currentKey = bufferMenuList.key(getCurrentBufferIndex().c_str(), 0);
    if (bufferMenuList.value(currentKey + 1, "") != "") {
        buffersClicked(currentKey + 6);
    } else {
        buffersClicked(5);
    }
}

void QFitsMainWindow::moveToPreviousBuffer() {
    bufferChangedByKey = true;
    fillBufferMenu();
    int currentKey = bufferMenuList.key(getCurrentBufferIndex().c_str(), 0);
    if (bufferMenuList.value(currentKey - 1, "") != "") {
        buffersClicked(currentKey + 4);
    } else {
        buffersClicked(4 + bufferMenuList.size());
    }
}

void QFitsMainWindow::fillUserMenu() {
    _userDialogs::iterator iter;

    userMenu->clear();
    for (iter = userDialogs.begin(); iter != userDialogs.end(); ++iter) {
        userMenu->addAction(iter->first);
    }
}

void QFitsMainWindow::userMenuClicked(int id) {
    imRedUser::showDialog(this, userMenu->activeAction()->text());
}

void QFitsMainWindow::userMenuTriggered(QAction *action) {
    imRedUser::showDialog(this, action->iconText());
}

//#ifdef HAS_VTK
void QFitsMainWindow::showCurrentView(std::string which, dpViewMode previousMode)
//#else
//void QFitsMainWindow::showCurrentView(int which)
//#endif
{
    main_view->setCurrentBufferIndex(which);

    dpViewMode mode = getCurrentBuffer()->getViewMode();
    switch (mode) {
        case ViewImage:
        case ViewWiregrid:
        case ViewContour:
        case ViewTable:
            viewActions->actions()[mode]->setChecked(true);
            break;
//#ifdef HAS_VTK
        case View3D:
            if (previousMode == ViewImage) {
                QFitsSingleBuffer *sb = dynamic_cast<QFitsSingleBuffer*>(getCurrentBuffer());
                if (sb != NULL) {
                    emit(setVisibleRect(sb->getQFitsWidget2D()->viewer->visibleRegion().boundingRect().width(),
                                        sb->getQFitsWidget2D()->viewer->visibleRegion().boundingRect().height()));
                }
            }
            break;
//#endif
        default:
        break;
    }

    getCurrentBuffer()->activateBuffer();
    applyAppearance();
}

void QFitsMainWindow::buffersTriggered(QAction *action) {
    int index = buffer->actions().indexOf(action);

    if (index > 5) {
        index--;
    }
    buffersClicked(index);
}

void QFitsMainWindow::buffersClicked(int which) {
    if (which == 0) {
        // new buffer
        dpuser_widget->executeCommand(QString(freeBufferName().c_str()) +
                                      " = fits(naxis1, naxis2)");
    } else if (which == 1) {
        // new buffer from file
        LoadFile(true);
    } else if (which == 2) {
        // copy current buffer
        dpuser_widget->executeCommand(QString(freeBufferName().c_str()) + " = " +
                          QString(main_view->getCurrentBufferIndex().c_str()));
    } else if (which == 3) {
        // delete current buffer
        dpuser_widget->executeCommand("free " +
                          QString(main_view->getCurrentBufferIndex().c_str()));
    } else if (which == 4) {
        // blink buffers
        if (blinkTimer->isActive())
            blinkTimer->stop();
        else {
            int i;
            QListWidgetItem *item;

            blinkcount = 0;
            blinkdialog->list->clear();
            for (auto var:main_view->bufferMap) {
                if (var.second->getDpData()->type == typeFits) {
                    item = new QListWidgetItem(QString(var.first.c_str()),
                                               blinkdialog->list, Qt::ItemIsUserCheckable);
                    item->setCheckState(Qt::Checked);
                }
            }
            if (blinkdialog->exec()) {
                blinklist.clear();

                for (int row = 0; row < blinkdialog->list->count(); row++) {
                    if (blinkdialog->list->item(row)->checkState() == Qt::Checked) {
                        blinklist.append(blinkdialog->list->item(row)->text());
                    }
                }
                if (blinklist.count() > 1) {
                    blinkTimer->start(blinkdialog->timeout->value());
                }
            }
        }
    } else {
        updateBufferList();

        // which refers to the entries in the Buffer-Menu, there the 5th entry
        // is the first of the loaded buffers
        main_view->setCurrentBufferIndex(bufferMenuList[which-5].c_str());
//        main_view->showFitsBuffer(getCurrentBuffer());
        getCurrentBuffer()->activateBuffer();
        applyAppearance();
    }
}

void QFitsMainWindow::updateToolbar() {
    QFitsBaseBuffer   *bb = NULL;
    QFitsMultiBuffer  *mb = NULL;
    QFitsSingleBuffer *sb = getActualSB();

    if (sb == NULL) {
        bb = main_view->getBuffer(getCurrentBufferIndex());
        sb = dynamic_cast<QFitsSingleBuffer*>(bb);
        mb = dynamic_cast<QFitsMultiBuffer*>(bb);
        if (bb == NULL) {
            return;
        }
    } else {
        bb = sb;
    }

//#ifdef HAS_VTK
    if ((sb != NULL) &&
        ((sb->getViewMode() == View3D) || (sb->getViewMode() == ViewWiregrid)))
    {
        mytoolbar->setZoomTextCombo(sb->getZoomFactor_3Dwire());
    } else
//#endif
    {
        mytoolbar->setZoomTextCombo(bb->getZoomFactor());
    }
    mytoolbar->updateImageMinMax(bb);
    mytoolbar->updateSpecMinMaxY(bb);

    QPalette pal(palette());
    bool active = false;
    if (sb != NULL) {
        // enable toolbar controls for editing
        pal.setColor(QPalette::Window, Qt::white);
        active = true;

        if (sb->Naxis(0) == 1) {
            QReadLocker locker(&buffersLock);
            sb->setData();
        } else {
            main_view->getWedge()->update();
        }        
    } else if (mb != NULL) {
        // disable toolbar controls for editing (just update with values from
        // buffer under cursor)
//        pal.setColor(QPalette::Background, QPalette::Window);
//        if (mb->hasCubeSpecHomogenSB()) {
            active = true;
//        } else {
//            active = false;
//        }

        main_view->getWedge()->update();

        if (!mb->getAppearance().hideViewingtools) {
            viewingtools->show();
            viewingtools->magnifier->update();
            viewingtools->total->update();
        }
    }

    mytoolbar->enableControlsView1D(active);
    mytoolbar->enableControlsView2D(active);
    mytoolbar->setPaletteControls(pal);

    mytoolbar->showControls();
}

void QFitsMainWindow::viewTriggered(QAction *action) {
    dpViewMode mode = (dpViewMode)viewActions->actions().indexOf(action);
    viewClicked(mode);

    switch(mode) {
    case ViewTable:
    case ViewImage:
        main_view->initialResize();
        break;
    default:
        break;
    }
}

void QFitsMainWindow::viewClicked(dpViewMode newViewMode) {
    QFitsBaseBuffer *bb = getCurrentBuffer();
    dpViewMode previousMode = bb->getViewMode();
    if (newViewMode != previousMode) {
        bb->ChangeWidgetState(newViewMode);
        bb->setFocus();

        QFitsSingleBuffer* sb = dynamic_cast<QFitsSingleBuffer*>(bb);
        if (sb != NULL) {
            switch (newViewMode) {
                case ViewImage:
                    mytoolbar->setZoomTextCombo(bb->getZoomFactor());
                    break;
                case ViewWiregrid:
                case ViewContour:
                case ViewTable:
                    break;
//            #ifdef HAS_VTK
                case View3D:
                    if (previousMode == ViewImage) {
                        // deactivate any possibly selected continuum
                        // and update image to get correct colormap again before
                        // displaying the cube
                        sb->setLineCont1(false);
                        sb->setLineCont2(false);
                        sb->getState()->setupColours();
                    }

//                    if (sb != NULL) {
//                        sb->getQFitsWidget3D(true)->cubeViewer->newData2();
//                    }
                    break;
//            #endif
                default:
                    break;
            }

            updateTotalVisibleRect();
        }

//    #ifdef HAS_VTK
        showCurrentView(main_view->getCurrentBufferIndex(), previousMode);
//    #else
//        showCurrentView(main_view->getCurrentBufferIndex());
//    #endif
    }
}

void QFitsMainWindow::dpuserExecuteScript() {
    scriptEditor->show();
    scriptEditor->open();
}

void QFitsMainWindow::dpuserChangeDirectory() {
    QString dir = QFileDialog::getExistingDirectory(this, "Select working directory", settings.lastOpenPath);
    if (!dir.isNull()) {
        dpuser_widget->executeCommand("cd \"" + dir + "\"");
        settings.lastOpenPath = dir;
    }
}

void QFitsMainWindow::dpuserCopyHistory() {
    QApplication::clipboard()->setText(dpuser_widget->list->join("\n"));
}

void QFitsMainWindow::longslitChangedValues(int xcenter, int ycenter,
                                            double angle, int slitwidth, double opening_angle)
{
    QFitsSingleBuffer *sb = dynamic_cast<QFitsSingleBuffer*>(getCurrentBuffer());
    if (sb != NULL) {
        sb->getQFitsWidget2D()->viewer->updateLongslitMarker(xcenter, ycenter,
                                                            angle, slitwidth, opening_angle);
    }
}

void QFitsMainWindow::ellipticalProfileChangedValues(int xcenter, int ycenter,
                                                     double angle, double ratio,
                                                     int slitwidth)
{
    QFitsSingleBuffer *sb = dynamic_cast<QFitsSingleBuffer*>(getCurrentBuffer());
    if (sb != NULL) {
        sb->getQFitsWidget2D()->viewer->updateEllipticalProfileMarker(xcenter, ycenter,
                                                                      angle, ratio,
                                                                      slitwidth);
    }
}

void QFitsMainWindow::markposChangedValues(QVector<int> center)
{
    QFitsSingleBuffer *sb = dynamic_cast<QFitsSingleBuffer*>(getCurrentBuffer());
    if (sb != NULL) {
        sb->getQFitsWidget2D()->viewer->updateMarkposMarker(center);
    }
}

void QFitsMainWindow::fillViewMenu() {
    // ViewImage always enabled
    viewActions->actions()[ViewImage]->setEnabled(true);

    // Check if ViewWiregrid & ViewContour should be enabled
    QFitsSingleBuffer *sb  = dynamic_cast<QFitsSingleBuffer*>(getCurrentBuffer());
    if (sb != NULL) {
        if (sb->Naxis(0) == 2) {
            viewActions->actions()[ViewWiregrid]->setEnabled(true);
            viewActions->actions()[ViewContour]->setEnabled(true);
        } else {
            viewActions->actions()[ViewWiregrid]->setEnabled(false);
            viewActions->actions()[ViewContour]->setEnabled(false);
        }
        if (sb->Naxis(0) == 3) {
            viewActions->actions()[ViewTable]->setEnabled(false);
        } else {
            viewActions->actions()[ViewTable]->setEnabled(true);
        }
    }

    // Check if ViewTable should be enabled
    QFitsMultiBuffer *mb  = dynamic_cast<QFitsMultiBuffer*>(getCurrentBuffer());
    if (mb != NULL) {
        if (!mb->hasCubeSpecHomogenSB()) {
            viewActions->actions()[ViewWiregrid]->setEnabled(false);
            viewActions->actions()[ViewContour]->setEnabled(false);
        } else {
            if (mb->getHasImage()) {
                viewActions->actions()[ViewWiregrid]->setEnabled(true);
                viewActions->actions()[ViewContour]->setEnabled(true);
            } else {
                viewActions->actions()[ViewWiregrid]->setEnabled(false);
                viewActions->actions()[ViewContour]->setEnabled(false);
            }
        }

        if ((mb->getHasChildMB() || mb->getHasCube())) {
            viewActions->actions()[ViewTable]->setEnabled(false);
        } else {
            viewActions->actions()[ViewTable]->setEnabled(true);
        }
    }

#ifdef HAS_VTK
    // Check if View3D should be enabled
    if ((sb != NULL) && (sb->Naxis(0) == 3)) {
        viewActions->actions()[View3D]->setEnabled(true);
    } else {
        viewActions->actions()[View3D]->setEnabled(false);
    }
#endif
}

void QFitsMainWindow::dpuserProgress(const int &progress, const QString &message) {

    if (progress < 0) {
        progressbar->setMinimum(0);
        progressbar->setMaximum(-progress);
        progressbar->setValue(0);
    } else if (progress == 0) {
        progressbar->reset();
        statusBar()->showMessage(message);
        QApplication::restoreOverrideCursor();
    } else if (progress < progressbar->maximum()) {
        if (!overrideSet) {
            overrideSet = true;
            QApplication::setOverrideCursor(Qt::WaitCursor);
            // disable "Display FITS Header" menu entry
            menu_displayFitsHeader->setEnabled(false);
        }
        progressbar->setValue(progress);
        statusBar()->showMessage(message);
    } else {
        overrideSet = false;
        QApplication::restoreOverrideCursor();
        // enable "Display FITS Header" menu entry
        menu_displayFitsHeader->setEnabled(true);
        progressbar->reset();
        statusBar()->clearMessage();
    }
}

void QFitsMainWindow::dpuserHelp(const QString &request) {
    QString what = request;

    if (what == "") {
        what = "index.html";
    } else if (what == "functions") {
        what = "functions.html";
    } else if (what == "procedures") {
        what = "procedures.html";
    }
    dphelp->setMainUrl(QUrl(what));
    dphelp->show();
/*
    if (settings.docuPath.length() > 2) {
        if (settings.docuPath.at(settings.docuPath.length() - 1) != '/') {
            settings.docuPath += "/";
        }
        if (settings.docuPath.left(4) != "http") {
            if (QFile::exists(settings.docuPath + what)) {
                QDesktopServices::openUrl(QUrl::fromLocalFile(settings.docuPath + what));
            } else {
                dp_output("no help available for %s", request.toStdString().c_str());
            }
        } else {
            QDesktopServices::openUrl(QUrl(settings.docuPath + what));
        }
    } else {
        QDesktopServices::openUrl(QUrl("http://www.mpe.mpg.de/~ott/dpuser/" + what));
    }
*/
}

void QFitsMainWindow::dpuserVar(const std::string &id) {
    bool updateView = true;
dp_debug("---------- dpuserVar() ----------\n"); fflush(stdout);
    if (((dpuser_vars[id].type != typeFits) &&
         (dpuser_vars[id].type != typeDpArr) &&
         (dpuser_vars[id].type != typeStrarr)) ||
        (looplock > 0))      // in looplock mode, do nothing
    {
        if (main_view->hasBaseBuffer(id)) {
            if (main_view->getCurrentBufferIndex() == id) {
                for (auto var:dpuser_vars) {
                    if ((var.second.type == typeFits) ||
                            (var.second.type == typeDpArr) ||
                            (var.second.type == typeStrarr)) {
                        main_view->setCurrentBufferIndex(var.first);
                        getCurrentBuffer()->activateBuffer();
                        applyAppearance();

                        break;
                    }
                }
//                int iii = 0;
//                while ((variables[iii].type != typeFits) &&
//                       (variables[iii].type != typeDpArr) &&
//                       (variables[iii].type != typeStrarr) &&
//                       (iii < nvariables))
//                {
//                    iii++;
//                }
//                if (iii < nvariables) {
//                    main_view->setCurrentBufferIndex(iii);
//                    getCurrentBuffer()->activateBuffer();
//                    applyAppearance();
//                }
            }
            main_view->deleteBaseBuffer(id);
        }
        return;
    }

    // Don't update if the variable starts with an underscore or ends
    // with _standardstar (because this then comes from inside QFitsView)
    if ((QString(id.c_str()).right(13) == "_standardstar") ||
        (QString(id.c_str()).left(1) == "_"))
    {
        updateView = false;
    }


    //
    // Update, recreate or add buffer here
    //
    dpuserType *dpt = new dpuserType(dpuser_vars[id]);
    QFitsBaseBuffer *bb = NULL;

    QReadLocker locker(&buffersLock);

    zoomCorr_spectrumVisible = spectrum->isVisible();
    zoomCorr_wedgeVisible = main_view->getWedge()->isVisible();

    if (main_view->bufferMapContainsKey(id)) {
        // buffer exists already
        bb = main_view->getBuffer(id);
        QFitsSingleBuffer     *sb  = dynamic_cast<QFitsSingleBuffer*>(bb);
        QFitsMultiBuffer      *mb  = dynamic_cast<QFitsMultiBuffer*>(bb);
        if (((sb != NULL)  && (dpuser_vars[id].type == typeFits)) ||
            ((mb != NULL)  && (dpuser_vars[id].type == typeDpArr)))
        {
            // variable changed in dpuser AND is same type of buffer -> update buffer
            bb = main_view->updateBuffer(id, dpt);
        } else {
            // variable changed in dpuser AND is different type of buffer -> recreate buffer
            bb = main_view->recreateBuffer(id, dpt);
        }
    } else {
        // new variable in dpuser -> add new buffer
        bb = main_view->addNewBuffer(id, dpt);
    }

    if (bb != NULL) {
        main_view->setCurrentBufferIndex(id);

        if (updateView) {
            locker.unlock();
            bb->activateBuffer();
            applyAppearance();

            if (!resetGUIsettings) {
                mytoolbar->comboZoom->setEditText(preferences->GetInitialZoom());
                FitZoom fz;
                double zoomValue = mytoolbar->getZoomTextCombo(&fz);
                bb->zoomTextChanged(zoomValue, fz);
            }
            bb->updateScaling();
        }
        main_view->initialResize();
    }
    resetGUIsettings = true;
    markposDialog->clearValues();
}

void QFitsMainWindow::dpuserView(const std::string &id) {
    bool updateView = true;
dp_debug("---------- dpuserVar() ----------\n"); fflush(stdout);
    if (((dpuser_vars[id].type != typeFits) &&
         (dpuser_vars[id].type != typeDpArr) &&
         (dpuser_vars[id].type != typeStrarr)) ||
        (looplock > 0))      // in looplock mode, do nothing
    {
        if (main_view->getCurrentBufferIndex() == id) {
            for (auto var:dpuser_vars) {
                if ((var.second.type == typeFits) ||
                        (var.second.type == typeDpArr) ||
                        (var.second.type == typeStrarr)) {
                    main_view->setCurrentBufferIndex(var.first);
                    getCurrentBuffer()->activateBuffer();
                    applyAppearance();

                    break;
                }
            }
        }
        main_view->deleteBaseBuffer(id);
        return;
    }

    // Don't update if the variable starts with an underscore or ends
    // with _standardstar (because this then comes from inside QFitsView)
    if ((QString(id.c_str()).right(13) == "_standardstar") ||
        (QString(id.c_str()).left(1) == "_"))
    {
        updateView = false;
    }


    //
    // Update, recreate or add buffer here
    //
    dpuserType *dpt = new dpuserType(dpuser_vars[id]);
    QFitsBaseBuffer *bb = NULL;

    QReadLocker locker(&buffersLock);

    zoomCorr_spectrumVisible = spectrum->isVisible();
    zoomCorr_wedgeVisible = main_view->getWedge()->isVisible();

    if (main_view->bufferMapContainsKey(id)) {
        // buffer exists already
        bb = main_view->getBuffer(id);
        QFitsSingleBuffer     *sb  = dynamic_cast<QFitsSingleBuffer*>(bb);
        QFitsMultiBuffer      *mb  = dynamic_cast<QFitsMultiBuffer*>(bb);
    } else {
        // new variable in dpuser -> add new buffer
        bb = main_view->addNewBuffer(id, dpt);
    }

    if (bb != NULL) {
        main_view->setCurrentBufferIndex(id);

        if (updateView) {
            locker.unlock();
            bb->activateBuffer();
            applyAppearance();

            if (!resetGUIsettings) {
                mytoolbar->comboZoom->setEditText(preferences->GetInitialZoom());
                FitZoom fz;
                double zoomValue = mytoolbar->getZoomTextCombo(&fz);
                bb->zoomTextChanged(zoomValue, fz);
            }
            bb->updateScaling();
        }
        main_view->initialResize();
    }
    resetGUIsettings = true;
}

void QFitsMainWindow::dpuserCommand(const QString &cmd, const QString &arg, const int &option) {
    if (cmd == "markpos") {
//        markposDialog->show();
        markposDialog->clearValues();
        markposDialog->setRadius(arg.toInt());
        markposDialog->setMethod(option);
        toolsWidget->setCurrentWidget(markposDialog);
        markposDialog->show();
        toolsWidget->show();
        activateWindow();
    } else if (cmd == "message") {
        switch(option) {
        case 4:
            QMessageBox::critical(this, "dpuser", arg);
            break;
        case 2:
            QMessageBox::warning(this, "dpuser", arg);
            break;
        default:
            QMessageBox::information(this, "dpuser", arg);
            break;
        }

        dpusermutex->unlock();
    } else if (cmd == "setBrightnessContrast") {
        QStringList l = arg.split(" ");
        main_view->setBrightness(l[0].toInt());
        main_view->setContrast(l[1].toInt());
    } else if (cmd == "question") {
        DPQuestion = 0;
        if (QMessageBox::question(this, "dpuser", arg) == QMessageBox::Yes) DPQuestion = 1;
        dpusermutex->unlock();
#ifdef LBT
    } else if (cmd == "luci1align") {
        QStringList l = arg.split(" ");
        luciMaskAlign->updateValue(0, l[0].toDouble());
        luciMaskAlign->updateValue(1, l[1].toDouble());
        luciMaskAlign->updateValue(2, l[2].toDouble());
    } else if (cmd == "luci2align") {
        QStringList l = arg.split(" ");
        luciMaskAlign->updateValue(3, l[0].toDouble());
        luciMaskAlign->updateValue(4, l[1].toDouble());
        luciMaskAlign->updateValue(5, l[2].toDouble());
    } else if (cmd == "luci1files") {
        QStringList l = arg.split(" ");
        luciMaskAlign->updateFilename(0, l[0]);
        luciMaskAlign->updateFilename(1, l[1]);
        luciMaskAlign->updateFilename(2, l[2]);
    } else if (cmd == "luci2files") {
        QStringList l = arg.split(" ");
        luciMaskAlign->updateFilename(3, l[0]);
        luciMaskAlign->updateFilename(4, l[1]);
        luciMaskAlign->updateFilename(5, l[2]);
#endif
#ifdef HAS_PLPLOT
    } else if (cmd == "plplot") {
        if (arg == "show") {
            plsstrm(pg2plplotWindow[option]->strm);
            pg2plplotWindow[option]->show();
            pg2plplotWindow[option]->raise();
        } else if (arg == "update") {
            pg2plplotWindow[option]->update();
        }
#endif /* HAS_PLPLOT */
    }
}

void QFitsMainWindow::updatePgplot(const int &which, const QImage &image) {
    if (which < 0 || which > 9) {
        QMessageBox::warning(this, "QFitsView", "Too many PGPLOT windows open");
        return;
    }
    if (image.isNull()) return;
    if (image.width() == qpgplot_windows[which]->plotter->width() && image.height() == qpgplot_windows[which]->plotter->height()) {
      qpgplot_windows[which]->plotter->pixmap = QPixmap::fromImage(image);
    } else {
      qpgplot_windows[which]->plotter->pixmap = QPixmap::fromImage(image.scaled(width(), height()));
    }
    qpgplot_windows[which]->show();
    qpgplot_windows[which]->raise();

    qpgplot_windows[which]->plotter->update();
}

void QFitsMainWindow::updatePgplot(const int &which, const int &w, const int &h) {
    if (which < 0 || which > 9) {
        QMessageBox::warning(this, "QFitsView", "Too many PGPLOT windows open");
        return;
    }

    qpgplot_windows[which]->resize(w, h);
}

void QFitsMainWindow::reloadImage() {
    QString fname;
    std::string bufferIndex = main_view->getCurrentBufferIndex();

    if (dpuser_vars[bufferIndex].type == typeFits) {
        fname = dpuser_vars[bufferIndex].fvalue->getFileName();
    } else if (dpuser_vars[bufferIndex].type == typeDpArr) {
        fname = dpuser_vars[bufferIndex].dparrvalue->at(0)->getFileName();
    } else if (dpuser_vars[bufferIndex].type == typeStrarr) {
        fname = dpuser_vars[bufferIndex].arrvalue->getFileName();
    }

    if (fname.size() > 0) {
        int pos = fname.indexOf(", ext");
        if (pos != -1) {
            fname.chop(fname.size() - pos);
        }

        if (dpuser_vars[bufferIndex].type == typeFits) {
            Fits _tmp;
            int numExtensions = _tmp.CountExtensions(fname.toLocal8Bit().constData());
            if (numExtensions < 1) {
                // load normally
                dpuser_widget->executeCommand(
                        QString(bufferIndex.c_str()) +
                        QString(" = readfits(\"") + fname + "\")");
            } else {
                // show Advanced Dialog
                dpFitsExtensionDialog *dialog = new dpFitsExtensionDialog(this, fname, FALSE);
                dialog->exec();
            }
        } else if (dpuser_vars[bufferIndex].type == typeDpArr) {
            // show Advanced Dialog
            dpFitsExtensionDialog *dialog = new dpFitsExtensionDialog(this, fname, FALSE);
            dialog->exec();
        } else if (dpuser_vars[bufferIndex].type == typeStrarr) {
            // show Advanced Dialog
            dpFitsExtensionDialog *dialog = new dpFitsExtensionDialog(this, fname, FALSE);
            dialog->exec();
        }
    }
}

void QFitsMainWindow::dpuserInterrupt() {
    FitsInterrupt = 1;
    ScriptInterrupt = 1;
    dp_output("Interrupt Encountered");
    QApplication::restoreOverrideCursor();
    overrideSet = false;
    menu_displayFitsHeader->setEnabled(true);
    progressbar->reset();
    statusBar()->clearMessage();
}

void QFitsMainWindow::updateOrientation() {
    getCurrentBuffer()->orientationChanged();
}

void QFitsMainWindow::longslitChangedCenter(int x, int y) {
    emit longslitCenterChanged(x, y);
}

void QFitsMainWindow::longslitChangedAngle(double angle) {
    emit longslitAngleChanged(angle);
}

void QFitsMainWindow::markposNewPosition(int x, int y) {
    emit markPosition(x, y);
}

void QFitsMainWindow::updateCubeMode(int mode) {
    QFitsBaseBuffer *bb = getCurrentBuffer();
    bb->setCubeMode((dpCubeMode)mode, true);
    bb->updateCubeMode();
}

void QFitsMainWindow::blinkTimerTimeout() {
    int i, index = -1;
    blinkcount++;
    if (blinkcount == blinklist.count()) {
        blinkcount = 0;
    }

    for (i = 0; i < bufferMenuList.count(); i++) {
        if (QString(bufferMenuList[i].c_str()) == blinklist[blinkcount]) {
            index = i;
        }
    }

    if (index != -1) {
        buffersClicked(index + 5);
    }
}

void QFitsMainWindow::DisplayFITSHeader() {
    QFitsSingleBuffer* sb = dynamic_cast<QFitsSingleBuffer*>(getCurrentBuffer());
    if (sb == NULL) {
        QFitsMultiBuffer* mb = dynamic_cast<QFitsMultiBuffer*>(getCurrentBuffer());
        if (mb != NULL) {
            sb = dynamic_cast<QFitsSingleBuffer*>(mb->getMarkedSingleBuffer());
            if (sb == NULL) {
                return;
            }
        }
    }

    dpuserType *dp = sb->getDpData();
    if ((dp->type == typeFits) &&
        (dp->fvalue != NULL))
    {
        headerView->showUp(dp->fvalue);
    }
}

void QFitsMainWindow::LoadClicked() {
    LoadFile(false);
}

void QFitsMainWindow::LoadFile(bool isNewBuffer) {
    QString fname = QFileDialog::getOpenFileName(this, "QFitsView - Open File", settings.lastOpenPath,
                                                 "Fits files (*.fits *.fts *.fits.gz *.fts.gz);;"
                                                 "All files (*)");

    if (fname.size() > 0) {
        Fits _tmp;
        QByteArray s = fname.toLocal8Bit();
        int numExtensions = _tmp.CountExtensions(s.constData());
        if (numExtensions < 1) {
            // load normally
            QString cmd, buffername;
            QFileInfo finfo(fname);
            settings.lastOpenPath = finfo.absoluteDir().path();
            settings.lastOpenPath.replace("\\", "/");
            fname.replace("\\", "/");

            if (isNewBuffer) {
                buffername = freeBufferName().c_str();
            } else {
                buffername = QString(fitsMainWindow->getCurrentBufferIndex().c_str());
            }

            cmd = buffername + " = readfits(\"" + fname + "\")";

            QApplication::setOverrideCursor(Qt::WaitCursor);
            dpuser_widget->executeCommand(cmd);
            QApplication::restoreOverrideCursor();
            updateBufferList();

        } else {
            // show Advanced Dialog
            dpFitsExtensionDialog *dialog = new dpFitsExtensionDialog(this, fname, isNewBuffer);
            dialog->exec();
        }
    }
}


void QFitsMainWindow::ImportClicked() {
    QString fname, cmd;
    fname = QFileDialog::getOpenFileName(this, "QFitsView - Import File", settings.lastOpenPath,
                           "Text files (*.txt);;"
                           "All files (*)");

    if (!fname.isNull()) {
        QFileInfo finfo(fname);
        settings.lastOpenPath = finfo.absoluteDir().path();
        settings.lastOpenPath.replace("\\", "/");
        fname.replace("\\", "/");

        dpImportDialog importdialog(this, fname);

        if (importdialog.exec()) {

            cmd = QString(main_view->getCurrentBufferIndex().c_str());
            if (cmd == "buffer1") cmd = freeBufferName().c_str();
            cmd += " = import(\"";
            cmd += fname;
            cmd += "\"";
            if (importdialog.importNumber->isChecked()) {
                cmd += ", " + QString::number(importdialog.columns->value());
                cmd += ", \"" + importdialog.delimiter->currentText().left(1) + "\"";
                if (importdialog.useComment->isChecked()) {
                    cmd += ", \"" + importdialog.comment->text() + "\"";
                } else {
                    cmd += ", \"\"";
                }
                cmd += ", " + QString::number(importdialog.skiplines->value());
                cmd += ", /number";
            } else {
                cmd += ", /text";
            }
            cmd += ")";

            dpuser_widget->executeCommand(cmd);
        }
    }
}

void QFitsMainWindow::applyAppearance() {
    QFitsBaseBuffer *bb = getCurrentBuffer();
    BufferAppearance ba = bb->updateAppearance();

    imred->setEnabled(ba.enableImredMenu);
    mytoolbar->enableControlsArithmetic(ba.enableArithmeticButtons);
    map->setEnabled(ba.enableColourmapMenu);
    scaling->setEnabled(ba.enableScaleMenu);
    zoom->setEnabled(ba.enableZoomMenu);

    if (ba.hideViewingtools) {
        fitsMainWindow->viewingtools->hide();
    } else {
        fitsMainWindow->viewingtools->show();
    }
    if (ba.hideViewingtoolsCutsplot) {
        fitsMainWindow->viewingtools->cuts_plot->hide();
    } else {
        fitsMainWindow->viewingtools->cuts_plot->show();
    }
    if (ba.hideWedge) {
        fitsMainWindow->main_view->getWedge()->hide();
    } else {
        fitsMainWindow->main_view->getWedge()->show();
    }
    if (ba.hideSpectrum) {
        fitsMainWindow->spectrum->hide();
    } else {
        fitsMainWindow->spectrum->enableControls(ba.enableSpectrumControls);
        fitsMainWindow->spectrum->show();
    }

    updateToolbar();

    switch (ba.toolsVisible) {
        case Tools_2Dfit:
            fitsMainWindow->toolsWidget->setCurrentWidget(fitsMainWindow->fitter2d);
            break;
        case Tools_Markpos:
            fitsMainWindow->toolsWidget->setCurrentWidget(fitsMainWindow->markposDialog);
            fitsMainWindow->markposDialog->updateMethod();
            break;
        default:
            fitsMainWindow->toolsWidget->setCurrentWidget(fitsMainWindow->emptyTool);
            break;
    }

    // update checkmark in colourmap-menu
    bb->getColormap()->setChecked(true);
    invertAction->setChecked(bb->getInvertColormap());

    setWindowTitle(ba.windowTitle);

    arrangeChildren();
}

QFitsSingleBuffer* QFitsMainWindow::getActualMarkedSB() {
    QFitsMultiBuffer *mb = dynamic_cast<QFitsMultiBuffer*>(getCurrentBuffer());
    if (mb != NULL) {
        return mb->getMarkedSingleBuffer();
    }
    return NULL;
}

void QFitsMainWindow::setDirToWatch(const dpString &d, const dpString &pattern, const dpString &whatToDo) {
    fsWatcher.removePaths(fsWatcher.directories());
    QString dir = d.c_str();
    if (!dir.isEmpty()) {
        if (fsWatcher.addPath(dir)) {
            FileSystemChangedAction = whatToDo.c_str();
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
            if (pattern.size() == 0) FileSystemChangedPattern.setPattern("*");
            else FileSystemChangedPattern.setPattern(pattern.c_str());
            FileSystemChangedPattern.setPatternSyntax(QRegExp::Wildcard);
#else
            if (pattern.size() == 0)
                FileSystemChangedPattern.setPattern(QRegularExpression::anchoredPattern(QRegularExpression::wildcardToRegularExpression("*")));
            else
                FileSystemChangedPattern.setPattern(QRegularExpression::anchoredPattern(QRegularExpression::wildcardToRegularExpression(pattern.c_str())));
#endif /* QT_VERSION */
        }
        QDir dirw(dir);
        dirEntryList = dirw.entryList(QDir::NoDotAndDotDot | QDir::Files);
    }
}

void QFitsMainWindow::FileSystemChanged(const QString &path) {
    QDir dir;
    dir.setPath(path);

    QStringList newEntryList = dir.entryList(QDir::NoDotAndDotDot | QDir::Files);

#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QSet<QString> newDirSet = QSet<QString>::fromList(newEntryList);
    QSet<QString> currentDirSet = QSet<QString>::fromList(dirEntryList);
#else
    QSet<QString> newDirSet(newEntryList.begin(), newEntryList.end());
    QSet<QString> currentDirSet(dirEntryList.begin(), dirEntryList.end());
#endif /* QT_VERSION */

   // Files that have been added
    QSet<QString> newFiles = newDirSet - currentDirSet;
		
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QStringList newFile = newFiles.toList();
#else
    QStringList newFile(newFiles.begin(), newFiles.end());
#endif /* QT_VERSION */

    dirEntryList = newEntryList;

    if (!newFile.isEmpty()) {
        QString fileName;
        for (int i = 0; i < newFile.size(); i++) {
            fileName = newFile.at(i);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
            if (FileSystemChangedPattern.exactMatch(fileName)) {
#else
            if (FileSystemChangedPattern.match(fileName).hasMatch()) {
#endif /* QT_VERSION */
                QString act = FileSystemChangedAction;
                act.replace("$$", "\"" + dir.absoluteFilePath(fileName) + "\"");
                dpuser_widget->executeCommand(act);
            }
        }
    }
}
