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

 Copyright 2015 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 "MvQNewIconWidget.h"

#include <QApplication>
#include <QButtonGroup>
#include <QComboBox>
#include <QDebug>
#include <QDialogButtonBox>
#include <QHBoxLayout>
#include <QKeyEvent>
#include <QLabel>
#include <QLineEdit>
#include <QListWidget>
#include <QMouseEvent>
#include <QPainter>
#include <QPushButton>
#include <QSettings>
#include <QStackedWidget>
#include <QStyle>
#include <QStyleOption>
#include <QToolButton>
#include <QVBoxLayout>
#include <QDrag>

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

#include "Path.h"

//==============================
//
// MvQNewIconDelegate
//
//==============================

MvQNewIconDelegate::MvQNewIconDelegate(QWidget *parent) : QStyledItemDelegate(parent)
{
}
 
void MvQNewIconDelegate::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;

		//painter->fillRect(option.rect,QColor(238,238,238));
		
		//We render everything with the default method
  		style->drawControl(QStyle::CE_ItemViewItem, &vopt, painter, widget);
	
		//Draw separator line
		//painter->save();
		//painter->setPen(QColor(180,180,180));
		//painter->drawLine(option.rect.x(),option.rect.bottom()+1,
		//		  option.rect.right(),option.rect.bottom()+1);
				  
		//QRect iconRect = style->subElementRect(QStyle::SE_ItemViewItemDecoration, &vopt, widget);              
		//painter->drawLine(iconRect.right()+4,iconRect.top()-4,
		//		  iconRect.right()+4,iconRect.bottom());		  
				  
		//painter->restore();		
	}
	else
	 	QStyledItemDelegate::paint(painter,option,index);
}		
		
//==============================
//
// MvQNewIconListWidget
//
//==============================

MvQNewIconListWidget::MvQNewIconListWidget(QWidget *parent) : 
    QListWidget(parent)
{
	setDragEnabled(true); 
	
	setSpacing(1); 
	setProperty("sidebarView","true");
	
	MvQNewIconDelegate* delegate=new MvQNewIconDelegate(this);
	setItemDelegate(delegate);
		
	setContextMenuPolicy(Qt::CustomContextMenu);
}  


//--------------------------------
// Drag
//--------------------------------

void MvQNewIconListWidget::mousePressEvent(QMouseEvent *event)
{
	if(event->button() == Qt::LeftButton)
	{
		startPos_=event->pos();
		
		/*QListWidgetItem *item=itemAt(event->pos());
		if(item)
		{			 				  		  		  		  
			startPos_=event->pos();  			
		}*/			 	
	}
	
	QListView::mousePressEvent(event);
}

void MvQNewIconListWidget::mouseMoveEvent(QMouseEvent *event)
{
   	if(event->buttons() & Qt::LeftButton)
	{	  	
	  	int distance = (event->pos() - startPos_).manhattanLength();
		if(distance >= QApplication::startDragDistance())
		{			
		  	QListWidgetItem *item=itemAt(startPos_);
			if(item)
			{
				QString cname=item->data(Qt::UserRole).toString();			
				MvQNewIconMimeData *mimeData=new MvQNewIconMimeData(cname,MvQNewIconMimeData::UserDef);
				
				qDebug() << "cname" << cname;
				
				QDrag *drag=new QDrag(this);			
				drag->setPixmap(MvQIconProvider::pixmap(IconClass::find(cname.toStdString()),20));
				drag->setHotSpot(QPoint(20,20));
				drag->setMimeData(mimeData);
				
				if(drag->exec(Qt::CopyAction) == Qt::CopyAction)
				{
				  	emit iconCreated(cname);
				}
				return;
			}			
		}
	}		

	QListView::mouseMoveEvent(event);
}	

//=====================================================
//
// MvQNewIconPanel
//
//=====================================================

MvQNewIconPanel::MvQNewIconPanel(SelectionMode mode,QWidget *parent) : 
     QWidget(parent),
     selectionMode_(mode)
{		 	  	
  	QVBoxLayout *vb=new QVBoxLayout;
	vb->setSpacing(2); 
	vb->setContentsMargins(2,2,2,2);
	setLayout(vb);
	
	QLabel *label;
	
	//In panel mode we need a close button
	if(selectionMode_ == PanelMode)
	{	  		
		//Top row 
		QHBoxLayout *hb=new QHBoxLayout;
		hb->setSpacing(0); 
		hb->setContentsMargins(0,0,0,0);
	
		vb->addLayout(hb);	
	
		hb->addSpacing(4);
		label=new QLabel("<b>" + tr("Create new icon") + "</b>",this);
		hb->addWidget(label,1);
	
		QToolButton *closeTb=new QToolButton(this);
		closeTb->setAutoRaise(true);	
		closeTb->setIcon(QPixmap(":/desktop/remove.svg")); 
		closeTb->setToolTip(tr("Close sidebar"));
		hb->addWidget(closeTb);
	
		connect(closeTb,SIGNAL(clicked(bool)),
			this,SIGNAL(closePanel(bool)));
	}	
	
	//Button row	
	QHBoxLayout *hbButton=new QHBoxLayout;
	vb->addLayout(hbButton);	
	hbButton->setSpacing(0);
	
	QSize icSize(16,16);
	
	QToolButton *recentTb=new QToolButton(this);
	recentTb->setIcon(QPixmap(":/desktop/history.svg"));
	recentTb->setIconSize(icSize);
	recentTb->setToolTip(tr("Most recent"));
	recentTb->setCheckable(true);
	recentTb->setChecked(false);
	recentTb->setText(tr("Recent"));
	recentTb->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
	recentTb->setProperty("mvStyle","strip");
	recentTb->setProperty("strip","first");	
	recentTb->setFocusPolicy(Qt::NoFocus);
	hbButton->addWidget(recentTb);

	QToolButton *groupTb=new QToolButton(this);
	groupTb->setIcon(QPixmap(":/desktop/icon_group.svg"));
	groupTb->setIconSize(icSize);
	groupTb->setToolTip(tr("Types"));
	groupTb->setCheckable(true);
	groupTb->setChecked(false);
	groupTb->setText(tr("Types"));
	groupTb->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
	groupTb->setProperty("mvStyle","strip");
	groupTb->setProperty("strip","mid");
	groupTb->setFocusPolicy(Qt::NoFocus);
	hbButton->addWidget(groupTb);

	QToolButton *searchTb=new QToolButton(this);
	searchTb->setIcon(QPixmap(":/desktop/filter.svg"));
	searchTb->setIconSize(icSize);
	searchTb->setToolTip(tr("Filter"));
	searchTb->setCheckable(true);
	searchTb->setChecked(false);
	searchTb->setText(tr("Filter"));
	searchTb->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
	searchTb->setProperty("mvStyle","strip");
	searchTb->setProperty("strip","last");
	searchTb->setFocusPolicy(Qt::NoFocus);
	hbButton->addWidget(searchTb);
	
	hbButton->addStretch(1);
	
	vb->addSpacing(3);
	
	//Button group for mode selection
	modeBg_=new QButtonGroup(this);
	modeBg_->setExclusive(true);
	
	modeBg_->addButton(recentTb,0);
	modeBg_->addButton(groupTb,1);
	modeBg_->addButton(searchTb,2);

	connect(modeBg_,SIGNAL(buttonClicked(int)),
		this,SLOT(slotChangeMode(int)));
		
	//----------------------------------------------------
	// Stacked widget for all the icon selection widgets
	//----------------------------------------------------
	
  	mainPanel_=new QStackedWidget(this);
	vb->addWidget(mainPanel_);
  		
	//---------------------------
	// Recently used 
	//---------------------------
  		
  	recentList_=new MvQNewIconListWidget(this);
	mainPanel_->addWidget(recentList_);
	
	connect(recentList_,SIGNAL(itemActivated(QListWidgetItem*)),
		this,SLOT(slotIconSelected(QListWidgetItem*)));	
		
  	connect(recentList_,SIGNAL(iconCreated(QString)),
		this,SLOT(slotAddToRecentIcons(QString)));	
		
	//---------------------------
	// Type widget
	//---------------------------
  		
  	QWidget *typeW=new QWidget(this);	
  	QVBoxLayout *typeVb=new QVBoxLayout(typeW);
	//typeVb->setSpacing(0); 
	typeVb->setContentsMargins(1,1,1,1);
	
	//Type
	QHBoxLayout *typeHb=new QHBoxLayout;	
	QLabel *typeLabel=new QLabel(tr("Type: "));
	typeHb->addWidget(typeLabel);
	typeCb_=new QComboBox(this);
	typeHb->addWidget(typeCb_,1);
	typeVb->addLayout(typeHb);	
	
	//Icon
	iconPanel_=new QStackedWidget(this);
	typeVb->addWidget(iconPanel_);
		
	// Scan for icons that can be created	
	IconClass::scan(*this);
	
	foreach(QString key,iconLists_.keys())
	{
	  	typeCb_->addItem(key,key);	  	
	  	iconPanel_->addWidget(iconLists_[key]);
		iconLists_[key]->sortItems();
		
		connect(iconLists_[key],SIGNAL(iconCreated(QString)),
		      this,SLOT(slotAddToRecentIcons(QString)));
		
		//This is just a selection,. It will not trigger the itemactivated signal.
		if(iconLists_[key]->count() >0)
			iconLists_[key]->setCurrentRow(0);	
	}
	
	mainPanel_->addWidget(typeW);
	
	connect(typeCb_,SIGNAL(currentIndexChanged(int)),
		this,SLOT(slotTypeChanged(int)));
		
	//------------------
	// Search widget
	//------------------
	
	QWidget *searchW= new QWidget(this);
	QVBoxLayout *searchVb=new QVBoxLayout(searchW);	
	searchVb->setSpacing(0); 
	searchVb->setContentsMargins(1,1,1,1);
		
	QHBoxLayout *searchHb=new QHBoxLayout;	
	label=new QLabel(tr("Filter:"));
	searchLine_=new QLineEdit(searchW);	
	searchHb->addWidget(label);
	searchHb->addSpacing(2);
	searchHb->addWidget(searchLine_,1);
	searchVb->addLayout(searchHb);
	searchVb->addSpacing(4);
	
	searchList_=new MvQNewIconListWidget(searchW);
	searchVb->addWidget(searchList_);
	
	connect(searchList_,SIGNAL(itemActivated(QListWidgetItem*)),
		this,SLOT(slotIconSelected(QListWidgetItem*)));	
		
	connect(searchList_,SIGNAL(iconCreated(QString)),
		this,SLOT(slotAddToRecentIcons(QString)));	
	

	mainPanel_->addWidget(searchW);
	
	connect(searchLine_,SIGNAL(textChanged(QString)),
		this,SLOT(slotSearch(QString)));
			
	//----------------
	// Init
	//----------------
	
	slotSearch("");
	updateRecentList();	
	
	modeBg_->button(2)->setChecked(true);
	mainPanel_->setCurrentIndex(2); 
	
	MvQRecentIcons::addObserver(this);
	
	setProperty("sidebar","true");
}
		
MvQNewIconPanel::~MvQNewIconPanel()
{   
	MvQRecentIcons::removeObserver(this);
}

void MvQNewIconPanel::next(const IconClass& c)
{
  	if(c.canBeCreated())
	{
		QString type=QString::fromStdString(c.iconBox());
		if(type.isEmpty())
			type="Other";
		
		MvQNewIconListWidget *w;
		QMap<QString,MvQNewIconListWidget*>::iterator it=iconLists_.find(type);
		if(it == iconLists_.end())
		{  
			w=new MvQNewIconListWidget(this);
			connect(w,SIGNAL(itemActivated(QListWidgetItem*)),
				this,SLOT(slotIconSelected(QListWidgetItem*)));	
			
			iconLists_[type]=w;
		}
		else 
		{
			w=it.value();
		}
			
		QListWidgetItem *typeItem=new QListWidgetItem(MvQIconProvider::pixmap(c,20),
						 QString::fromStdString(c.defaultName()));
								  
		typeItem->setData(Qt::UserRole,QString::fromStdString(c.name()));
			
		w->addItem(typeItem);	
				
		iconClasses_.push_back(&c);
	}	
}

void MvQNewIconPanel::slotTypeChanged(int index)
{	
  	QString type=typeCb_->itemData(index).toString();
  	QMap<QString,MvQNewIconListWidget*>::iterator it=iconLists_.find(type);
	if(it != iconLists_.end())
	{  
	 	iconPanel_->setCurrentWidget(it.value());
	}
}

void MvQNewIconPanel::slotIconSelected(QListWidgetItem* item)
{  		  		  
	if(selectionMode_ == DialogMode)	
	{
	  	QString name=item->data(Qt::UserRole).toString();
	  	emit iconSelected(name);		
		slotAddToRecentIcons(name); 
	}	
}  

void MvQNewIconPanel::slotSearch(QString str)
{
  	vector<const IconClass*> res;
		
	if(str.simplified().isEmpty())
	{		
	  	if(searchList_->count() != static_cast<int>(iconClasses_.size()))
		{
			res=iconClasses_;
			searchList_->clear();	 	
		}
		else
			return;  
	}	
  	else
	{  	
		IconClass::find(str.toStdString(),res);	
		searchList_->clear();		
	}	
	
	for(vector<const IconClass*>::iterator it=res.begin(); it != res.end(); it++)
	{			
		QListWidgetItem *item=new QListWidgetItem(MvQIconProvider::pixmap(*(*it),32),
				              QString::fromStdString((*it)->defaultName()));
		
		item->setData(Qt::UserRole,QString::fromStdString((*it)->name()));
		searchList_->addItem(item);
	}	
	
	searchList_->sortItems();
	
	//This is just a selection,. It will not trigger the itemactivated signal.
	if(searchList_->count() >0)
		searchList_->setCurrentRow(0);
}  

int MvQNewIconPanel::currentMode() const
{
 	return mainPanel_->currentIndex(); 
}  

void MvQNewIconPanel::setCurrentMode(int index)
{
  	if(index >=0 && index < modeBg_->buttons().count())
	{  
 		modeBg_->button(index)->setChecked(true);
  		slotChangeMode(index);
		//mainPanel_->setCurrentIndex(index);
	}	
}  

void MvQNewIconPanel::slotChangeMode(int index)
{
 	mainPanel_->setCurrentIndex(index); 
}  

void MvQNewIconPanel::slotAddToRecentIcons(QString name)
{  	
	MvQRecentIcons::add(name);
}

void MvQNewIconPanel::updateRecentList()
{
  	recentList_->clear();
  	QStringList lst=MvQRecentIcons::items();
	
  	for(int i=lst.count()-1; i >=0 ; i--)
	{
	  	const IconClass& kind=IconClass::find(lst[i].toStdString());
				
		QListWidgetItem *item=new QListWidgetItem(MvQIconProvider::pixmap(kind,32),
				              QString::fromStdString(kind.defaultName()));
		
		item->setData(Qt::UserRole,QString::fromStdString(kind.name()));
		recentList_->addItem(item);
	}	
	
	//This is just a selection,. It will not trigger the itemactivated signal.
	if(recentList_->count() >0)
		recentList_->setCurrentRow(0);
}

void MvQNewIconPanel::notifyRecentChanged()
{
  	updateRecentList();
}

void MvQNewIconPanel::paintEvent(QPaintEvent *)
 {
     QStyleOption opt;
     opt.init(this);
     QPainter p(this);
     style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
 }
 
 //Returns the active mode's current selection
 QString MvQNewIconPanel::currentSelection() const
 {
	QString s;
	
	switch(mainPanel_->currentIndex())
	{
	case 0:
		if(QListWidgetItem *item=searchList_->currentItem())
		{
			s=item->data(Qt::UserRole).toString();
		}
		break;
	case 1:
		{
			QString type=typeCb_->currentText();
			QMap<QString,MvQNewIconListWidget*>::const_iterator it=iconLists_.find(type);
			if(it != iconLists_.end())
			{
				if(QListWidgetItem *item=it.value()->currentItem())
				{
					s=item->data(Qt::UserRole).toString();
				}
			}	
		}
		break;
	case 2:
		if(QListWidgetItem *item=searchList_->currentItem())
		{
			s=item->data(Qt::UserRole).toString();
		}
		break;
	default:
		break;
	}
	
	return s;
 }	
 
void MvQNewIconPanel::keyPressEvent(QKeyEvent *event)
{
    //The search list gets the focus when arrow down or up is pressed
	if(event->key() == Qt::Key_Down || event->key() == Qt::Key_Up)
	{
		if(mainPanel_->currentIndex()==2)
		{
			if(!searchList_->hasFocus())
			{
				searchList_->setFocus();
			}
		}	
	}
	
    QWidget::keyPressEvent(event);
}
 
 
//==============================
//
// MvQNewIconDialog
//
//==============================

MvQNewIconDialog::MvQNewIconDialog(QWidget *parent) : 
   QDialog(parent)
{
	setWindowTitle(tr("Create new icon"));
	
	QVBoxLayout *vb=new QVBoxLayout;
	vb->setSpacing(0); 
	vb->setContentsMargins(1,1,1,1);	
	setLayout(vb);
	
	iconWidget_ =new MvQNewIconPanel(MvQNewIconPanel::DialogMode,this);	
	vb->addWidget(iconWidget_,1);

	// Buttonbox
	//QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
        //                              | QDialogButtonBox::Cancel);
 	
	QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | 
	                                                  QDialogButtonBox::Close);
	
	connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
    connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
		
	vb->addWidget(buttonBox);
	
	connect(iconWidget_,SIGNAL(iconSelected(QString)),
		this,SLOT(slotIconSelected(QString)));
	
	//Read settings	
	readSettings(); 
		
}

MvQNewIconDialog::~MvQNewIconDialog()
{
	writeSettings();  
}  

//When the close button is pressed
void MvQNewIconDialog::reject()
{
	QDialog::reject();
}
	
//It is called when return is pressed on the
//dialog. We pick the current selection in the active selection panel. 
void MvQNewIconDialog::accept()
{
  	selected_=iconWidget_->currentSelection();		
	if(!selected_.isEmpty())
		QDialog::accept();
	else
		QDialog::reject();
}  

//When an item is clicked or double-clicked in one of the icon lists
void MvQNewIconDialog::slotIconSelected(QString name)
{
  	selected_=name;
	QDialog::accept();
}

const IconClass& MvQNewIconDialog::selected()
{
 	return  IconClass::find(selected_.toStdString());
} 

void MvQNewIconDialog::writeSettings()
{
	QSettings settings("ECMWF","MV4-Desktop-NewIconDialog");
	
	//We have to clear it not to remember all the previous windows
	settings.clear();
	
	settings.beginGroup("main");
	settings.setValue("size",size());
	settings.setValue("currentMode",iconWidget_->currentMode());
	settings.endGroup();
}

void MvQNewIconDialog::readSettings()
{
	QSettings settings("ECMWF","MV4-Desktop-NewIconDialog");
  	
	settings.beginGroup("main");
	if(settings.contains("size"))
	{  
		resize(settings.value("size").toSize());
	}
	else
	{
	  	resize(QSize(350,500));
	}
	
	if(settings.contains("currentMode"))
	{
		iconWidget_->setCurrentMode(settings.value("currentMode").toInt());
	}
	settings.endGroup(); 	
}	












