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

 Copyright 2013 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 "MvQIconHolder.h"

#include <QDebug>
#include <QDropEvent>
#include <QLabel>
#include <QVBoxLayout>

#include "MvQContextMenu.h"
#include "MvQFolderModel.h"
#include "MvQIconMimeData.h"
#include "MvQIconProvider.h"

#include "Command.h"
#include "IconClass.h"
#include "IconFactory.h"
#include "IconObject.h"
#include "Parameter.h"
#include "RequestPanelItem.h"

//====================================
//
//	MvQIconHolderModel
//
//====================================

MvQIconHolderModel::MvQIconHolderModel(const vector<string>& classes,QObject *parent) : 
     QAbstractItemModel(parent),
     classes_(classes)
{
  
}  

void MvQIconHolderModel::setIcons(const vector<IconObjectH>& objects)
{	
	beginResetModel();
	
	//Cleaning
	foreach(IconObjectH actObj, icons_)
	{	
	  	if(actObj &&  actObj->isEmbedded() &&
		   std::find(objects.begin(),objects.end(),actObj) == objects.end())
		{
	  		actObj->destroy();
		}
	}
	
	icons_.clear();
	
	for(unsigned int i=0; i < objects.size(); i++)
	{
	  	icons_ << objects.at(i);	
	}
			
	endResetModel();	
}

void MvQIconHolderModel::clearIcons(const vector<IconObjectH>& objects)
{	
	beginResetModel();
	
	//Cleaning
	foreach(IconObjectH actObj, icons_)
	{	
	  	if(actObj &&  actObj->isEmbedded() &&
		   (std::find(objects.begin(),objects.end(),actObj) == objects.end()))
		{
	  		actObj->destroy();
		}
	}
	
	icons_.clear();
				
	endResetModel();	
}

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


int MvQIconHolderModel::rowCount( const QModelIndex& index) const
{
	if (!index.isValid() )
	{
	  	return  icons_.count();
	}
	else
	{
		return  0;
	}
}

QVariant MvQIconHolderModel::data( const QModelIndex& index, int role ) const
{
  	if (role != Qt::DisplayRole && role != Qt::DecorationRole  && 
	    role != Qt::ForegroundRole &&  role != Qt::UserRole  &&  role != Qt::FontRole )
	{  	
		return QVariant();
	}
	
  	if(!index.isValid())
		return QVariant();
	
	IconObject *obj=0;
	if(index.row() >=0 && index.row() < icons_.count())
		obj=icons_[index.row()];  
	
	if(!obj)
	  	return QVariant();
	
	switch(role)
	{
		case Qt::DecorationRole:  			
		{
		  	return MvQIconProvider::pixmap(obj,32,true);
		}		
		case Qt::DisplayRole:
	  		return QString::fromStdString(obj->name());
		default:
		  	break;
	}
	
	return QVariant();	  
}

QModelIndex MvQIconHolderModel::index( int row, int column, const QModelIndex & /*parent */) const
{
	return createIndex(row,column,(void*)0);
}


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

IconObject* MvQIconHolderModel::iconObject(const QModelIndex& index)
{
	IconObject *obj=0;
	if(index.row() >=0 && index.row() < icons_.count())
		obj=icons_[index.row()];  
	
	return obj;
}  

void MvQIconHolderModel::add(IconObjectH obj)
{	
	if(icons_.contains(obj))
	  	return;

	beginResetModel();
	icons_ << obj;
	endResetModel();
}
		
void MvQIconHolderModel::remove(IconObjectH obj)
{
	if(!obj) return;
	beginResetModel();	
	icons_.removeAll(obj);
	if(obj->isEmbedded())
		obj->toWastebasket();
	endResetModel();		
}

bool MvQIconHolderModel::accept(IconObjectH obj)
{	
	const IconClass& ic = obj->iconClass();
	for ( vector<string>::iterator it =  classes_.begin(); it != classes_.end(); ++it)
	{	
		if( ic.canBecome(IconClass::find(*it)) )   
			return true;			
	}	
	return classes_.size() == 0;	
}

void MvQIconHolderModel::iconObjects(vector<IconObjectH>& vals)
{
	for(int i=0; i < icons_.count(); i++)
		vals.push_back(icons_[i]);
}

//====================================
//
//	MvQIconHolder
//
//====================================

MvQIconHolderView::MvQIconHolderView(MvQIconHolderModel* model,RequestPanelItem *owner,QWidget *parent) : 
  QListView(parent),
  model_(model),
  owner_(owner)
{
  	setViewMode(QListView::IconMode);
	setFlow(QListView::LeftToRight);
	setMovement(QListView::Snap);
	setWrapping(false);
	setResizeMode(QListView::Adjust);
	setSpacing(5);
	
	QFont font;
	QFontMetrics fm(font);
	setMaximumHeight(fm.size(Qt::TextExpandTabs,"A").height()+32+10+5+10);
					
	//Double click
	connect(this,SIGNAL(doubleClicked(const QModelIndex&)),
		this,SLOT(slotDoubleClickItem(const QModelIndex)));
				
	setContextMenuPolicy(Qt::CustomContextMenu);
	
	//Context menu 
    	connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
                this, SLOT(slotContextMenu(const QPoint &)));
				
	setMouseTracking(true);
	setAcceptDrops(true);
	setDragEnabled(true);
	setDropIndicatorShown(true);
	setDragDropMode(QAbstractItemView::DragDrop);
	//setDragDropMode(QAbstractItemView::DropOnly);
	
	setModel(model);
}	

MvQIconHolderView::~MvQIconHolderView()
{
	qDebug() << "deleted ---> MvQIconHolderView";
}


void  MvQIconHolderView::slotDoubleClickItem(const QModelIndex& index)
{	 	
    	if(index.isValid()) 
	{
		if(IconObjectH obj=model_->iconObject(index))
		{
			QString method=QString::fromStdString(obj->iconClass().doubleClickMethod()).toLower(); 
			if(obj->isFolder())
			{
			  	return;
			}
		  	else if(!method.isEmpty())
			{
		  		obj->command(method.toStdString());
			}  
			else 
			{
		  		obj->doubleClick();
			}
		}
	}			
}


void MvQIconHolderView::slotContextMenu(const QPoint &pos)
{
  	static MvQContextItemSet cmItems("IconHolderView");
  	
  	QModelIndex index=indexAt(pos);
    	if(index.isValid()) 
	{
		IconObjectH obj=model_->iconObject(index);
	  	QString selected=MvQContextMenu::instance()->exec(cmItems.icon(),obj,mapToGlobal(pos),this);
		if(!selected.isEmpty())
		{  	
			command(selected,obj); 	
		}
	}	
}

void MvQIconHolderView::command(QString name,IconObjectH obj)
{
	//Other actions
	if(Command::isValid(name.toStdString()))
	{
		  obj->command(name.toStdString());
	}
	else if(name == "remove")
	{
		model_->remove(obj);
		emit edited();		  		  
	}  
}

void MvQIconHolderView::dragEnterEvent(QDragEnterEvent *event)
{
        qDebug() << "dragenter" << event <<  event->proposedAction() << event->source();

        if((event->proposedAction() == Qt::CopyAction ||
            event->proposedAction() == Qt::MoveAction))
        {
                qDebug() << "dragenter ok";
                event->accept();
        } 
        else
	{  
        	event->ignore();
	}	
}

void MvQIconHolderView::dragMoveEvent(QDragMoveEvent *event)
{
        qDebug() << "dragmove" << event <<  event->proposedAction() << event->source();

        if((event->proposedAction() == Qt::CopyAction ||
            event->proposedAction() == Qt::MoveAction))
        {
                qDebug() << "dragmove ok";
                event->accept();
        }
        else
	{  
		event->ignore();
	}	
}

void MvQIconHolderView::dropEvent(QDropEvent *event)
{
        qDebug() << "drop" <<  event->mimeData()->formats(); 

        if(event->proposedAction() != Qt::CopyAction &&
           event->proposedAction() != Qt::MoveAction)
	{
	  	event->ignore();
		return;
	}	
   
        if(event->mimeData()->hasFormat("metview/icon"))
        {                  
                const MvQIconMimeData* mimeData=qobject_cast<const MvQIconMimeData*>(event->mimeData());
				
		if(!mimeData)
		{
			event->ignore();
			return;
		}
		
		MvQFolderModel *dropModel=mimeData->model();
		if(!dropModel)
		{
		  	event->ignore();
			return;	
		}
		
		bool hasObj=false;
		foreach(IconObject* dropObj, mimeData->objects())
		{					  
				
		  	if(!dropObj || !model_->accept(dropObj))
			{
				event->ignore();
				return;
			}
		  
		  	IconObject *obj=dropObj;
		  	  
		  	//If drop came from a helper
			if(dropModel &&  mimeData->fromHelper())
			{
				string param=owner_->parameter().beautifiedName();
				obj=dropObj->clone(owner_->currentObject()->embeddedFolder(param));
			}
					
			if(obj)
			{
				hasObj=true;
				model_->add(obj); 
			}
						  
		}
		
		if(hasObj)
		{
		  	event->accept();
			emit edited();
			return;
		}
        }
        
        event->ignore();
}
