/***************************** LICENSE START ***********************************

 Copyright 2016 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include "uPlotBase.h"

// Qt include files
#include <QAbstractPrintDialog>
#include <QAction>
#include <QComboBox>
#include <QDebug>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QHBoxLayout>
#include <QMenu>
#include <QMessageBox>
#include <QPrinter>
#include <QPrintDialog>
#include <QPushButton>
#include <QStringList>
#include <QToolButton>
#include <QVBoxLayout>
#include <QWidgetAction>

//#ifndef QT_NO_OPENGL
//#include <QGLWidget>
//#endif

// My Qt include files
#include "MgQPlotScene.h"
#include "MgQRootItem.h"
#include "MgQSceneItem.h"

#include "ExportDialog.h"
#include "MvQAbout.h"
#include "MvQApplication.h"
#include "MvQEcChartsDialog.h"
#include "MvQMethods.h"

#ifdef METVIEW_WEATHER_ROOM
#include "MvQWeatherRoomDialog.h"
#endif

#include "MvQPlotView.h"
#include "MvQZoomStackWidget.h"

#ifdef METVIEW_ODB_NEW
#include "odb_api/odbcapi.h"
#endif


#include "MagPlusService.h"
#include "../libMetview/Path.h"  // path given to disambiguate from Magics Path.h
#include "MvMiscelaneous.h"
#include "ObjectList.h"
#include "PlotMod.h"
#include "PlotModView.h"
#include "Root.h"

//#define PLACEMARK

Presentable* uPlotBase::owner_  = 0;
string uPlotBase::uPlotTempDir_ = "";

uPlotBase::uPlotBase(QWidget* parent) :
    MvQMainWindow(parent)
{
#ifdef METVIEW_WEATHER_ROOM
    wroomSync_ = false;
#endif

    //Find out screen resolution
    int res = screenResolutionInDpi();

    //resize(1020,720);

    oriPlotWidthInCm_  = -1.;
    oriPlotHeightInCm_ = -1.;

    //---------------------
    // The scene
    //---------------------

    plotScene_ = new MgQPlotScene;
    plotScene_->setSceneRect(QRectF());
    plotScene_->setDpiResolution(res);

    activeScene_ = 0;

    //---------------------
    // The view
    //---------------------

    plotView_ = new MvQPlotView(plotScene_);
    plotView_->setMouseTracking(true);
    plotView_->setBackgroundBrush(QColor(125, 124, 123));

    connect(plotView_, SIGNAL(contextMenuEventHappened(const QPoint&, const QPointF&)),
            this, SLOT(slotBuildContextMenu(const QPoint&, const QPointF&)));

    connect(plotView_, SIGNAL(resizeEventHappened(const QSize&)),
            this, SLOT(slotResizeEvent(const QSize&)));

    connect(plotView_, SIGNAL(zoomRectangleIsDefined(const string&, const string&)),
            this, SLOT(slotPerformZoom(const string&, const string&)));

    connect(plotView_, SIGNAL(iconDropped(const MvQDrop&, QPoint)),
            this, SLOT(slotProcessDropInView(const MvQDrop&, QPoint)));

    actionContextSelectScene_ = 0;
    actionContextZoomUp_      = 0;
    actionContextZoomDown_    = 0;

    // Setup Drag-Drop connection
    // 	connect(QApplication::instance(), SIGNAL(sendDropInfo(MvQIconDropItem* )),
    //	        this, SLOT(processDrop(MvQIconDropItem*)));

    connect(this, SIGNAL(sendDropRequest(MvRequest*)),
            QApplication::instance(), SLOT(processDropRequest(MvRequest*)));

    // Create a temporary directory related to this session
    std::string errText;
    if (!metview::createWorkDir("uplot", uPlotTempDir_, errText)) {
        uPlotTempDir_ = getenv("METVIEW_TMPDIR");  // fallback position
    }
    uPlotTempDir_ += "/";
    Path path(uPlotTempDir_);
    path.mkdir();
}

uPlotBase::~uPlotBase()
{
    owner_ = 0;

    // Delete temporary directory
    Path path(tempDir());
    path.remove();
}

void uPlotBase::setupViewActions()
{
    QAction* action;

    //------------------
    // Resize
    //------------------

    //Plot size combo
    sizeCombo_ = new QComboBox;

    sizeMinValue_  = 10;
    sizeMaxValue_  = 200;
    sizeValueStep_ = 10;

    predefSizeValues_ << uPlotBase::FitToWindow << uPlotBase::FitToWidth << uPlotBase::FitToHeight << 50 << 75 << 100 << 150 << 200;

    customSizeItemIndex_ = predefSizeValues_.count();

    foreach (int val, predefSizeValues_) {
        if (val == uPlotBase::FitToWindow) {
            sizeCombo_->addItem(tr("Fit to Window"));
        }
        else if (val == uPlotBase::FitToWidth) {
            sizeCombo_->addItem(tr("Fit to Width"));
        }
        else if (val == uPlotBase::FitToHeight) {
            sizeCombo_->addItem(tr("Fit to Height"));
        }
        else {
            QString s = QString::number(val) + "%";
            sizeCombo_->addItem(s);
        }

        sizeCombo_->setItemData(sizeCombo_->count() - 1, val, Qt::UserRole);
    }

    //sizeCombo_->setCurrentIndex(4);

    action = new QAction(this);
    action->setText(tr("Decrease size"));
    action->setIcon(QIcon(QPixmap(QString::fromUtf8(":/uPlot/size_down.svg"))));
    actionSizeDown_ = action;

    action = new QAction(this);
    action->setText(tr("Increase size"));
    action->setIcon(QIcon(QPixmap(QString::fromUtf8(":/uPlot/size_up.svg"))));
    actionSizeUp_ = action;

    connect(sizeCombo_, SIGNAL(currentIndexChanged(int)),
            this, SLOT(slotSizeChanged(int)));

    connect(actionSizeDown_, SIGNAL(triggered()),
            this, SLOT(slotSizeDown()));

    connect(actionSizeUp_, SIGNAL(triggered()),
            this, SLOT(slotSizeUp()));

    QAction* sep = new QAction(this);
    sep->setSeparator(true);

    MvQMainWindow::MenuType menuType = MvQMainWindow::ViewMenu;

    menuItems_[menuType].push_back(new MvQMenuItem(sizeCombo_));
    menuItems_[menuType].push_back(new MvQMenuItem(actionSizeDown_));
    menuItems_[menuType].push_back(new MvQMenuItem(actionSizeUp_));
}

void uPlotBase::setupZoomActions()
{
    //Zoom
    QAction* actionZoom = new QAction(this);
    actionZoom->setObjectName(QString::fromUtf8("actionZoom"));
    actionZoom->setCheckable(true);
    QIcon icon;
    icon.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/zoom.svg")), QIcon::Normal, QIcon::Off);
    actionZoom->setIcon(icon);
    actionZoom->setText(tr("&Zoom"));
    //controlActions_.push_back(actionZoom);

    //Up
    actionZoomUp_ = new QAction(this);
    actionZoomUp_->setObjectName(QString::fromUtf8("actionZoomStackUp"));
    QIcon iconUp;
    iconUp.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/zoom_out.svg")), QIcon::Normal, QIcon::Off);
    actionZoomUp_->setIcon(iconUp);
    //actionUp->setIcon(QApplication::style()->standardIcon(QStyle::SP_ArrowUp));
    actionZoomUp_->setText(tr("Zoom &out"));
    actionZoomUp_->setShortcut(tr("Ctrl+Up"));

    //Down
    actionZoomDown_ = new QAction(this);
    actionZoomDown_->setObjectName(QString::fromUtf8("actionZoomStackUp"));
    QIcon iconDown;
    iconDown.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/zoom_in.svg")), QIcon::Normal, QIcon::Off);
    actionZoomDown_->setIcon(iconDown);
    //actionDown->setIcon(QApplication::style()->standardIcon(QStyle::SP_ArrowDown));
    actionZoomDown_->setText(tr("Zoom &in"));
    actionZoomDown_->setShortcut(tr("Ctrl+Down"));

    //Zoomstack
    QToolButton* zoomStackPb = new QToolButton;
    QIcon icon11;
    icon11.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/zoom_stack.svg")), QIcon::Normal, QIcon::Off);
    zoomStackPb->setIcon(icon11);
    zoomStackPb->setToolTip(tr("Zoom levels"));
    zoomStackPb->setPopupMode(QToolButton::InstantPopup);

    //zoomStackPb->setText(tr("Zoom history"));
    zoomStackPb->setObjectName("zoomStackPb");

    //QMenu *zoomStackMenu = new QMenu("&ZoomStack");

    zoomStackWidget_ = new MvQZoomStackWidget(plotScene_);
    zoomStackPb->setMenu(zoomStackWidget_);

    //QWidgetAction *wa = new QWidgetAction(zoomStackMenu);
    //wa->setDefaultWidget(zoomStackWidget_);
    //zoomStackMenu->addAction(wa);

    //Zoomstack combo
    //zoomStackWidget_ = new MvQZoomStackWidget(plotScene_);

    //Separator
    //QAction *actionSep=new QAction(this);
    //actionSep->setSeparator(true);

    //Zoom button
    connect(actionZoom, SIGNAL(toggled(bool)),
            plotView_, SLOT(slotSetEnableZoom(bool)));

    connect(plotView_, SIGNAL(zoomIsEnabledProgramatically(bool)),
            actionZoom, SLOT(setChecked(bool)));


    connect(zoomStackWidget_, SIGNAL(actLevelChanged(QString, int)),
            this, SLOT(slotZoomStackLevelChanged(QString, int)));

    connect(actionZoomUp_, SIGNAL(triggered()),
            zoomStackWidget_, SLOT(slotStepUp()));

    connect(actionZoomDown_, SIGNAL(triggered()),
            zoomStackWidget_, SLOT(slotStepDown()));

    MvQMainWindow::MenuType menuType = MvQMainWindow::ZoomMenu;

    menuItems_[menuType].push_back(new MvQMenuItem(actionZoom));
    menuItems_[menuType].push_back(new MvQMenuItem(actionZoomUp_));    //!!!
    menuItems_[menuType].push_back(new MvQMenuItem(actionZoomDown_));  //!!!
    //menuItems_["zoom"].push_back(new MvQMenuItem(actionSep));
    menuItems_[menuType].push_back(new MvQMenuItem(zoomStackPb));
}


void uPlotBase::setupHelpActions()
{
    // About
    QAction* actionAbout = new QAction(this);
    actionAbout->setObjectName(QString::fromUtf8("actionAbout"));
    QIcon icon;
    icon.addPixmap(QPixmap(QString::fromUtf8(":/window/metview_logo")), QIcon::Normal, QIcon::Off);
    actionAbout->setIcon(icon);
    actionAbout->setText(tr("&About uPlot"));

    connect(actionAbout, SIGNAL(triggered()), this, SLOT(slotShowAboutBox()));

    MvQMainWindow::MenuType menuType = MvQMainWindow::HelpMenu;

    menuItems_[menuType].push_back(new MvQMenuItem(actionAbout, MvQMenuItem::MenuTarget));
}

void uPlotBase::setupContextMenuActions()
{
    QAction* action;

    //Up
    action = new QAction(this);
    action->setObjectName(QString::fromUtf8("actionContextZoomStackUp"));
    QIcon iconUp;
    iconUp.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/zoom_out.svg")), QIcon::Normal, QIcon::Off);
    action->setIcon(iconUp);
    action->setText(tr("Zoom &out"));
    action->setShortcut(tr("Ctrl+Up"));
    actionContextZoomUp_ = action;

    //Down
    action = new QAction(this);
    action->setObjectName(QString::fromUtf8("actionContextZoomStackUp"));
    QIcon iconDown;
    iconDown.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/zoom_in.svg")), QIcon::Normal, QIcon::Off);
    action->setIcon(iconDown);
    action->setText(tr("Zoom &in"));
    action->setShortcut(tr("Ctrl+Down"));
    actionContextZoomDown_ = action;

    action = new QAction(this);
    action->setObjectName(QString::fromUtf8("actionContextSelectScene"));
    QIcon icon;
    icon.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/player_play.svg")), QIcon::Normal, QIcon::Off);
    //action->setIcon(icon);
    action->setText(tr("&Select as active scene"));
    actionContextSelectScene_ = action;
}


void uPlotBase::SetupResources()
{
    // Find uPlot resources file and read it
    Cached path = ObjectList::Find("visual_resources", "uPlot", "path");
    MvRequest requPlot;
    requPlot.read(path);

    int i = 0;
    requPlot.rewind();
    while (requPlot) {
        i++;
        requPlot.advance();
    }

    MvRequest tt;
    tt.read("/tmp/dummy-user/data/setup.txt");

    i = 0;
    tt.rewind();
    while (tt) {
        i++;
        tt.advance();
    }
    //COUT << "Number total resources = " << i << endl;
}

void uPlotBase::setPlot(float hor, float ver)
{
    if (oriPlotWidthInCm_ < 0) {
        oriPlotWidthInCm_  = hor;
        oriPlotHeightInCm_ = ver;
    }

    // Set drawing area size
    //float hsize = floorf((75.*1./2.54) * hor);
    //float vsize = floorf((75.*1./2.54) * ver);

    //plotScene_->setSceneRect(0,0,hsize,vsize);
    //plotView_->setMvPlotSize(hsize,vsize);
}

void uPlotBase::processDrop(MvQIconDropItem* drop)
{
    QPoint globalPos(x() + drop->x(), y() + drop->y());

    setDropTarget(globalPos);

    if (!plotView_->rect().contains(plotView_->mapFromGlobal(globalPos)))
        return;

    // IMPORTANT: THIS CODE WILL BE REPLACED BY:
    //	sPageId = activeScene_->layout().id();
    // WE WILL ASK SYLVIE TO IMPLEMENT THIS FUNCTION

    string sPageId;

    if (activeScene_) {
        sPageId = activeScene_->layout().id();
        if (sPageId.empty()) {
            MgQLayoutItem* projItem = activeScene_->firstProjectorItem();
            sPageId                 = projItem->layout().id();
        }
    }

    // Build request to be sent back to source
    int pageId;
    istringstream sst(sPageId);
    sst >> pageId;

    MvRequest req("DROP_REQUEST");
    req("BATCH") = drop->batchNumber();

    req("ACTION") = 3;

    MvRequest subreq("DROP");
    subreq("DROP_ID")           = pageId;
    subreq("DROP_X")            = 12.;
    subreq("DROP_Y")            = 4.2;
    subreq("_REGISTER_TRAILER") = 1;

    req("HEADER") = subreq;

    // Add View request if it exists
    if (owner_) {
        Presentable* pres = owner_->FindBranch(pageId);
        if (pres) {
            MvRequest reqView = pres->GetView().ViewRequest();
            req("_CONTEXT")   = reqView;
        }
        //Safety solution
        else {
            MvRequest reqView = owner_->Request()("PAGES");
            reqView           = reqView("VIEW");
            req("_CONTEXT")   = reqView;
        }
    }

    // Send drop request to the appropriate function
    emit sendDropRequest(&req);
}

void uPlotBase::slotProcessDropInView(const MvQDrop& drop, QPoint pos)
{
    setDropTargetInView(pos);

    // IMPORTANT: THIS CODE WILL BE REPLACED BY:
    //	sPageId = activeScene_->layout().id();
    // WE WILL ASK SYLVIE TO IMPLEMENT THIS FUNCTION

    string sPageId;

    if (activeScene_) {
        sPageId = activeScene_->layout().id();
        if (sPageId.empty()) {
            MgQLayoutItem* projItem = activeScene_->firstProjectorItem();
            sPageId                 = projItem->layout().id();
        }
    }

    // Build request to be sent back to source
    int pageId = 0;
    istringstream sst(sPageId);
    sst >> pageId;

    MvRequest req("DROP_REQUEST");
    //	req("BATCH") = drop->batchNumber();

    req("ACTION") = 3;

    MvRequest subreq("DROP");
    subreq("DROP_ID") = pageId;
    subreq("DROP_X")  = 12.;

    if (drop.iconNum() > 0) {
        subreq.setValue("ICON_NAME", drop.iconPath(0).toStdString().c_str());

        for (int i = 1; i < drop.iconNum(); i++) {
            subreq.addValue("ICON_NAME", drop.iconPath(i).toStdString().c_str());
        }
    }

    subreq("DROP_Y")            = 4.2;
    subreq("_REGISTER_TRAILER") = 1;

    req("HEADER") = subreq;

    // Add View request if it exists
    if (owner_) {
        Presentable* pres = owner_->FindBranch(pageId);
        if (pres) {
            MvRequest reqView = pres->GetView().ViewRequest();
            req("_CONTEXT")   = reqView;
        }
        //Safety solution
        else {
            MvRequest reqView = owner_->Request()("PAGES");
            reqView           = reqView("VIEW");
            req("_CONTEXT")   = reqView;
        }
    }

    //qDebug() << "DROP REQUEST";
    //req.print();

    // Send drop request to the appropriate function
    emit sendDropRequest(&req);
}

void uPlotBase::processContentsRequest(MvRequest& iconReq)
{
    owner_->contentsRequest(iconReq);
}


#if 0
void uPlotBase::dataReceived()
{
	const QMetaObject *tt = metaObject ();
}
#endif


void uPlotBase::slotEnableOpenGL(bool /*opengl*/)
{
    //#ifndef QT_NO_OPENGL
    //     	plotView_->setViewport(opengl ?
    //		new QGLWidget(QGLFormat(QGL::SampleBuffers |  QGL::DoubleBuffer | QGL::AlphaChannel)) :
    //		new QWidget);
    //#endif
}

void uPlotBase::slotEnableAntialias(bool status)
{
    plotScene_->setEnableAntialias(status);
}

//===================================================
//
//  Zoom slots
//
//===================================================

void uPlotBase::slotZoomStackLevelChanged(QString layoutId, int actLevel)
{
    owner_->ZoomRequest(layoutId.toInt(), actLevel);
}

void uPlotBase::updateZoomActionState()
{
    int levelNum = zoomStackWidget_->levelNum();
    int actLevel = zoomStackWidget_->currentLevel();

    if (levelNum <= 1) {
        actionZoomUp_->setEnabled(false);
        actionZoomDown_->setEnabled(false);
    }
    else if (actLevel == 0) {
        actionZoomUp_->setEnabled(false);
        actionZoomDown_->setEnabled(true);
    }
    else if (actLevel == levelNum - 1) {
        actionZoomUp_->setEnabled(true);
        actionZoomDown_->setEnabled(false);
    }
    else {
        actionZoomUp_->setEnabled(true);
        actionZoomDown_->setEnabled(true);
    }
}

void uPlotBase::slotPerformZoom(const string& sid, const string& def)
{
    //Location stores the bottom-left,top-right corners.
    //Its constructor is requeres the following order:
    //top,left,bottom,right

    //Change active scen if needed befor performing the zoom
    if (activeScene_) {
        MgQLayoutItem* projItem = activeScene_->firstProjectorItem();
        if (projItem && projItem->layout().id() != sid) {
            foreach (MgQSceneItem* item, plotScene_->sceneItems()) {
                projItem = item->firstProjectorItem();
                if (projItem && sid == projItem->layout().id()) {
                    activeScene_ = item;
                    break;
                }
            }
        }
    }

    //Location zoomCoord(tr_y,bl_x,bl_y,tr_x);
    int id = QString(sid.c_str()).toInt();
    owner_->ZoomRequest(id, def);
}


void uPlotBase::slotStepCacheStateChanged()
{
    //Layer model will be reset since as new animation step is cached
    //new layers might have added to the scene
    //layerWidget_->model()->layersAreAboutToChange();

    //Notify the scene about the unique layers's status. This will set the
    //status of all the new layers to the correct values
    //plotScene_->updateLayers(layerWidget_->model()->layers());

    //Pass the new list of unique layers to the layer model and
    //finish its resetting
    //layerWidget_->model()->setLayers(plotScene_->uniqueLayers());
}


void uPlotBase::slotLoadExportDialog()
{
    ExportDialog exportDialog(currentStep(), stepNum());

    connect(&exportDialog, SIGNAL(sendExpDialogInfo(MvRequest*)),
            this, SLOT(slotExpDialogInfo(MvRequest*)));

    if (!exportDialog.exec())
        return;
}

void uPlotBase::slotLoadEcChartsDialog()
{
    // Is there anything plotted?
    if (!owner_) {
        PlotMod::Instance().MetviewError("Display Window empty", "Warning");
        return;
    }

    // Ask and wait for user options
    MvQEcChartsDialog dialog(currentStep(), stepNum());
    if (dialog.exec() != QDialog::Accepted)
        return;

    // Get information from the dialog window
    //   string ecCharts_layername = dialog.getLayerName();
    string outputFileName = dialog.getOutputFileName();

    // Build request
    MvRequest plotReq = owner_->ExportToEcCharts();

    // Save request
    plotReq.save(outputFileName.c_str());

    /*
   if ( owner_->ExportPlot(req1) == false )
   {
      COUT << "CREATE A ERROR WINDOW MESSAGE" << endl;
   }*/
}

// the Weather Room-specific slots need to be defined even if
// METVIEW_WEATHER_ROOM is not defined. This is because the Qt MOC file is
// shared between all the uPlot executables. For uPlot, METVIEW_WEATHER_ROOM is
// defined, but not for GeoTool. But they both link with the same MOC file
// which has to have the slots defined in order for the feature to work
// in uPlot.

void uPlotBase::slotLoadWeatherRoomDialog()
{
#ifdef METVIEW_WEATHER_ROOM
    // Is there anything plotted?
    if (!owner_) {
        PlotMod::Instance().MetviewError("Weather Room-> Nothing to be exported", "Warning");
        return;
    }

    // Ask and wait for user options
    MvQWeatherRoomDialog dialog(currentStep(), stepNum());
    if (dialog.exec() != QDialog::Accepted)
        return;

    // Get information from the dialog window
    wroomCell_ = dialog.getCell();
    wroomWall_ = dialog.getWallId();

    // Build plot request and upload it to the weather room
    if (!this->plotWeatherRoom())
        return;

#endif
}


#ifdef METVIEW_WEATHER_ROOM
bool uPlotBase::plotWeatherRoom(bool checkSync)
{
    // Nothing to be plotted (ask to check the synchronisation flag
    // and the video wall is not synchronised with uPlot)
    if (checkSync && syncWeatherRoom() == false)
        return true;

    // Define output device. Create a temporary file.
    MvRequest devReq;
    this->outputDeviceWeatherRoom(devReq);

    // Ask my owner to recreate the plot and save it accordingly
    // Set the syncronous flag, e.g. make sure the file is created
    // before uploading it
    if (owner_->ExportPlot(&devReq, true) == false) {
        PlotMod::Instance().MetviewError("Weather Room-> Failed to upload plot", "Warning");
        return false;
    }

    // Upload file to the weather room
    string fName = (const char*)devReq("OUTPUT_FULLNAME");
    this->uploadWeatherRoom(fName);

    return true;
}
#endif

#ifdef METVIEW_WEATHER_ROOM
void uPlotBase::outputDeviceWeatherRoom(MvRequest& devReq)
{
    // Define output device. Create a temporary file.
    wroomFormat_ = "pdf";
    devReq.setVerb("PDFOUTPUT");
    string fName              = marstmp();
    devReq("OUTPUT_FULLNAME") = fName.c_str();
}
#endif

#ifdef METVIEW_WEATHER_ROOM
void uPlotBase::uploadWeatherRoom(const string& fName)
{
    // Get data unit information used to create the plot
    MvRequest req("DataInfo");
    owner_->GetDataUnitInfo(req);

    // Create json file
    // Write fixed info
    const char* jName = marstmp();
    ofstream jFile;
    jFile.open(jName);
    jFile << "{\n";
    jFile << "   \"page_format\" : \"a4\",\n";
    jFile << "   \"file_format\" : \"" << wroomFormat_ << "\",\n";
    //   jFile << "      \"rotate\"    : 90,\n";
    jFile << "   \"title\"       : \"title\",\n";
    jFile << "   \"file\"        : \"" << fName.c_str() << "\",\n";
    jFile << "   \"pages\"       : {\n";

    // Write data unit info BASE_TIME
    char cbuf[512];
    const char* expver;
    int i, step;
    double ddate, dtime;
    int count = req.countValues("DATE");
    jFile << "      \"base_time\" : [";
    for (i = 0; i < count; i++) {
        req.getValue(ddate, "DATE", i);
        req.getValue(dtime, "TIME", i);  //time format: HHMM
        ddate += dtime / 2400;           //fraction of 24hs
        MvDate date(ddate);
        date.Format("yyyy-mm-ddTHH:MM:SSZ", cbuf);
        jFile << "\"" << cbuf << "\"";
        if (i < (count - 1))
            jFile << ",";
    }
    jFile << "],\n";

    // Write data unit info STEP
    jFile << "      \"step\"      : [";
    for (i = 0; i < count; i++) {
        req.getValue(step, "STEP", i);
        jFile << step;
        if (i < (count - 1))
            jFile << ",";
    }
    jFile << "],\n";

    // Write data unit info EXPVER
    jFile << "      \"expver\"    : [";
    for (i = 0; i < count; i++) {
        req.getValue(expver, "EXPVER", i);
        jFile << "\"" << expver << "\"";
        if (i < (count - 1))
            jFile << ",";
    }
    jFile << "]\n";

    // Close file
    jFile << "     }\n}";
    jFile.close();

    // Upload file by calling a python script
    const char* upload = getenv("MV_WEATHER_ROOM_UPLOAD");
    sprintf(cbuf, "%s --index %s --wall %s --cell %d", upload, jName, wroomWall_.c_str(), wroomCell_);
    system(cbuf);

    // Delete the temporary files: ps and json
    sprintf(cbuf, "rm -f %s", fName.c_str());
    system(cbuf);

    sprintf(cbuf, "rm -f %s", jName);
    system(cbuf);
    //#endif
}
#endif


// the Weather Room-sepcific slots need to be defined even if
// METVIEW_WEATHER_ROOM is not defined. This is because the Qt MOC file is
// shared between all the uPlot executables. For uPlot, METVIEW_WEATHER_ROOM is
// defined, but not for GeoTool. But they both link with the same MOC file
// which has to have the slots defined in order for the feature to work
// in uPlot.

void uPlotBase::slotEnableWroomSync(bool flag)
{
#ifdef METVIEW_WEATHER_ROOM
    wroomSync_ = flag;
#endif
}

void uPlotBase::slotLoadPrintDialog()
{
    // Is there anything plotted?
    if (!owner_) {
        PlotMod::Instance().MetviewError("uPlot-> Nothing to be printed", "Warning");
        return;
    }

    // Create the PrintDialog user interface
#if 0  // Qt printing
	QPrinter printer(QPrinter::HighResolution);
	QPrintDialog dialog( &printer );
	if ( !dialog.exec() )
		return;

	// Get printer attributes
//	printer.setResolution(300);
//	printer.setOutputFormat(QPrinter::PostScriptFormat);Enabled
//qDebug() << printer.resolution();

	// Recreate the plot and sent it to the printer
	QPainter painter(&printer);
	painter.translate(0,painter.viewport().height()); //origin moved to lower left corner
	painter.scale(1.,-1.);				  //plot directions: W->E and S->N
	plotScene_->render(&painter);

#else  //lpr printing
    QPrintDialog printDialog;
    QPrinter* pr = printDialog.printer();

    // Read and apply previous gui settings
    // The default printer name is defined by UNIX and
    // it seems that it can not be changed by QPrinter
    QSettings settings(MVQ_QSETTINGS_DEFAULT_ARGS, "uPlotPrintDialog");
    settings.beginGroup("main");
    pr->setOrientation((QPrinter::Orientation)settings.value("orientation").toInt());
    settings.endGroup();

    // Set print dialog default values
    printDialog.setOption(QAbstractPrintDialog::PrintToFile, false);
    printDialog.setOption(QAbstractPrintDialog::PrintCollateCopies, false);
    printDialog.setPrintRange(QAbstractPrintDialog::PageRange);
    printDialog.setMinMax(1, stepNum());
    printDialog.setFromTo(currentStep() + 1, currentStep() + 1);
    if (!printDialog.exec())
        return;

    // Get printer parameters
    string name     = pr->printerName().toLocal8Bit().constData();
    int orientation = pr->orientation();  //0-portrait, 1-landscape
    int numCopies   = pr->actualNumCopies();

    // Create printer request
    MvRequest printerReq("PRINTER_MANAGER");
    printerReq("DESTINATION")   = MVPRINTER;
    printerReq("PRINTER_NAME")  = name.c_str();
    printerReq("ORIENTATION")   = orientation;
    printerReq("NUMBER_COPIES") = numCopies;

    // Get print range parameters
    if (printDialog.printRange() == QAbstractPrintDialog::PageRange) {
        // Get range of values
        for (int i = printDialog.fromPage(); i <= printDialog.toPage(); i++)
            printerReq.addValue("_OUTPUT_FRAME_LIST", i);
    }

    // Ask my owner to recreate the plot and send it to the output device
    owner_->PrintFile(printerReq);

    // Save current gui settings
    settings.beginGroup("main");
    settings.setValue("orientation", orientation);
    settings.endGroup();
#endif
}

void uPlotBase::slotExpDialogInfo(MvRequest* req1)
{
    // Is there anything plotted?
    if (!owner_) {
        PlotMod::Instance().MetviewError("uPlot-> Nothing to be exported", "Warning");
        return;
    }

// THIS IS A TEMPORARY SOLUTION TO ACCEPT ONLY FORMATS PS AND PDF
// MOVE FROM QPRINTER TO QIMAGE TO ACCEPT OTHER FORMATS
#if 0  //Qt export

	// Loop on drivers
	MvRequest req (*req1);  // change prototype to receive a req& not a *req
	while (req)
	{
		const char* fname;
		req.getValue(fname,"OUTPUT_NAME");
		string verb = req.getVerb();  // Ask my owner to recreate the plot and save it accordingly
   if ( owner_->ExportPlot(req1) == false )
   {
      COUT << "CREATE A ERROR WINDOW MESSAGE" << endl;
   }
		size_t found = verb.find("OUTPUT");
		string format = verb.substr(0,found);
		std::transform(format.begin(), format.end(),format.begin(), ::tolower);

		if ( format.compare("ps") == 0 || format.compare("pdf") == 0 )
		{
			QPrinter printer (QPrinter::HighResolution);
			printer.setPaperSize(QPrinter::A4);

			if ( format.compare("ps") == 0 )
				printer.setOutputFormat(QPrinter::PostScriptFormat);
			else
				printer.setOutputFormat(QPrinter::PdfFormat);

			string str(fname);
			str += ".";
			str += format;

			printer.setOutputFileName(str.c_str());
			printer.setOrientation(QPrinter::Landscape);

			// Recreate the plot and save it accordingly
			QPainter painter(&printer);
			painter.translate(0,painter.viewport().height()); //origin moved to lower left corner
			painter.scale(1.,-1.); //plot directions: W->E and S->N
			//plotScene_->render(&painter);
			plotScene_->renderForPrinter(&painter);
		}
		else
		{
/*
			QImage image;
			QPainter painter(&image);
			painter.translate(0,painter.viewport().height()); //origin moved to lower left corner
			painter.scale(1.,-1.); //plot directions: W->E and S->N
			plotScene_->render(&painter);*/
		}

		req.advance();
	}

#else  //Magics++ export
    // Ask my owner to recreate the plot and save it accordingly
    if (owner_->ExportPlot(req1) == false) {
        PlotMod::Instance().MetviewError("uPlot-> Failed to export plot", "Warning");
        return;
    }
#endif
}


void uPlotBase::slotGenerateMacro()
{
    if (!owner_) {
        PlotMod::Instance().MetviewError("uPlot-> Display Window empty. Nothing to be generated", "Warning");
        return;
    }

    // Ask my owner to recreate the plot and save it in a file
    owner_->GenerateMacro();
}

void uPlotBase::slotShowAboutBox()
{
    string magicsVersionString = getMagicsVersionString();
    QString magicsVersion(QString::fromUtf8(magicsVersionString.c_str()));

    QMap<MvQAbout::Version, QString> text;
    text[MvQAbout::MagicsVersion] = magicsVersion;

#if defined METVIEW_ODB
    const char* odbapi_version = odb_api_version();
    QString odbapiVersion(odbapi_version);
    text[MvQAbout::OdbApiVersion] = odbapiVersion;
#endif

    MvQAbout about("uPlot", "",
                   MvQAbout::GribApiVersion | MvQAbout::MetviewVersion | MvQAbout::MagicsVersion | MvQAbout::OdbApiVersion,
                   text);

    about.exec();
}

//===============================
//
// Resize
//
//===============================

void uPlotBase::slotResizeEvent(const QSize&)
{
    int index = sizeCombo_->currentIndex();
    int id    = sizeCombo_->itemData(index, Qt::UserRole).toInt();
    if (id == FitToWindow || id == FitToWidth || id == FitToHeight) {
        changeSize(id);
    }
}

void uPlotBase::slotSizeChanged(int index)
{
    changeSize(sizeCombo_->itemData(index, Qt::UserRole).toInt());
}

void uPlotBase::slotSizeDown()
{
    int scalingId;
    int id = sizeCombo_->itemData(sizeCombo_->currentIndex(), Qt::UserRole).toInt();

    if (id == FitToWindow || id == FitToWidth || id == FitToHeight) {
        float scaling = currentSizeRatio();
        scalingId     = static_cast<int>(scaling * 100.);
    }
    else {
        scalingId = id;
    }

    scalingId -= sizeValueStep_;

    if (scalingId >= sizeMinValue_ && scalingId <= sizeMaxValue_) {
        setCustomSize(scalingId);
    }
}

void uPlotBase::slotSizeUp()
{
    int scalingId;
    int id = sizeCombo_->itemData(sizeCombo_->currentIndex(), Qt::UserRole).toInt();

    if (id == FitToWindow || id == FitToWidth || id == FitToHeight) {
        float scaling = currentSizeRatio();
        scalingId     = static_cast<int>(scaling * 100.);
    }
    else {
        scalingId = id;
    }

    scalingId += sizeValueStep_;

    if (scalingId >= sizeMinValue_ && scalingId <= sizeMaxValue_) {
        setCustomSize(scalingId);
    }
}

void uPlotBase::setCustomSize(int sizeId)
{
    //If custom size item is not available in the combobox we add one to it
    if (customSizeItemIndex_ >= sizeCombo_->count()) {
        sizeCombo_->addItem(QString::number(sizeId) + "%", sizeId);
    }
    else if (customSizeItemIndex_ == sizeCombo_->count() - 1) {
        sizeCombo_->setItemData(customSizeItemIndex_, sizeId);
        sizeCombo_->setItemText(customSizeItemIndex_, QString::number(sizeId) + "%");
    }

    if (sizeCombo_->currentIndex() != customSizeItemIndex_) {
        sizeCombo_->setCurrentIndex(customSizeItemIndex_);
    }
    else {
        changeSize(sizeId);
    }
}

float uPlotBase::currentSizeRatio()
{
    QRectF currentRect = plotScene_->sceneRect();
    if (currentRect.isEmpty()) {
        return 1.;
    }

    QRectF oriRect = plotScene_->oriSceneRect();
    if (oriRect.isEmpty()) {
        return 1.;
    }

    return currentRect.width() / oriRect.width();
}

void uPlotBase::changeSize(int sizeId, bool renderIt)
{
    float scaling;

    if (sizeId == FitToWindow) {
        QRectF sceneRect = plotScene_->sceneRect();
        if (sceneRect.isEmpty()) {
            return;
        }

        QSize size   = plotView_->maximumViewportSize();
        float wRatio = size.width() / sceneRect.width();
        float hRatio = size.height() / sceneRect.height();
        scaling      = (wRatio < hRatio) ? wRatio : hRatio;

        if (scaling < 0.95 || scaling > 1.05) {
            plotScene_->setPlotScale(scaling, MgQPlotScene::RelativeToCurrentSize);
        }
    }
    else if (sizeId == FitToWidth) {
        QRectF sceneRect = plotScene_->sceneRect();
        if (sceneRect.isEmpty()) {
            return;
        }

        QSize size   = plotView_->maximumViewportSize();
        float wRatio = size.width() / sceneRect.width();
        scaling      = wRatio;

        if (scaling < 0.95 || scaling > 1.05) {
            plotScene_->setPlotScale(scaling, MgQPlotScene::RelativeToCurrentSize);
        }
    }
    else if (sizeId == FitToHeight) {
        QRectF sceneRect = plotScene_->sceneRect();
        if (sceneRect.isEmpty()) {
            return;
        }

        QSize size   = plotView_->maximumViewportSize();
        float hRatio = size.height() / sceneRect.height();
        scaling      = hRatio;

        if (scaling < 0.95 || scaling > 1.05) {
            plotScene_->setPlotScale(scaling, MgQPlotScene::RelativeToCurrentSize);
        }
    }
    else if (sizeId >= 10 && sizeId <= 200) {
        scaling = static_cast<float>(sizeId) * 0.01;

        //float w=oriPlotWidthInCm_*scaling;
        //float h=oriPlotHeightInCm_*scaling;

        plotScene_->setPlotScale(scaling, MgQPlotScene::RelativeToOriSize);

        if (renderIt) {
            plotScene_->sceneItemChanged();
        }
    }

    if (renderIt) {
        plotScene_->sceneItemChanged();
    }

    updateResizeActionState();

    emit plotScaleChanged();

    //GraphicsEngine& ge = owner_->GetGraphicsEngine();
    //owner_->ResizeRequest(w,h);
}

void uPlotBase::updateResizeActionState()
{
    int index = sizeCombo_->currentIndex();
    int id    = sizeCombo_->itemData(index, Qt::UserRole).toInt();
    int sizeId;

    if (index < 0)
        return;

    if (id == FitToWindow || id == FitToWidth || id == FitToHeight) {
        sizeId = static_cast<int>(plotScene_->plotScale() * 100);
    }
    else {
        sizeId = id;
    }

    if (sizeId + sizeValueStep_ <= sizeMaxValue_) {
        actionSizeUp_->setEnabled(true);
    }
    else {
        actionSizeUp_->setEnabled(false);
    }

    if (sizeId - sizeValueStep_ >= sizeMinValue_) {
        actionSizeDown_->setEnabled(true);
    }
    else {
        actionSizeDown_->setEnabled(false);
    }
}


void uPlotBase::slotBuildContextMenu(const QPoint& globalPos, const QPointF& scenePos)
{
    setupContextMenuActions();

    QList<QAction*> actions;

    //If there is only one scene
    if (plotScene_->sceneItems().count() <= 1) {
        actions << actionZoomUp_ << actionZoomDown_;
        QMenu::exec(actions, globalPos);
        return;
    }

    //More than one scene
    MgQSceneItem* item = plotScene_->findSceneItem(scenePos);
    if (!item)
        return;


    //Context menu triggered from the active scene
    if (item == activeScene_) {
        actions << actionZoomUp_ << actionZoomDown_;
        QMenu::exec(actions, globalPos);
    }

    //Context menu triggered from a non-active scene
    else {
        actions << actionContextSelectScene_ << actionContextZoomUp_ << actionContextZoomDown_;

        //Set the status of the context zoom actions
        MvQZoomStackData* zoomData = zoomStackWidget_->pageData(item);
        if (zoomData) {
            int levelNum = zoomData->levelNum();
            int actLevel = zoomData->selectedLevel();

            if (levelNum <= 1) {
                actionContextZoomUp_->setEnabled(false);
                actionContextZoomDown_->setEnabled(false);
            }
            else if (actLevel == 0) {
                actionContextZoomUp_->setEnabled(false);
                actionContextZoomDown_->setEnabled(true);
            }
            else if (actLevel == levelNum - 1) {
                actionContextZoomUp_->setEnabled(true);
                actionContextZoomDown_->setEnabled(false);
            }
            else {
                actionContextZoomUp_->setEnabled(true);
                actionContextZoomDown_->setEnabled(true);
            }
        }
        else {
            actionContextZoomUp_->setEnabled(false);
            actionContextZoomDown_->setEnabled(false);
        }

        QAction* action = QMenu::exec(actions, globalPos);

        if (action == actionContextSelectScene_) {
            slotSetActiveScene(item);
        }
        else if (action == actionContextZoomUp_) {
            slotSetActiveScene(item);
            //Now this scene is active. We can use the original zoomUp action!!
            actionZoomUp_->trigger();
        }
        else if (action == actionContextZoomDown_) {
            slotSetActiveScene(item);
            //Now this scene is active. We can use the original zoomDown action!!
            actionZoomDown_->trigger();
        }
    }
}


int uPlotBase::screenResolutionInDpi()
{
    int defaultRes = -1;

    char* mvres = getenv("METVIEW_SCREEN_RESOLUTION");
    if (mvres) {
        int res = QString(mvres).toInt();
        if (res > 50 && res < 400) {
            return res;
        }
    }

    return defaultRes;
}

#if 0
// ----------------------------------------------------------------------------
// uPlotBase::messageToLogWindow
// sends the given message to the Metview message log window
// ----------------------------------------------------------------------------

void uPlotBase::messageToLogWindow (const string& msg, int severity)
{
	MvRequest reqst("USER_MESSAGE");
	reqst("INFO") = msg.c_str(); 
	send_message(MvApplication::instance().getService(),(request*)reqst);


        // also send to the Mars/Metview module log
	char msg_c[1024];
	strncpy(msg_c, msg.c_str(), 1023);
	marslog(severity, msg_c);
}
#endif

void uPlotBase::setPlotWidgetSize(float hor, float ver)
{
    setPlot(hor, ver);
}
