/***************************** 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 <QApplication>
#include <QDebug>
#include <QIcon>
#include <QPainter>
#include <QStyle>

#include "MgQLayoutItem.h"
#include "MgQPlotScene.h"
#include "MgQSceneItem.h"

#include "MvQZoomStackWidget.h"

#include "MagPlusService.h"


int MvQZoomStackMenuStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
{
        if (metric == PM_SmallIconSize)
            return 64;
 
       return QProxyStyle::pixelMetric(metric, option,widget);
}
    
#ifndef METVIEW_QT5
int MvQZoomStackMenuPlastiqueStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
{
        if (metric == PM_SmallIconSize)
            return 64;
 
       return QPlastiqueStyle::pixelMetric(metric, option,widget);
}
#endif

//=========================
//   MvQZoomStackLevel
//=========================

MvQZoomStackLevel::MvQZoomStackLevel()
{
}

MvQZoomStackLevel::~MvQZoomStackLevel()
{
}

void MvQZoomStackLevel::setImage(QImage &img)
{
	float w=img.width();
	float h=img.height();

	//We copy the image into a pixmap with the maximum sie of 60x48
	QPixmap pix;
	if(h*60./w <=48.)
	{
		pix=QPixmap::fromImage(img).scaledToWidth(60,Qt::SmoothTransformation);
	}
	else
	{
		pix=QPixmap::fromImage(img).scaledToHeight(48,Qt::SmoothTransformation);
	}	

	//Define the pixmap rectangle
	int pw=pix.width();
	int ph=pix.height();
	int pdy=(64-ph)/2;
	int pdx=(64-pw)/2;			
	QRect pixRect(pdx,pdy,pw,-pdy);
	
	//We create a 60x60 pixmap with white background
	pixmap_=QPixmap(64,64);
	pixmap_.fill(Qt::white);

	//Paint the image pixmap into the middle
	QPainter painter(&pixmap_);
	painter.drawPixmap(pixRect,pix);

	//Render a border around it
	painter.setPen(QColor(230,230,230));
	painter.drawRect(0,0,64,64);


}

//=========================
//   MvQZoomStackData
//=========================


MvQZoomStackData::MvQZoomStackData(QString grLayoutId) : 
		  grLayoutId_(grLayoutId)
{
	//Initially we do not have levels
	levelNum_=0;
	actLevel_=-1;
	selectedLevel_=-1;

	//levelPreviewWidth_=180;
	levelPreviewWidth_=100;
}


MvQZoomStackData::~MvQZoomStackData()
{
	clear();
}

void MvQZoomStackData::clear()
{
	foreach(MvQZoomStackLevel *level,levels_)
	{
		delete level;
	}
	levels_.clear();

	levelNum_=0;
	actLevel_=-1;
	selectedLevel_=-1;
}


int MvQZoomStackData::update(int levelNum,int actLevel,MgQLayoutItem *item)
{
	//Get the new number of levels
	int levelNumOri=levelNum_;
	int actLevelOri=actLevel_;
	
	//int selectedLevel=-1;

	levelNum_=levelNum;
	actLevel_=actLevel;
		
	if(levelNum_ > 30)
	{
		levelNum_=0;
		actLevel_=0;
	}

	// By default levelNum = 0 and actLevel = -1
	// and there are no zoom levels.

	if(levelNum_<=0)
	{
		clear();

		//The gui is not enabled yet
		//enabled_=false;

		//Clear the preview textures
		//clear();

		//Save the preview map into a texture
		if(levelNum_==0 && actLevel_==-1)
		{
			if(levels_.count() == 0) // && currentLayout_ != 0)
			{
				MvQZoomStackLevel *level= new MvQZoomStackLevel;
				generatePreview(level,item);
				//level->tb()->setChecked(true);
				levels_.push_back(level);
				selectedLevel_=0;
			}
			else 
			{
				generatePreview(levels_[0],item);
				selectedLevel_=0;
				//levels_[0]->tb()->setChecked(true);
			}
		}	
		return selectedLevel_;
	
	}
	else
	{
		//enabled_=true;
	}

	//If the levelNum or the current level has changed.
	if(levelNumOri != levelNum_  || actLevelOri != actLevel_)
	{
		//focusedLevel_=-1;

		//If there are less levels
		if(levelNumOri > levelNum_)
		{
			for(int i=levelNumOri-1; i>= levelNum_; i--)
			{
				MvQZoomStackLevel *level=levels_.back();
				//tbGroup_->removeButton(level->tb());
				//layout_->removeWidget(level->tb());
				delete level;
				levels_.pop_back();
			}

			generatePreview(levels_.back(),item);
			selectedLevel_=levels_.count()-1;
			//levels_.back()->tb()->setChecked(true);
		}

		//If there are more levels
		else if(levelNumOri < levelNum_)
		{
			MvQZoomStackLevel *level= new MvQZoomStackLevel;
			generatePreview(level,item);
			//layout_->addWidget(level->tb());
			//tbGroup_->addButton(level->tb(),levels_.count());
			//level->tb()->setChecked(true);
			levels_.push_back(level);
			selectedLevel_=levels_.count()-1;
		}

		//If the level num is the same. If the actLevel is the last one we 
		//regenerate the preview
		else 
		{
			selectedLevel_=actLevel_;
			if(actLevel_ == levelNum_-1)
			{
				generatePreview(levels_[actLevel_],item);
				//levels_[actLevel_]->tb()->setChecked(true);
			}
		}
	}
	
	return selectedLevel_;

}

void MvQZoomStackData::generatePreview(MvQZoomStackLevel *level,MgQLayoutItem* qln)
{
	if(qln == 0) return;

	//Get the preview layout's scene rectangle. We increase the width and
	//height a bit so that the rendered image could contain the whole frame
	QRectF sourceRect=qln->sceneBoundingRect();
	sourceRect.adjust(0.,0.,5.,5.);

	//Define the size of the device where the preview plot will be rendered
	float tw=levelPreviewWidth_;

	float w=sourceRect.width();
	float h=sourceRect.height();
	float r=tw/w;
	float th=h*r;

	if(th > levelPreviewWidth_)
	{
		th=levelPreviewWidth_;
		r=th/h;
		tw=w*r;
	}

	//Create the device. We double the needed size for later smooth recaling!
	QImage device=QImage(tw*2,th*2,QImage::Format_RGB888);

	//Set the target rect
	QRectF targetRect(0,0,device.width(),device.height());

	//Create the painter
	QPainter *painter=new QPainter(&device);	

	//Fill the target device with with colour
	painter->fillRect(0,0,device.width(),device.height(),
			 QBrush(Qt::white));

	//Render the item into the device
	qln->scene()->render(painter,targetRect,sourceRect);

	//Rescale the device to the needed side with smooth transformation. Then mirror it horizontally.
	QImage img=device.scaledToWidth(tw,Qt::SmoothTransformation).mirrored(false,true);

	img.save("/var/tmp/dummy-user/zoom.png");
	
	
	//Now we can set the preview!
	level->setImage(img);
}

bool MvQZoomStackData::setActLevel(int level)
{
	if(level >=0 && level < levelNum_ && level != actLevel_)
	{
		actLevel_=level;
		selectedLevel_=actLevel_;
		return true;
	}
	return false;
}

void MvQZoomStackData::stepUp()
{
	slotStepTo(actLevel_-1);
}

void MvQZoomStackData::stepDown()
{
	slotStepTo(actLevel_+1);
}

void MvQZoomStackData::slotStepTo(int level)
{
	if(setActLevel(level))
	{
		emit actLevelChanged(grLayoutId_,actLevel_);				 
	}
}

//=========================
//   MvQZoomStackWidget
//=========================

MvQZoomStackWidget::MvQZoomStackWidget(MgQPlotScene *scene,QWidget *parent) : QMenu(parent)
{
	setObjectName(QString::fromUtf8("zoomStackWidget"));        

	plotScene_=scene;
	activeScene_=0;
	currentPage_=0;
	skipUpdate_=false;
#ifndef METVIEW_QT5
	setStyle(new MvQZoomStackMenuPlastiqueStyle);
#endif
	connect(this,SIGNAL(triggered(QAction*)),
		this,SLOT(slotStepTo(QAction*)));
}

MvQZoomStackWidget::~MvQZoomStackWidget()
{
	QMapIterator<QString,MvQZoomStackData*> it(page_);
 	while (it.hasNext()) 
	{
     		it.next();
		delete it.value();
 	}
	page_.clear();	
}

void MvQZoomStackWidget::updateData()
{
	if(skipUpdate_) 
	{
		return;
	}
}

void MvQZoomStackWidget::reset(MgQSceneItem* activeScene,bool changeActiveScene)
{
	if(skipUpdate_) 
	{
		return;
	}

	activeScene_=activeScene;

 	if(!changeActiveScene)
	{  
		QStringList idLst;
		foreach(MgQSceneItem* item,plotScene_->sceneItems())
		{
			MgQLayoutItem *zoomLayout=item->firstProjectorItem();	
			if(zoomLayout)
			{
		   		idLst << QString::fromStdString(zoomLayout->layout().id());	
			}
		}
	
		//Remove unused scenes from the zoomstack
		foreach(QString id, page_.keys())
		{
	  		if(idLst.indexOf(id) == -1)
			{
				delete page_[id]; 
				page_.remove(id);
			}	
		}	
	}
	
	if(!activeScene_)
		return;

	//-----------------------------
	// Identify the active scene
	//-----------------------------
	
	MgQLayoutItem *zoomLayout=activeScene_->firstProjectorItem();
	if(!zoomLayout) return;

	int levelNum=zoomLayout->layout().zoomLevels();
	int actLevel=zoomLayout->layout().zoomCurrentLevel();
	QString id = QString::fromStdString(zoomLayout->layout().id());

	if(changeActiveScene)
	{  
		if(!page_.contains(id))
		{ 	
			page_[id] = new MvQZoomStackData(id);

			connect(page_[id],SIGNAL(actLevelChanged(QString,int)),
			        this,SIGNAL(actLevelChanged(QString,int)));
		
			//Find preview layout in the scene and remove it
			MgQPreviewLayoutItem *previewLayout=activeScene_->previewLayoutItem();
			if(!previewLayout) return;	
			plotScene_->removeItem(previewLayout);

			//Create a new scene and add the previewLayout to it!
			QGraphicsScene *previewScene= new QGraphicsScene;
			previewScene->addItem(previewLayout);
			previewLayout->setVisible(true);

			page_[id]->update(levelNum,actLevel,previewLayout);
		
			delete previewScene;
		}
	}
	else
	{
		if(!page_.contains(id))
		{	
			page_[id] = new MvQZoomStackData(id);

			connect(page_[id],SIGNAL(actLevelChanged(QString,int)),
			        this,SIGNAL(actLevelChanged(QString,int)));
		}


		//Find preview layout in the scene an remove it
		MgQPreviewLayoutItem *previewLayout=activeScene_->previewLayoutItem();
		if(!previewLayout) return;	
		plotScene_->removeItem(previewLayout);

		//Create a new scene and add the previewLayout to it!
		QGraphicsScene *previewScene= new QGraphicsScene;
		previewScene->addItem(previewLayout);
		previewLayout->setVisible(true);
	
		page_[id]->update(levelNum,actLevel,previewLayout);	  
	  
		delete previewScene;
	}
	
		
	foreach(QAction *action,actions())
	{
		removeAction(action);
		delete action;
	}

	for(int i=0; i < page_[id]->levels().count(); i++)
	{
		QAction *action = new QAction(this);			        		
		action->setIcon(page_[id]->levels().at(i)->pixmap());
		action->setData(i);
		addAction(action);
	}

	if(currentPage_ != page_[id])
	{
		currentPage_ = page_[id];
	}
}

MvQZoomStackData* MvQZoomStackWidget::pageData(MgQSceneItem* item)
{
	if(!item)
		return 0;
			
	MgQLayoutItem *zoomLayout=item->firstProjectorItem();	
	if(zoomLayout)
	{
		QString id=QString::fromStdString(zoomLayout->layout().id());	
	  	if(page_.find(id) != page_.end())
		{
		  	return page_[id];
		}
	}
	
	return 0;
}  

void MvQZoomStackWidget::slotStepUp()
{
	if(!currentPage_)
		return;

	if(currentLevel() >= 1)
	{	
		int level=currentLevel()-1;
		skipUpdate_=true;
		slotStepTo(level);
		skipUpdate_=false;
	}
}

void MvQZoomStackWidget::slotStepDown()
{
	if(!currentPage_)
		return;

	skipUpdate_=true;
	if(currentLevel() >=0 && currentLevel() < levelNum()-1)
	{
		int level=currentLevel()+1;
		skipUpdate_=true;	
		slotStepTo(level);
		skipUpdate_=false;
	}
}

void MvQZoomStackWidget::slotStepTo(QAction *action)
{
	if(!currentPage_)
		return;

	int level=action->data().toInt();

	qDebug() << "level" << level;

	if(level != -1)
	{
		skipUpdate_=true;
		currentPage_->slotStepTo(level);
		skipUpdate_=false;
	}
}

void MvQZoomStackWidget::slotStepTo(int level)
{
	if(!currentPage_)
		return;

	qDebug() << "level" << level;

	if(level != -1)
	{
		skipUpdate_=true;
		currentPage_->slotStepTo(level);
		skipUpdate_=false;
	}
}

int MvQZoomStackWidget::levelNum()
{
	if(!currentPage_)
		return 0;

	return currentPage_->levels().count();
}

int MvQZoomStackWidget::currentLevel()
{
	if(!currentPage_)
		return 0;

	return currentPage_->selectedLevel();
}

