/***************************** 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 "MvQProductBrowser.h"

#include <QApplication>
#include <QCloseEvent>
#include <QDialogButtonBox>
#include <QDebug>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QMouseEvent>
#include <QPainter>
#include <QPushButton>
#include <QSettings>
#include <QVBoxLayout>

#include "MvQIconMimeData.h"
#include "MvQIconProvider.h"

#include "IconClass.h"
#include "Path.h"
#include "Product.h"

QMap<Product*,QPixmap> MvQProductModel::pixmaps_;
int MvQProductModel::itemHeight_;

//=====================================================
//
// MvQProductListDelegate
//
//=====================================================

MvQProductListDelegate::MvQProductListDelegate(MvQProductModel* prodModel,int itemHeight,QWidget *parent) : 
  QStyledItemDelegate(parent),
  prodModel_(prodModel),
  itemHeight_(itemHeight)
{
	
}

void MvQProductListDelegate::paint(QPainter *painter,const QStyleOptionViewItem &option,
		           const QModelIndex& index) const
{
	if(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();

		//Get font size
		QFont font=QApplication::font();
		QFontMetrics fm(font);
		int fontSize=fm.height()+4;
		
		//Save painter state
		painter->save();
		
		//Highlight
		if (option.state & QStyle::State_HasFocus)
             		painter->fillRect(option.rect, option.palette.highlight());
			
		//Draw icon
		QPixmap pixmap=index.data(Qt::DecorationRole).value<QPixmap>();
		QRect iconRect = style->subElementRect(QStyle::SE_ItemViewItemDecoration, &vopt, widget);
		painter->drawPixmap(iconRect,pixmap);
		
		//Draw icon border
		painter->setPen(QColor(230,230,230));
		painter->drawRect(iconRect);		
		
		//-------------------
		// Pushbuttons
		//-------------------
		
		int buttonWidth=0;
		int buttonHeight=fontSize+4;
		int buttonY=option.rect.bottomRight().y()-3-buttonHeight;
								
		//Vis pb
		QStyleOptionButton visPbOpt;        
		visPbOpt.text="Visualise";
		visPbOpt.state = QStyle::State_Active | QStyle::State_Enabled;
        	
		buttonWidth=fm.width(visPbOpt.text)+6;
		visPbOpt.rect = QRect(option.rect.width()-6-buttonWidth,
        			      buttonY,
				      buttonWidth,
        			      buttonHeight); 
								 
        	style->drawControl(QStyle::CE_PushButton, &visPbOpt, painter,widget);	
		prodModel_->setData(index,visPbOpt.rect,MvQProductModel::FolderPbRole);					
		
		//Open pb
		QStyleOptionButton folderPbOpt;        
        	folderPbOpt.text="Open";
		folderPbOpt.state = QStyle::State_Active | QStyle::State_Enabled;
        	
		buttonWidth=fm.width(folderPbOpt.text)+6+16+2;
		folderPbOpt.rect = QRect(visPbOpt.rect.topLeft().x()-16-buttonWidth,
					 buttonY,
				 	 buttonWidth,
					 buttonHeight); 
								 
		folderPbOpt.icon=MvQIconProvider::pixmap(IconClass::find("FOLDER"),16);	
		folderPbOpt.iconSize=QSize(16,16);
		
        	style->drawControl(QStyle::CE_PushButton, &folderPbOpt, painter,widget);	
		prodModel_->setData(index,folderPbOpt.rect,MvQProductModel::FolderPbRole);		
	  
		//Draw separator line
		painter->setPen(QColor(230,230,230));
		painter->drawLine(option.rect.bottomLeft(),option.rect.bottomRight());
		
		//-----------------------
		// Title + Description
		//-----------------------
		
		font.setBold(true);					
		painter->setFont(font);
		if(option.state & QStyle::State_HasFocus)	
			painter->setPen(option.palette.highlightedText().color());
		else
		  	painter->setPen(option.palette.text().color());
		
		//Title
		int textWidth=option.rect.width()-(iconRect.x()+iconRect.width()+5)-10;		
				
		QString title=index.data(Qt::DisplayRole).toString();
		QRect titleRect(iconRect.topRight().x()+10,option.rect.y()+3,
			        textWidth, fontSize+7);
				
		painter->drawText(titleRect,Qt::AlignLeft,title);
		
		textWidth=folderPbOpt.rect.x()-15-(iconRect.topRight().x()+10);  	
		
		//Description
		/*font.setBold(false);
		painter->setFont(font);
		
		QString desc=index.data(MvQProductModel::DescriptionRole).toString();
		QRect descRect(titleRect.x(),
			       titleRect.bottomLeft().y()+7,
			       textWidth,
			       fontSize*2+10);
			       	
				
		painter->drawText(descRect,Qt::TextWordWrap | Qt::AlignLeft,desc);*/
				

		//restore painter state
		painter->restore();			
	}		
	else
	{		
		QStyledItemDelegate::paint(painter,option,index);
	}
}
QSize MvQProductListDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
	QSize size=QStyledItemDelegate::sizeHint(option,index);

	if(index.column() == 0)
	{
		size.setHeight(itemHeight_);
	}
	else
	{
	  	size+=QSize(0,6);
	}
	
	return size;
}
	
//=====================================================
//
// MvQProductListView
//
//=====================================================	

MvQProductListView::MvQProductListView(QWidget *parent) : QListView(parent)
{
}  

void MvQProductListView::mousePressEvent(QMouseEvent *event)  
{
	QModelIndex index=indexAt(event->pos());
	if(index.isValid())
	{  	
		if(model()->data(index,MvQProductModel::FolderPbRole).toRect().contains(event->pos()))
		{
		  	emit openFolder(index);
		}	
	
	}
	
	QAbstractItemView::mousePressEvent(event);
}  
 
//=============================================
//
// MvQProductModel
//
//=============================================

MvQProductModel::MvQProductModel(int itemHeight,QObject *parent) : 
   QAbstractItemModel(parent)
{ 
	itemHeight_=itemHeight;
}

MvQProductModel::~MvQProductModel()
{
}

void MvQProductModel::setProduct(const vector<Product*>& data)
{
	beginResetModel();
	folderPbRect_.clear();
	visPbRect_.clear();	
	data_=data;	
	endResetModel();
}

int MvQProductModel::columnCount( const QModelIndex& parent) const
{
	 return parent.isValid() ? 0 : 1;
}

int MvQProductModel::rowCount( const QModelIndex& index) const
{	
	if (!index.isValid() )
	{		
	  	return static_cast<int>(data_.size());
	}
	else
	{
		return  0;
	}
}

QVariant MvQProductModel::data( const QModelIndex& index, int role ) const
{	
  	if(!index.isValid() || index.column() != 0)
	{
		return QVariant();
	}
	
	if(index.row() <0 || index.row() >= static_cast<int>(data_.size()))
	{
		return QVariant();
	}  
		
	int row=index.row();
	
	switch(role)
	{
		case Qt::DecorationRole:  			
		  	return MvQProductModel::pixmap(data_.at(row));		  		
			
		case Qt::DisplayRole:
	  		return QString::fromStdString(data_.at(row)->title());
		
		case DescriptionRole:
		case Qt::ToolTipRole:
		         return QString::fromStdString(data_.at(row)->description());
		
		case FolderPbRole:	 	
			return folderPbRect_.value(index);
		 
		case VisPbRole:	 	
			return folderPbRect_.value(index);
		
		case PathRole:	 	
			return QString::fromStdString(data_.at(row)->path());
		
		default:
		  	break;
	}
	
	return QVariant();
}


bool MvQProductModel::setData(const QModelIndex & index, QRect rect, int role) 
{			
	if(!index.isValid())
	{
		return false;	
	}
	
	if(role == FolderPbRole)  	
	{
	  	folderPbRect_[index]=rect;
		return true;
	}
	else if(role == VisPbRole)  	
	{
	  	visPbRect_[index]=rect;
		return true;
	}
	
	return false;
}

QModelIndex MvQProductModel::index( int row, int column, const QModelIndex & /*parent*/ ) const
{

	return createIndex(row,column,(void*)0);
}


QModelIndex MvQProductModel::parent( const QModelIndex & /*index*/ ) const
{
    return QModelIndex();
}


QPixmap MvQProductModel::pixmap(Product *item)
{
	if(!item || !item->hasImage())
	  	return QPixmap();
	
  	QMap<Product*,QPixmap>::iterator it=pixmaps_.find(item);
	if(it != pixmaps_.end())
		return it.value();
			
	QImage img(QString::fromStdString(item->imagePath()));
					  
	QPixmap pix=QPixmap::fromImage(img.scaledToHeight(itemHeight_-8,Qt::SmoothTransformation));
				          
	pixmaps_[item]=pix;
	 
	return pix;
}

//=============================================
//
// MvQProductListWidget
//
//=============================================

MvQProductListWidget::MvQProductListWidget(QWidget *parent) : 
    QListWidget(parent)
{
	setAcceptDrops(false);
	setDragEnabled(true);
}  

void MvQProductListWidget::mousePressEvent(QMouseEvent *event)
{
	if( event->button() == Qt::LeftButton)
	{
		startPos_=event->pos();
	}
	
	QListView::mousePressEvent(event);
}

void MvQProductListWidget::mouseMoveEvent(QMouseEvent *event)
{
	if(event->buttons() & Qt::LeftButton)
	{
		int distance = (event->pos() - startPos_).manhattanLength();
		if(distance >= QApplication::startDragDistance())
		{
			 performDrag();
		}	
	}
	
	QListView::mouseMoveEvent(event);
}

void MvQProductListWidget::performDrag()
{
	/*QListWidgetItem *item=currentItem();
	
	if(!item)
		return;
		
	const IconClass& iconClass=IconClass::find(item->data(Qt::UserRole).toString().toStdString());
	
	
	MvQNewIconMimeData::IconDefType type=(iconDefType_ == UserDef)?
	                                     (MvQNewIconMimeData::UserDef):
	                                     (MvQNewIconMimeData::SystemDef);
	
	MvQNewIconMimeData *mimeData= new MvQNewIconMimeData(iconClass.name().c_str(),type);
	
	QDrag *drag = new QDrag(this);
	drag->setPixmap(MvQPixmapProvider::current()->pixmap(iconClass));
	drag->setMimeData(mimeData);	
		
	if(drag->exec(Qt::CopyAction)  == Qt::CopyAction)
	{
	}*/								  	
}	

//=====================================================
//
// MvQProductBrowser
//
//=====================================================

MvQProductBrowser::MvQProductBrowser(QWidget *parent) : 
        QDialog(parent)       
{		
	//setAttribute(Qt::WA_DeleteOnClose);
	
	setWindowTitle("Metview - products");
	
	//Initial size
	resize(QSize(600,800));
	
	//layout
	QVBoxLayout *vb=new QVBoxLayout;
	vb->setSpacing(0); 
	vb->setContentsMargins(1,1,1,1);
	setLayout(vb);

	//Search
	QLabel *label=new QLabel("Search:");
	searchLine_=new QLineEdit(this);
	
	QHBoxLayout *hb=new QHBoxLayout(this);
	hb->addWidget(label);
	hb->addWidget(searchLine_,1);
	vb->addLayout(hb);
	
	searchList_=new MvQProductListView(this);
	vb->addWidget(searchList_);
	
	//Item height in view
	QFont font=QApplication::font();
	QFontMetrics fm(font);
	int itemHeight=fm.height()*5+10;
	if(itemHeight < 58) itemHeight=58;

	model_=new MvQProductModel(itemHeight,this);
	searchList_->setModel(model_);
	
	MvQProductListDelegate *delegate=new MvQProductListDelegate(model_,itemHeight,this);
	searchList_->setItemDelegate(delegate);
	
	connect(searchLine_,SIGNAL(textChanged(QString)),
		this, SLOT(slotSearch(QString)));
		
	connect(searchList_,SIGNAL(openFolder(const QModelIndex&)),
		this,SLOT(slotOpenFolder(const QModelIndex&)));
				
	// Buttons
	buttonBox_= new QDialogButtonBox(this);
	
	buttonBox_->addButton(QDialogButtonBox::Close);
	
	connect(buttonBox_, SIGNAL(clicked(QAbstractButton*)), 
		this, SLOT(slotButtonClicked(QAbstractButton*)));
	
	vb->addWidget(buttonBox_);
}

MvQProductBrowser::~MvQProductBrowser()
{	
}

void MvQProductBrowser::closeEvent(QCloseEvent* event)
{
	//emit aboutToClose(this);
	close();
	event->accept();
}

void MvQProductBrowser::slotButtonClicked(QAbstractButton* button)
{
	if(!button) return;
	
	if(buttonBox_->standardButton(button) == QDialogButtonBox::Close)
	{
		close();
		accept();  	
	}  
  
} 
void MvQProductBrowser::slotItemSelected(QListWidgetItem* /*item*/)
{
  	/*QMap<const IconClass&,QListWidgetItem*>::iterator it=classes_.find(item);
	if(it != classes_.end())
		selected_=it.value();  */

	//accept();  
}  

void MvQProductBrowser::slotSearch(QString str)
{
  	vector<Product*> res;
	
	if(str.simplified().isEmpty())
	{
		model_->setProduct(res);
		return;
	}	
  
	Product::find(str.toStdString(),res);
	model_->setProduct(res);
	
	/*searchList_->clear();
	
	
	
	for(vector<Product*>::iterator it=res.begin(); it != res.end(); it++)
	{			
		if((*it)->hasImage())
		{
		  	QImage img(QString::fromStdString((*it)->imagePath()));
					  
	  		QListWidgetItem *item=new QListWidgetItem(QPixmap::fromImage(img.scaled(60,45,Qt::KeepAspectRatio,Qt::SmoothTransformation)),
				              QString::fromStdString((*it)->title()));
						
			item->setData(Qt::UserRole,QString::fromStdString((*it)->title()));
			searchList_->addItem(item);
		}	
	}*/	
}  

void MvQProductBrowser::slotOpenFolder(const QModelIndex& index)
{
	emit openFolderInWin(model_->data(index,MvQProductModel::PathRole).toString()) ;   
}  
 
void MvQProductBrowser::writeSettings()
{
}	

void MvQProductBrowser::readSettings()
{
}	
