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

 Copyright 2012 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 <QDebug>
#include <QLabel>
#include <QStackedLayout>
#include <QToolButton>
#include <QVBoxLayout>

#include "MvQLayerDataWidget.h"

#include "Layer.h"
#include "Transformation.h"

#ifdef METVIEW_ODB_NEW
#include "MvQOdbDataWidget.h"
#endif

#include "MvQPlaceMark.h"
#include "MvQPlotView.h"

#include "MgQPlotScene.h"
#include "MgQRootItem.h"
#include "MgQSceneItem.h"

MvQLayerDataWidget::MvQLayerDataWidget(MgQPlotScene *plotScene,MvQPlotView *plotView,QWidget *parent) : 
          QWidget(parent),
          plotScene_(plotScene),
          plotView_(plotView),
          sceneItem_(0), 
          layer_(0),
          dataProbe_(0)
{
  	layout_=new QVBoxLayout;
	layout_->setContentsMargins(0,0,0,0);
	//layout_->setSpacing(1);
	setLayout(layout_);
	
	//Panels
		
	panelLayout_=new QStackedLayout;
	layout_->addLayout(panelLayout_);
	
	QWidget *emptyWidget=new QWidget(this);
	QVBoxLayout *emptyVb=new QVBoxLayout(emptyWidget);
	QLabel *label=new QLabel(tr("No data is available for this layer!"),this);
	emptyVb->addWidget(label);
	emptyVb->addStretch(1);
	panelLayout_->addWidget(emptyWidget);
	
	QPair<PanelType,QWidget*> item(EmptyPanel,label);		
	panels_ << item;
		
	//Data probe
	
	QHBoxLayout *probeHb=new QHBoxLayout();
	layout_->addLayout(probeHb);
	
	probeTb_=new QToolButton(this);
	probeTb_->setToolTip(tr("Enable data probe"));
	probeTb_->setIcon(QPixmap(QString::fromUtf8(":/uPlot/data_probe.svg")));
	probeTb_->setText("Probe");
	probeTb_->setCheckable(true);
	probeTb_->setChecked(false);	
	
	QToolButton  *resetProbeTb = new QToolButton(this);
	resetProbeTb->setToolTip(tr("Reset probe"));
	resetProbeTb->setIcon(QPixmap(QString::fromUtf8(":/uPlot/reset.svg")));
	
	probeHb->addWidget(probeTb_);
	probeHb->addWidget(resetProbeTb);
	probeHb->addSpacing(24);

	probeLabel_=new QLabel("",this);
	probeLabel_->setObjectName(QString::fromUtf8("fileInfoLabel"));	
	probeLabel_->setMargin(0);
	probeLabel_->setAlignment(Qt::AlignLeft| Qt::AlignVCenter);
        probeLabel_->setAutoFillBackground(true);
        probeLabel_->setTextInteractionFlags(Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse);
	probeLabel_->setFrameShape(QFrame::Box);
        probeLabel_->setFrameShape(QFrame::StyledPanel);
	//probeLabel_->setVisible(false);
	probeHb->addWidget(probeLabel_,1);
	//probeHb->addStretch(1);
	
	connect(probeTb_,SIGNAL(toggled(bool)),
		this,SLOT(slotProbe(bool)));
	
	connect(resetProbeTb,SIGNAL(clicked(bool)),
		this,SLOT(slotResetProbe(bool)));	
		
	updateProbeLabel();
	
}

MvQLayerDataWidget::~MvQLayerDataWidget()
{
}	

void MvQLayerDataWidget::updateData()
{
	if(!layer_ || !sceneItem_)
	{
	  	panelLayout_->setCurrentIndex(0);
		return;
	}
	
	//---------------------------------------------------------
	// Check if the panel assigned to the current layer exists
	//---------------------------------------------------------
	
	QMap<MgQLayerItem*,QWidget*>::iterator itP=activePanels_.find(layer_);
	if(itP != activePanels_.end())
	{
		if(itP.value() == panelLayout_->currentWidget())
			return;	
		else
		{	
			panelLayout_->setCurrentWidget(itP.value());
			return;
		}	
	}
	
	//---------------------------------------------------------
	// Create the panel
	//---------------------------------------------------------
	
	//Get metadata
	MetaDataCollector md;
	md["_datatype"]="";
	md["path"]="";
	md["hasMatrix"]="";
	layerMetaData(md);
		
	//Get datatype and path
	map<string,string>::iterator it=md.find("_datatype");
	if(it==md.end())
	{
		panelLayout_->setCurrentIndex(0);
		return;
	}	
	string dataType=it->second;

	QString dataPath;
	it=md.find("path");
	if(it != md.end())
		dataPath=QString::fromStdString(it->second);  
		
	//Get data indexes
	DataIndexCollector info;
	sceneItem_->layerDataIndexForCurrentStep(layer_,info);
	if(info.dataIndex().size() <=0)
	{
	  	panelLayout_->setCurrentIndex(0);
		return;
	}
	
	//ODB
	if(dataType == "ODB_geopoints")
	{  
		loadOdb(dataPath,info);
	}
	else if(dataType == "ODB_xy")
	{  
		it=md.find("hasMatrix");
		if(it == md.end() || it->second != "true")
		{
			loadOdb(dataPath,info);
		}	
	}	
	else
	{
	  	panelLayout_->setCurrentIndex(0);
	}
	
}

void MvQLayerDataWidget::slotFrameChanged()
{
	updateData();
}

void MvQLayerDataWidget::layerMetaData(MetaDataCollector &md) 
{
	if(!layer_ || !sceneItem_)
		return;

	sceneItem_->layerMetaDataForCurrentStep(layer_,md);	
}

void MvQLayerDataWidget::loadOdb(QString path,const DataIndexCollector& info )
{
#ifdef METVIEW_ODB_NEW	

	if(!layer_)
		return;
	
	QWidget *panel=findIdlePanel(OdbPanel);
	MvQOdbDataWidget *w=0;
	if(!panel)
	{	
		panel=new MvQOdbDataWidget(this);
		w=static_cast<MvQOdbDataWidget*>(panel);
		w->setMaxChunkSizeInMb(0); //we do not allow data chunks
		
		panelLayout_->addWidget(panel);
		
		QPair<PanelType,QWidget*> item(OdbPanel,panel);		
		panels_ << item;
		activePanels_[layer_]=panel;
		
		connect(w,SIGNAL(dataRowSelected(int)),
			this,SLOT(slotSetIndex(int)));					
	}
	else
	{
	  	w=static_cast<MvQOdbDataWidget*>(panel);
		if(activePanels_.find(layer_) == activePanels_.end())
	 	activePanels_[layer_]=panel; 
	}
	
	if(w)
	{
		w->init(path,info.dataIndex());
		if(visibleOdbColumns_.count() > 0)
		{
		  	w->setVisibleColumns(visibleOdbColumns_);
		}	
	}	
	
	panelLayout_->setCurrentWidget(panel);
#endif	
}


void MvQLayerDataWidget::slotProbe(bool b)
{
	if(b)
	{   
  		if(dataProbe_)
		{
	  		dataProbe_->setActivated(true);
		}
		else
		{  		  
	  		createDataProbe(); 
		}
		
		
	}
	else
	{
	  	if(dataProbe_)
		{
		  	dataProbe_->setActivated(false);
		}
	}
	
	updateProbeLabel();
}

void MvQLayerDataWidget::slotResetProbe(bool /*b*/)
{
	if(dataProbe_ && dataProbe_->activated() && layoutItem_)
	{ 
		QRectF rect=layoutItem_->mapRectToScene(layoutItem_->boundingRect());	
		QPointF coord;
		layoutItem_->mapFromSceneToGeoCoords(rect.center(),coord);
				
		dataProbe_->setCoordinates(coord);
		slotPointSelected(coord);
	}	
}

void MvQLayerDataWidget::createDataProbe()
{
	if(dataProbe_ || !sceneItem_)
		return;
	
	if(layoutItem_)
	{	
		QRectF rect=layoutItem_->mapRectToScene(layoutItem_->boundingRect());	
		QPointF coord;
		layoutItem_->mapFromSceneToGeoCoords(rect.center(),coord);
				
		dataProbe_=new MvQPlaceMark(plotScene_,plotView_,0);
		//dataProbe_->setFlag(QGraphicsItem::ItemIgnoresTransformations);
		dataProbe_->setZValue(1.8);
		dataProbe_->setActivated(true);
		dataProbe_->setCoordinates(coord);
		dataProbe_->reset(layoutItem_);		

		connect(dataProbe_,SIGNAL(pointSelected(QPointF)),
			this,SLOT(slotPointSelected(QPointF)));
			
		connect(dataProbe_,SIGNAL(beingMoved(QPointF)),
			this,SLOT(slotUpdateProbeLabel(QPointF)));	

		plotView_->setDataProbe(dataProbe_);
		//dataProbe_->setParentItem(plotScene_->annotationRootItem());
		plotScene_->addItem(dataProbe_);
	}
}

void MvQLayerDataWidget::updateProbe()
{
	/*if(dataProbe_ && dataProbe_->activated())
	{	
		dataProbe_->setCoordinates(dataProbe_->coordinates());
		updateProbeLabel();
	}*/
}			
			
void MvQLayerDataWidget::updateProbeLabel()
{
	if(dataProbe_ && dataProbe_->activated())
		slotUpdateProbeLabel(dataProbe_->coordinates());
	else
	  	slotUpdateProbeLabel(QPointF());
}  

void MvQLayerDataWidget::slotUpdateProbeLabel(QPointF cr)
{
	QString s;
	
	if(!layer_ || !sceneItem_)
	{
	 	s=tr("<i>No plot is avilable</i>");
	}	
	else if(dataProbe_ && dataProbe_->activated())
	{
	  	if(dataProbe_->isOutOfPlot())
		{
			s=tr("<i>Probe is out of plot</i>");	
		}
		else
		{  
			s=tr("Probe position: ");
		  	s+="<b>" + coordXName_ + ": </b>";
	  		s+=QString::number(cr.x());
	  		s+="  <b>" + coordYName_ + ": </b>";
	  		s+=QString::number(cr.y());
		}	
	}
	else
	{
	  	s=tr("<i>Probe is disabled</i>");
	}
	
	probeLabel_->setText(s);
}	
  
void MvQLayerDataWidget::slotPointSelected(QPointF coord)	
{	
	if(!layer_ || !sceneItem_)
	{
	 	return;
	}
	
	updateProbeLabel();
	
	if(dataProbe_ && 
	   (!dataProbe_->activated() || dataProbe_->isOutOfPlot()))
	{
		return;
	}	
	  
	QMap<MgQLayerItem*,QWidget*>::iterator it=activePanels_.find(layer_);
	if(it == activePanels_.end())
		return;
	
	QWidget *panel=it.value();
	PanelType type=panelType(panel);
	
	if(type == EmptyPanel)
	  	return;	
  
  	//Get the index for the position	
	double searchRadiusX=2.;
	double searchRadiusY=2.;
			
	float plotScale=plotScene_->plotScale();						
	double cx=layoutItem_->coordRatioX();
	double cy=layoutItem_->coordRatioY();			
		
	if(cx != 0.)
	{
		searchRadiusX=20./fabs(cx*plotScale);
	}
	if(cy != 0.)
	{
		searchRadiusY=20./fabs(cy*plotScale);
	}
		

	ValuesCollector vc;		
	vc.setSearchRadius(searchRadiusX,searchRadiusY);
	vc.push_back(ValuesCollectorPoint(coord.x(),coord.y()));
		
	sceneItem_->collectLayerDataForCurrentStep(layer_,vc);	
	
	//Pass the inex to the panel widget 
	if(vc.size()>0 && vc.at(0).size() > 0)
	{
		int index=vc.at(0).at(0)->index();
		setIndexForPanel(index,type,panel);
	}		
}			

void MvQLayerDataWidget::slotSetIndex(int index)
{	
	if(!dataProbe_ || !dataProbe_->activated() ||  !layer_ || !sceneItem_)
	{
	 	return;
	}
		
	ValuesCollector vc;		
	vc.push_back(ValuesCollectorPoint(index));
		
	sceneItem_->collectLayerDataForCurrentStep(layer_,vc);	
	
	//Pass the inex to the panel widget 
	if(vc.size()>0 && vc.at(0).size() > 0)
	{
		double x=vc.at(0).at(0)->x();
		double y=vc.at(0).at(0)->y();
				
		QPointF pos(x,y);		
		dataProbe_->setCoordinates(pos);
		updateProbeLabel();
	}
}

void MvQLayerDataWidget::setIndexForPanel(int index,PanelType type,QWidget *panel)
{
	if(index == -1)
		  return;

	if(type == OdbPanel)
	{
#ifdef METVIEW_ODB_NEW		
		MvQOdbDataWidget *data=static_cast<MvQOdbDataWidget*>(panel);  	
		if(data)
		{
			  data->highlightRow(index);
		}
#endif		
	}
}

//===============================================
//
// Reset
//
//===============================================

void MvQLayerDataWidget::setLayer(MgQLayerItem* layer)
{ 
	layer_=layer;
	
	if(!layer_)
	{
		updateData();		
		return;
	}	
			
	updateData();	    
} 

MvQLayerDataWidget::PanelType MvQLayerDataWidget::panelType(QWidget* w)
{
 	QPair<PanelType,QWidget*> p;
  	foreach(p,panels_)
	{
		if(p.second == w)
		{	  
	  		return p.first;
		}
	}
	return EmptyPanel;
}	

QWidget* MvQLayerDataWidget::findIdlePanel(PanelType type)
{  
	QPair<PanelType,QWidget*> p;
  	foreach(p,panels_)
	{
		if(p.first == type)
		{
			QMap<MgQLayerItem*,QWidget*>::iterator it=activePanels_.find(layer_);  	
			if(it == activePanels_.end())
			{
			  	return p.second;
			}
		}
	}	
	
	return 0;
}

QWidget* MvQLayerDataWidget::findActivePanel(PanelType type)
{  
	QPair<PanelType,QWidget*> p;
  	foreach(p,panels_)
	{
		if(p.first == type)
		{
			if(activePanels_.values().indexOf(p.second) != -1)
			{  
				return p.second;
			}
		}
	}	
		qDebug() << "active" << activePanels_;
	
	return 0;
}

void MvQLayerDataWidget::clear()
{
	activePanels_.clear(); 
}

void MvQLayerDataWidget::reset(MgQSceneItem* sceneItem, MgQLayerItem* layer)
{
	sceneItem_=sceneItem;
	layer_=layer;
	
	//Save some data
	storePanelProperties();
		
	activePanels_.clear();
   	setLayer(layer_);
	
	layoutItem_=0;
	if(sceneItem_)
	{
		layoutItem_=sceneItem_->firstProjectorItem();
		
		if(layoutItem_)
		{  
			const Transformation& transformation = layoutItem_->layout().transformation();
			switch(transformation.coordinateType())
			{
			case Transformation::GeoType:
				coordXName_=tr("Lon");
				coordYName_=tr("Lat");
				break;
			case Transformation::XyType:
			default:
			  	coordXName_=tr("X");
				coordYName_=tr("Y");
				
				break;
			}													
							
			if(dataProbe_)
			{	
				dataProbe_->reset(layoutItem_);
				updateProbeLabel();
			}
		}
	}	
}

void MvQLayerDataWidget::storePanelProperties()
{
	QWidget *panel=findActivePanel(OdbPanel);
	if(panel)
	{
#ifdef METVIEW_ODB_NEW
		MvQOdbDataWidget *data=static_cast<MvQOdbDataWidget*>(panel);  	
		if(data)
		{
			visibleOdbColumns_=data->visibleColumns();
		}
#endif		
	}
}	
	
void MvQLayerDataWidget::writeSettings(QSettings& settings)
{
  	settings.beginGroup("MvQLayerDataWidget");  
	
	//Save some data
	storePanelProperties();
	
	if(visibleOdbColumns_.count() > 0)
	{  	
		settings.setValue("visibleOdbColumns",visibleOdbColumns_);
	}
	
	settings.endGroup();	
}

void MvQLayerDataWidget::readSettings(QSettings& settings)
{
  	settings.beginGroup("MvQLayerDataWidget");
	visibleOdbColumns_=settings.value("visibleOdbColumns").toStringList();
  	settings.endGroup(); 
}  
