/***************************** 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 <QBrush>
#include <QColor>
#include <QDebug>
#include <QHBoxLayout>
#include <QLabel>
#include <QMimeData>
#include <QMouseEvent>
#include <QPainter>
#include <QPushButton>
#include <QSlider>
#include <QStringList>
#include <QStyleOptionProgressBar>

#include "MvQLayerModel.h"
#include "MgQLayerItem.h"
#include "MgQPlotScene.h"
#include "MgQSceneItem.h"

#include "MvQLayerContentsIcon.h"

#include "Cached.h"
#include "MvPath.hpp"

//======================================
// Item delegate
//======================================

MvQLayerDelegate::MvQLayerDelegate(QWidget *parent) : QStyledItemDelegate(parent)
{
	itemHeight_=50+8;
}

void MvQLayerDelegate::paint(QPainter *painter,const QStyleOptionViewItem &option,
		           const QModelIndex& index) const
{
	int id=index.internalId();
	if(id <  100 && index.column() == 0)
	{
		QStyleOptionViewItemV4 vopt(option);
   		initStyleOption(&vopt, index);
   
    		const QStyle *style = vopt.widget ? vopt.widget->style() : QApplication::style();
    		const QWidget* widget = vopt.widget;

		//int height=option.rect.height();

		//vopt.text=QString();
		//vopt.icon=QIcon();		

		//We render everything with the default method
  		style->drawControl(QStyle::CE_ItemViewItem, &vopt, painter, widget);
	
		//Get current values from model
		QString txt=index.data(Qt::DisplayRole).toString();
		QPixmap pixmap=index.data(Qt::DecorationRole).value<QPixmap>();
		QBrush bg=index.data(Qt::BackgroundRole).value<QBrush>();
	
		//Save painter state
		painter->save();

		//Highlight
		//if (option.state & QStyle::State_HasFocus)
             	//	painter->fillRect(option.rect, option.palette.highlight());
	
	        //QRect checkRect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator,&vopt, widget);
                QRect iconRect = style->subElementRect(QStyle::SE_ItemViewItemDecoration, &vopt, widget);
                //QRect textRect = style-> subElementRect(QStyle::SE_ItemViewItemText, &vopt, widget);

		//Draw icon border
		painter->setPen(QColor(230,230,230));
		painter->drawRect(iconRect);

		//Text
		/*QString text=index.data(Qt::DisplayRole).toString();
		QRect textRect(iconRect.x()+iconRect.width()+10,option.rect.y()+5,
			       option.rect.width()-(iconRect.x()+iconRect.width()+5)-10, height/2-5);
		
		painter->setPen(Qt::black);
		painter->drawText(textRect,Qt::AlignLeft,text);*/

		//Draw separator line
		painter->setPen(QColor(230,230,230));
		painter->drawLine(option.rect.bottomLeft(),option.rect.bottomRight());

		//restore painter state
		painter->restore();			
	}		
	else
	{		
		QStyledItemDelegate::paint(painter,option,index);
	}
}
QSize MvQLayerDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
	QSize size=QStyledItemDelegate::sizeHint(option,index);
	
	int id=index.internalId();
	if(id <  100 && index.column() == 0)
	{
		size.setHeight(itemHeight_);
	}
	else
	{
	  	size+=QSize(0,6);
	}
	
	return size;
}
	
//======================================
// Item model
//======================================

MvQLayerModel::MvQLayerModel(MgQPlotScene *scene)
{
	scene_=scene;
}

MvQLayerModel::~MvQLayerModel()
{
	clearIcons();
}

void MvQLayerModel::clearIcons()
{
  	QHashIterator<MgQLayerItem*,QList<MvQLayerContentsIcon*> > it(icons_);
	while (it.hasNext()) 
	{
     		it.next();
	  	foreach(MvQLayerContentsIcon* icon,it.value())
		{
		  	if(icon) delete icon;
		}
	}
	 
	icons_.clear();
}  


void MvQLayerModel::layersAreAboutToChange()
{
	beginResetModel();
}

void MvQLayerModel::resetLayers(MgQSceneItem* scenItem)
{
  	sceneItem_=scenItem;
	clearIcons();
	if(sceneItem_)
	{
	  	layers_=sceneItem_->layerItems();
	}
	else
	{
	  	layers_.clear();
	}	
	endResetModel();
}

int MvQLayerModel::layerToRow(MgQLayerItem* layer) const
{
	if(!layer)
	  	return -1;
	
	int stackLevel=layer->stackLevel();
	
	return layers_.count()-1-stackLevel;
}

MgQLayerItem* MvQLayerModel::rowToLayer(int row) const
{
	//
	int stackLevel=layers_.count()-1-row;

	foreach(MgQLayerItem *item,layers_)
	{
		if(item->stackLevel() == stackLevel)
		{
			return item;
		}
	}
	return 0;
}

int MvQLayerModel::rowToStackLevel(int row)
{
	//
	return layers_.count()-1-row;
}

int MvQLayerModel::columnCount( const QModelIndex& /* parent */ ) const
{
   	 return 1;
}

int MvQLayerModel::rowCount( const QModelIndex& parent) const
{
    	if(!sceneItem_)
	  	return 0;
	  
	//Non-root
	if(parent.isValid() )
	{
		int id=parent.internalId();
		if(idToLevel(id) == 0)
		{
			MgQIconList icons;
			MgQLayerItem *item=rowToLayer(id);
			if(item)
			{
			  	sceneItem_->layerIconsForCurrentStep(item,icons);		
			}
			return icons.size();			
		}
		else
		{
			return 0;
		}
	}
	//Root
	else
	{
		return layers_.count();
	}	
	
	
}

Qt::ItemFlags MvQLayerModel::flags ( const QModelIndex & index) const
{
	Qt::ItemFlags defaultFlags;

	if(index.column() == 0)
		defaultFlags=Qt::ItemIsEnabled |
		   Qt::ItemIsSelectable |
		   Qt::ItemIsEditable |
		   Qt::ItemIsUserCheckable;
	else 
		defaultFlags=Qt::ItemIsEnabled |
		   Qt::ItemIsSelectable |
		   Qt::ItemIsEditable;

 	
    	if (index.isValid())
       		return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
     	else
        	return Qt::ItemIsDropEnabled | defaultFlags;
}

QVariant MvQLayerModel::data( const QModelIndex& index, int role ) const
{
	if( !index.isValid() || index.column() != 0)
        {			
		return QVariant();
	}
	
 	int id=index.internalId();
	if(idToLevel(id) == 0)
	{
		MgQLayerItem* layer=rowToLayer(id);
		if(!layer)
		  	return QVariant();
		
	  	if(role == Qt::CheckStateRole)
		{
			if(layer->layerVisibility() == true)
				return QVariant(Qt::Checked);
			else
				return QVariant(Qt::Unchecked);
		}
		else if(role == Qt::DisplayRole)
		{
			return label(layer,index.row(),index.column() );
		}
		else if(role == Qt::DecorationRole)
		{
			return QPixmap::fromImage(layer->preview());		
		}
	}	
	else if(idToLevel(id) == 1)	  
	{
		int parentRow=idToParentRow(id);
		MgQLayerItem* layer=rowToLayer( parentRow);
		if(!layer)
		  	return QVariant();
		
		MvQLayerContentsIcon *icon=layerIcon(layer,index.row());
		if(!icon)
		  	return QVariant();
				
		if(role == Qt::DisplayRole)
		{		
			return icon->name();
		}  
		else if(role == Qt::DecorationRole)
		{		
			return icon->pixmap();
		}  
		else if(role == Qt::UserRole)
		{
			return icon->path();	  
		}  
		  
	}
		
	
	/*else if(role == Qt::ToolTipRole)
	{
 		MgQLayerItem* layer=rowToLayer(index.row());
		
		map<string,string>::const_iterator it=layer->layer().getInfos().find("Desc");

		if( it!= layer->layer().getInfos().end())
		{
			return 	QString::fromStdString(it->second);
		}

		return QVariant();
	}*/

	return  QVariant();
}

bool MvQLayerModel::setData( const QModelIndex & index, const QVariant & value, int role) 
{
	if( !index.isValid())
	{
		return false;	
	}
	
	int id=index.internalId();
	if(idToLevel(id) != 0)
		return false;
	  
	if(index.column() == 0)
	{		
		if(role == Qt::CheckStateRole)
		{	
			MgQLayerItem* layer=rowToLayer(index.row());

			bool checked=(value.toInt() == Qt::Checked)?true:false;
			if(checked != layer->layerVisibility())
			{
				layer->setLayerVisibility(checked);	
				emit  dataChanged(index,index);

				//Notify the scene about the change in the layer status

				if(sceneItem_)
				  	sceneItem_->updateLayers();
				
				//emit  layerUpdate(); 
				emit layerVisibilityChanged(QString(layer->layer().id().c_str()),checked);
				
				return true;
								
			}
		}	
	}

	return false;

}
QVariant MvQLayerModel::headerData( const int section, const Qt::Orientation orient , const int role ) const
{
	if ( orient != Qt::Horizontal || role != Qt::DisplayRole )
        return QAbstractItemModel::headerData( section, orient, role );   

   	switch (section) 
    	{
    	case 0: 	
		return QString("Title");
		break;	
    	default:
        	return QString();
    	}
    	  	
    	return QVariant();
}

QString MvQLayerModel::label(MgQLayerItem* layer,const int /*row*/, const int column ) const
{
	switch ( column ) 
	{
    	case 0: 
	{
		QString str(layer->layer().name().c_str());
		QStringList lst=str.split("/");
		if(!lst.isEmpty())
		{
			return lst.last();
		}
		return QString();
	}
    	default:
        	return QString();
    	}
}

MvQLayerContentsIcon*  MvQLayerModel::layerIcon(MgQLayerItem *layer, int index) const
{
	if(index <0 || !layer) return 0;
  	
  	QHash<MgQLayerItem*,QList<MvQLayerContentsIcon*> >::const_iterator it=icons_.find(layer);
	if(it!= icons_.end())
	{
		if(index< it.value().count())
		{
			return it.value().at(index);	
		}
	}
	
	MgQIconList icons;
	sceneItem_->layerIconsForCurrentStep(layer,icons);
			
	for(int i=0; i < icons.size(); i++)	 
	{
	 	MvQLayerContentsIcon *icon=new MvQLayerContentsIcon(icons.at(i));			
		icons_[layer] << icon;
	} 
	 

	it=icons_.find(layer);
	if(it!= icons_.end())
	{ 
		if(index< it.value().count())
		{
			return it.value().at(index);	
		} 
	} 
	  
	return 0;  
}		
	
	
MvQLayerContentsIcon* MvQLayerModel::indexToIcon(const QModelIndex& index) const
{
	if( !index.isValid() || index.column() != 0)
        {			
		return 0;
	}
	
	int id=index.internalId();
	if(idToLevel(id) == 1)	  
	{
		int parentRow=idToParentRow(id);
		MgQLayerItem* layer=rowToLayer(parentRow);
		if(!layer)
		  	return 0;
		
		return layerIcon(layer,index.row());
	}	

	return  0;
}			  

QModelIndex MvQLayerModel::index( int row, int column, const QModelIndex& parent) const
{
	if(!sceneItem_ || row < 0 || column < 0 || parent.column() > 3)
	{
		return QModelIndex();
	}
	
	//Parent is non-root -> level-1 items: id is the parent row (number+1)*1000
	if(parent.isValid() )
	{
		int id=(parent.row()+1)*1000;
		return createIndex(row, column, id); 
	}
	//Parent is root -> level-0 items: id is the row number
	else
	{
		return createIndex(row, column, row); 
	}
}


QModelIndex MvQLayerModel::parent( const QModelIndex& index) const
{
	if(!index.isValid() )
	{
		return QModelIndex();
	}
	
	int id=index.internalId();
	if(idToLevel(id) == 0)
	{
		return QModelIndex();
	}
	else 
	{
		int parentRow=idToParentRow(id);
		return createIndex(parentRow,0,parentRow);
	}

	return QModelIndex();
}

int MvQLayerModel::idToLevel(int id) const
{
	if(id >=0 && id < 1000)
		return 0;
	else
		return 1;
}

int MvQLayerModel::idToParentRow(int id) const
{
	if(idToLevel(id) == 0)
		return -1;
	else
		return id/1000-1;
}

int MvQLayerModel::indexToLevel(const QModelIndex& index) const
{
  	return idToLevel(index.internalId());
}	

MgQLayerItem* MvQLayerModel::layer(const QModelIndex& index) const
{
	if(!index.isValid())
		return 0;
	
	return rowToLayer(index.row());
}

int MvQLayerModel::transparency(const QModelIndex& index)
{
	if(!index.isValid())
		return 0;
	
	MgQLayerItem* layer=rowToLayer(index.row());
  	
	if(!layer)
	  	return 0;
	
	int value=static_cast<int>((1.-layer->layerAlpha())*100.);
	if(value < 0)
		value=0;
	else if (value > 100)
		value=100;
	
	return value;
}


void MvQLayerModel::setTransparency(const QModelIndex& index,int value)
{
	if(!index.isValid() || value < 0 || value > 100)
		return;
	
	MgQLayerItem* layer=rowToLayer(index.row());
	float alpha = 1.-static_cast<float>(value)/100.;
	layer->setLayerAlpha(alpha);

	//Notify the scene about the change in the layer status

	if(sceneItem_)
	  	sceneItem_->updateLayers();
	
	emit layerTransparencyChanged(QString(layer->layer().id().c_str()),value);
	
}


void MvQLayerModel::moveUp(const QModelIndex& index)
{
	if(!index.isValid())
		return;

	moveLayer(index.row(),index.row()-1);	
}	

void MvQLayerModel::moveDown(const QModelIndex& index)
{
	if(!index.isValid())
		return;

	moveLayer(index.row(),index.row()+1);
	
}	

void MvQLayerModel::moveTop(const QModelIndex& index)
{
	if(!index.isValid())
		return;

	moveLayer(index.row(),0);	
}

void MvQLayerModel::moveBottom(const QModelIndex& index)
{
	if(!index.isValid())
		return;

	moveLayer(index.row(),rowCount(index));	
}


void MvQLayerModel::moveLayer(int sourceRow,int targetRow)
{
	if(sourceRow < 0 ||  sourceRow >= layers_.count() ||
	   targetRow < 0 ||  targetRow >= layers_.count() ||
           sourceRow == targetRow )
	{
		return;
	}

	//This list for each stackLevel assigns the corresponding Layer item
	QList<MgQLayerItem*> stackLevel;
	for(int i=0; i < layers_.count(); i++)
	{
		bool found=false;
		foreach(MgQLayerItem *item, layers_)
		{
			if(item->stackLevel() == i)
			{
				stackLevel << item;
				found=true;
			}
		}
		if(found == false)
		{
			qDebug() <<  "MvQLayerModel::moveLayer --> Inconsistency in stackLevels!";
			return;
		}
	}

	//No simpy move the sorce index to the target!!
	stackLevel.move(rowToStackLevel(sourceRow),rowToStackLevel(targetRow));

	QList<QPair<QString,int> > stackingOrder;
	
	
	//Reset the stacklevels for all the layer items!!!
	for(int i=0; i < stackLevel.count(); i++)
	{
		stackLevel[i]->setStackLevel(i);
		stackingOrder << qMakePair(QString(stackLevel[i]->layer().id().c_str()),i); 
	}

	emit layerStackingOrderChanged(stackingOrder);
	
	/*

	layers_[i]->setStackLevel(stackLevel[i]);
		qDebug() << "set layer:" << i << "to" << stackLevel[i];
	}	


	QList<int> stackLevel;
	foreach(MgQLayerItem *item, layers_)
	{
		stackLevel << item->stackLevel();
	}
	
	qDebug() << "stackLevel:" << stackLevel;
	qDebug() << "move" << sourceRow << targetRow << rowToStackLevel(sourceRow) <<  rowToStackLevel(targetRow);

	stackLevel.move(rowToStackLevel(sourceRow),rowToStackLevel(targetRow));

	qDebug() << "stackLevel:" << stackLevel;

	for(int i=0; i < stackLevel.count(); i++)
	{
		layers_[i]->setStackLevel(stackLevel[i]);
		qDebug() << "set layer:" << i << "to" << stackLevel[i];
	}
	
	*/
	
	//Notify the scene about the change in the layer status

	if(sceneItem_)
	  	sceneItem_->updateLayers();
	
	//layers_[0]->scene()->update();

		//reset();  NOT in Qt 5
	beginResetModel();
	endResetModel();	
}

string MvQLayerModel::layerId(const QModelIndex& index) 
{	
	MgQLayerItem* item=layer(index);

	if(!item)
		return string();
		
	return item->layer().id();
}

  
QString MvQLayerModel::layerName(const QModelIndex& index) 
{
	MgQLayerItem* item=layer(index);

	if(!item)
		return QString();
		
	QString str(item->layer().name().c_str());
	QStringList lst=str.split("/");
	if(!lst.isEmpty())
	{
		return lst.last();
	}
	
	return QString();
}


void MvQLayerModel::layerMetaData(const QModelIndex& index,MetaDataCollector &md) 
{
	MgQLayerItem* item=layer(index);
	if(!item)
		return;
	
	//MetaDataCollector mdc=metaData;

	if(sceneItem_)
		sceneItem_->layerMetaDataForCurrentStep(item,md);	
	
	//metaData=mdc;
}

QString MvQLayerModel::layerMetaData(const QModelIndex& index,QString key) 
{
	MgQLayerItem* item=layer(index);

	if(!item)
		return QString();

	MetaDataCollector md;
	string keyStr=key.toStdString();
	md[keyStr]="";
		
	sceneItem_->layerMetaDataForCurrentStep(item,md);	
	
	return QString::fromStdString(md[keyStr]);
}


/*
const map<string,string>& MvQLayerModel::layerInfo(const QModelIndex& index) 
{
	static const map<string,string> emptyMap;

	MgQLayerItem* item=layer(index);
	if(!item)
		return emptyMap;

	return scene_->getLayerInfoForCurrentStep(item);
}

QString MvQLayerModel::layerInfo(const QModelIndex& index,QString key) 
{
	MgQLayerItem* item=layer(index);

	if(!item)
		return QString();

	const map<string, string>& itemInfo=scene_->getLayerInfoForCurrentStep(item);		
	//const map<string, string>& itemInfo=item->layer().getInfos();
	if(!itemInfo.empty())
	{
		map<string,string>::const_iterator it=item->layer().getInfos().find(key.toStdString());
		if(it !=  itemInfo.end())
		{
			return QString::fromStdString(it->second);
		}
	}
	
	return QString();
}
*/

Qt::DropActions MvQLayerModel::supportedDropActions() const
{
	return Qt::CopyAction;
}

QStringList MvQLayerModel::mimeTypes() const
 {
     QStringList types;
     types << "application/vnd.text.list";
     return types;
 }

QMimeData* MvQLayerModel::mimeData(const QModelIndexList &indexes) const
 {
     	QMimeData *mimeData = new QMimeData();
     	QByteArray encodedData;

     	QDataStream stream(&encodedData, QIODevice::WriteOnly);

    	foreach (QModelIndex index, indexes) 
	{
        	if (index.isValid()) 
		{
             		QString text = QString::number(index.row());
             		stream << text;
         	}
     	}

     	mimeData->setData("application/vnd.text.list", encodedData);
     	return mimeData;
}

bool MvQLayerModel::dropMimeData(const QMimeData *data,
     Qt::DropAction action, int row, int /*column*/, const QModelIndex &parent)
{
     	if (action == Qt::IgnoreAction)
        	return true;

     	if (!data->hasFormat("application/vnd.text.list"))
        	return false;

	int beginRow;

     	if (row != -1)
        	beginRow = row; 
	else if (parent.isValid())
        	beginRow = parent.row();
	else
         	beginRow = rowCount(QModelIndex());

	QByteArray encodedData = data->data("application/vnd.text.list");
     	QDataStream stream(&encodedData, QIODevice::ReadOnly);
    	QStringList newItems;
     	int rows = 0;

     	while (!stream.atEnd()) 
	{
        	QString text;
         	stream >> text;
         	newItems << text;
         	rows++;
     	}
 	
	qDebug() << "newItems:" <<  newItems;


	if(rows ==0)
		return false;

	
	int sourceRow=newItems[0].toInt();
	moveLayer(sourceRow,beginRow);

	emit layerDragFinished();

     	return true;
}
