/***************************** 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 <QLabel>
#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"

#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 "Root.h"
#include "PlotModView.h"
#include "ShareTargets.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* )));

   statusMessageLabel_ = new QLabel("");
   statusMessageLabel_->setFrameShape(QFrame::NoFrame);

   // 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);
requPlot.print();
	int i = 0;
	requPlot.rewind();
	while ( requPlot )
	{
		i++;
		requPlot.advance();
	}
	cout << "Number uPlot resources = " << i << endl;

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()
{
	cout << " dataReceived " << endl;
	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_ )
   {
      cout << "Plot Window empty" << endl;
      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_ )
   {
      cout << "Nothing to be exported" << endl;
      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() )
   {
      cout << "CREATE A ERROR WINDOW MESSAGE" << endl;
   }
#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 )
   {
      cout << "CREATE A ERROR WINDOW MESSAGE" << endl;
      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_ )
	{
		cout << "Nothing to be printed" << endl;
		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("ECMWF","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_ ) {
		cout << "Nothing to be exported" << endl;
		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 )
	{
		cout << "CREATE A ERROR WINDOW MESSAGE" << endl;
	}
#endif
}


void uPlotBase::slotGenerateMacro ()
{
	if ( !owner_ ) {
		cout << "Display image empty. Nothing to be generated" << endl;
		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;
}

// ----------------------------------------------------------------------------
// 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);
}

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