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

#include <QDebug>
#include <QDir>
#include <QDragEnterEvent>
#include <QDragMoveEvent>
#include <QHBoxLayout>
#include <QMenu>
#include <QSignalMapper>
#include <QStyleOption>
#include <QPainter>

#include "MvQBookmarks.h"
#include "MvQContextMenu.h"
#include "MvQDropTarget.h"
#include "MvQFileBrowser.h"
#include "MvQFolderViewBase.h"
#include "MvQIconProvider.h"

#include "Folder.h"
#include "IconClass.h"

QList<MvQContextItem*> MvQPathWidget::cmTbItems_;
QList<MvQContextItem*> MvQPathWidget::cmMenuItems_;

//=============================================================
//
//  MvQPathButton
//
//=============================================================

MvQPathButton::MvQPathButton(QWidget *parent) : QToolButton(parent), menu_(0)
{
  	setAcceptDrops(true);
}

void MvQPathButton::checkDropTarget(QDropEvent *event)
{  
	if(!event->mimeData()->hasFormat("metview/icon"))
	{	
		removeDropTarget();			
	}
	
	QString s=text();
	
	if(!s.isEmpty())
	{	
		//Folder *f=Folder::folder(s.toStdString(),false);  		
		//if(f && !f->locked())
		//{
	  		Qt::DropAction dropAction=event->proposedAction();
			MvQDropTarget::Instance()->reset(s,(dropAction == Qt::MoveAction));	
						
			if(window())
			{  
				MvQDropTarget::Instance()->move(mapToGlobal(event->pos())+QPoint(20,20));
			}
			return;
		//}
	}
	
	removeDropTarget();	
}	  

void MvQPathButton::removeDropTarget() 
{  
  	MvQDropTarget::Instance()->hide();
} 

void MvQPathButton::dragEnterEvent(QDragEnterEvent *event)
{		
	if(event->source() &&
	   (event->proposedAction() == Qt::CopyAction ||
	    event->proposedAction() == Qt::MoveAction))
	{
		event->accept();
		
	}
	else  
		event->ignore();
}

void MvQPathButton::dragMoveEvent(QDragMoveEvent *event)
{
	if(event->source() &&
	   (event->proposedAction() == Qt::CopyAction ||
	    event->proposedAction() == Qt::MoveAction))
	{		
		checkDropTarget(event);
		event->accept();
	}
	else
	{
	  	removeDropTarget();
	  	event->ignore();
	}	
}

void MvQPathButton::dragLeaveEvent(QDragLeaveEvent *event)
{
	removeDropTarget();
	event->accept();
}

void MvQPathButton::dropEvent(QDropEvent *event)
{
	removeDropTarget();
	
	if(!event->source())
	{
		event->ignore();
		return;
	}	
	
	if(event->proposedAction() != Qt::CopyAction &&
	   event->proposedAction() != Qt::MoveAction)
	{
		event->ignore();
		return;
	}	
		
	emit iconDropped(event);
}

//=============================================================
//
//  MvQPathWidget
//
//=============================================================

MvQPathWidget::MvQPathWidget(QWidget *parent) : 
  QWidget(parent), 
  actionReload_(0), 
  reloadTb_(0), 
  bookmarkTb_(0)
{
	layout_=new QHBoxLayout(this);
	layout_->setSpacing(0);
	layout_->setContentsMargins(6,0,6,0); 
	setLayout(layout_);
	
	setProperty("path","1");
	
	smp_=new QSignalMapper(this);
	
	connect(smp_,SIGNAL(mapped(int)),
		this,SIGNAL(pathClicked(int)));
		
	connect(this,SIGNAL(pathClicked(int)),
		this,SLOT(slotChangeDir(int)));
		
}  

void MvQPathWidget::slotContextMenu(const QPoint& pos)
{
	static MvQContextItemSet cmItems("Breadcrumbs");  
	
	QString path;
	QMenu *menu=0;
	
	QToolButton *tb=static_cast<QToolButton*>(QObject::sender());	
	if(tb)
	{
	  	path=getPath(tb);
	}
	else 
	{	menu=static_cast<QMenu*>(QObject::sender());
		if(menu)
		{
		  	QAction *ac=menu->actionAt(pos);
			path=getPath(ac);
		}
	}	
		  		  	
	if((tb || menu) && !path.isEmpty())
	{
		QString selection;
		if(tb)		  
			selection=MvQContextMenu::instance()->exec(cmItems.icon(),tb->mapToGlobal(pos),tb);  		
		//else
		//  	selection=MvQContextMenu::instance()->exec(cmMenuItems_,menu->mapToGlobal(pos),menu);  	
		  
		if(!selection.isEmpty()) 
		{
		  	emit commandRequested(selection,path);
		}	
	}	
}	

void MvQPathWidget::clearLayout()
{
  	QLayoutItem *item;
 	while( (item = layout_->takeAt(0)) != 0) 
	{
     		QWidget *w=item->widget();
		if(w)
		{  
		  	layout_->removeWidget(w);
		  	//delete w;
		}
		delete item;
 	}
}

void MvQPathWidget::setReloadAction(QAction* ac)
{
  	actionReload_=ac;
}	
 
void MvQPathWidget::setPath(QString path)
{
	setPath(Folder::folder(path.toStdString(),false));
}	

void MvQPathWidget::setPath(Folder *folder)
{
	//Clear the layout (widgets are not deleted in this step!)
	clearLayout();
  	path_.clear();
  	
	if(!folder)
	  	return;
		
	path_=QString::fromStdString(folder->fullName());
		
	QList<Folder*> lst;
	lst << folder;
	Folder *f=folder;
	while(f->parent())
	{
	  	f=f->parent();
		lst.prepend(f);
	}	
	
	//-----------------------------------------------------------
	//Try to reuse the current items and delete the unneeded ones
	//-----------------------------------------------------------
	
	//Find out how many items can be reused. 
	//firstIndex: the first original item that differs from the current one.  
	int lastIndex=-1;
	for(int i=0; i <  lst.count() && i < items_.count(); i++)
	{  
		if(QString::fromStdString(lst.at(i)->fullName()) == items_[i]->fullName_)
		{
			lastIndex=i;
		}
		else
		  	break;
	}	
	
	//Delete unused items (if there are any)
	int num=items_.count();
	for(int i=lastIndex+1; i <  num; i++)
	{  		
		MvQPathWidgetItem *item=items_.back();
	  	items_.removeLast();
		delete item;
	}	
	
	for(int i=lastIndex+1; i < lst.count(); i++)
	{
	  	Folder *f=lst.at(i);
	  
		MvQPathWidgetItem *item = new MvQPathWidgetItem(QString::fromStdString(f->name()),
								QString::fromStdString(f->fullName()));		
	  	items_ << item;
	  	 		
	  	MvQPathButton *tb;
		
		//---------------------------------------
		// Dir name
		//---------------------------------------
		
		tb=new MvQPathButton(this);
		item->nameTb_=tb;		
		
		if(item->fullName_ == "/")
		{
		  	tb->setToolButtonStyle(Qt::ToolButtonIconOnly);
			tb->setIconSize(QSize(16,16));
			tb->setIcon(MvQIconProvider::pixmap(f,16));
			tb->setObjectName("pathIconTb");
		}	
		else
		{
		  	if(f->locked())
			{  
		  		tb->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
		  		tb->setIconSize(QSize(12,12));
				tb->setIcon(MvQIconProvider::lockPixmap(12));				
			}
			else
			{  
		  		tb->setToolButtonStyle(Qt::ToolButtonTextOnly);
			}
			tb->setText(item->name_);
			tb->setObjectName("pathNameTb");
			
			if(f->isLink())
			  	tb->setStyleSheet("QToolButton {font-style: italic;}");
		}  	
			
		//tb->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
		tb->setAutoRaise(true);		  	
		
		connect(tb,SIGNAL(clicked(bool)),
			smp_,SLOT(map()));				
			
		//Context menu 
    		tb->setContextMenuPolicy(Qt::CustomContextMenu);
	
		connect(tb,SIGNAL(customContextMenuRequested(const QPoint &)),
                	this, SLOT(slotContextMenu(const QPoint &)));	  		
		
		smp_->setMapping(tb,i);		
		
		connect(tb,SIGNAL(iconDropped(QDropEvent*)),
			this,SLOT(slotIconDropped(QDropEvent*)));
		
	  	//---------------------------------------
		//Menu with the folders in the given dir	
		//---------------------------------------
		
		tb=new MvQPathButton(this);
		item->menuTb_=tb;
		
		//tb->setArrowType(Qt::RightArrow);
		tb->setAutoRaise(true);
		//tb->setIconSize(QSize(10,10));
		tb->setPopupMode(QToolButton::InstantPopup);
		tb->setObjectName("pathMenuTb");
		
		connect(tb,SIGNAL(clicked()),
			this,SLOT(slotShowDirMenu()));
	
		QMenu *mn=createDirMenu(i,f,tb);
		//tb->addMenu(mn); 
		tb->assignMenu(mn);
	}
	
	//Add items to layout 
	for(int i=0; i <  items_.count(); i++)
	{
		layout_->addWidget(items_.at(i)->nameTb_);
		layout_->addWidget(items_.at(i)->menuTb_);		
	}
	
	//Set the text in the last item bold
	for(int i=0; i <  items_.count(); i++)
	{
		QString st=items_.at(i)->nameTb_->styleSheet();
		if(i== items_.count()-1)
		 	st+="QToolButton {font-weight: bold;}";
		else
		  	st+="QToolButton {font-weight: normal;}";
		
		items_.at(i)->nameTb_->setStyleSheet(st);
	}	
		
	/*items_.at(items_.count()-1)->nameTb_->setStyleSheet("QToolButton {font-weight: bold;}");

	for(int i=0; i <  items_.count()-1; i++)
	{
		items_.at(i)->nameTb_->setStyleSheet("QToolButton {font-weight: normal;}");
	}*/  
	 
	layout_->addStretch(1);	
	
	//Bookmarks
	if(!bookmarkTb_)
	{
	  	bookmarkTb_=new QToolButton(this);
		bookmarkTb_->setAutoRaise(true);
		//bookmarkTb_->setIconSize(QSize(20,20));
		bookmarkTb_->setObjectName("pathIconTb");
		
		connect(bookmarkTb_,SIGNAL(clicked()),
			this,SLOT(slotBookmark()));
	}	
	
	updateBookmarkStatus();
	
	layout_->addWidget(bookmarkTb_);
	
	//Reload
	if(actionReload_)
	{
	  	if(!reloadTb_)
		{  	
		  	reloadTb_=new QToolButton(this);
			reloadTb_->setDefaultAction(actionReload_);
			reloadTb_->setAutoRaise(true);
			//reloadTb_->setIconSize(QSize(20,20));
			reloadTb_->setObjectName("pathIconTb");	
		}
		layout_->addWidget(reloadTb_);
	}
	
	
}  

QMenu* MvQPathWidget::createDirMenu(int index,Folder* folder,QWidget *parent)
{
	if(index >=0 && index < items_.count())
	{ 		
	  	QMenu *dirMenu=new QMenu(parent);
	  	
		for(map<string,IconObjectH>::const_iterator it=folder->kids().begin(); it!= folder->kids().end(); it++)
		{
		  	if(it->second->visible() &&  it->second->iconClass().type() == "Folder")
			{
				QAction *ac=dirMenu->addAction(QString::fromStdString(it->first));
				ac->setData(index);
			}
		}
		
		connect(dirMenu,SIGNAL(triggered(QAction*)),
			this,SLOT(slotChangeDir(QAction*)));
		
		dirMenu->setContextMenuPolicy(Qt::CustomContextMenu);
		
		connect(dirMenu,SIGNAL(customContextMenuRequested(const QPoint &)),
                        this, SLOT(slotContextMenu(const QPoint &)));
		
		return dirMenu;	
	}
	
	return 0;
}

void MvQPathWidget::slotShowDirMenu()
{
	if(MvQPathButton *tb=static_cast<MvQPathButton*>(sender()))
	{
	  	tb->assignedMenu()->popup(mapToGlobal(tb->pos()));
	}		
}

void MvQPathWidget::slotChangeDir(int index)
{
	if(index >=0 && index < items_.count()-1)
	{
	  	QString path=items_.at(index)->fullName_;
	  		 
	  	//QString path;
		//for(int i=0; i <= index; i++)
		//	path+="/"+items_[i].name_;
		
		qDebug() << path;
				
		//setPath(path);
		
		emit dirChanged(path);
				
		setPath(path);
	}
}

void MvQPathWidget::slotChangeDir(QAction *ac)
{
	QString path=getPath(ac);
	
	if(!path.isEmpty())
	{
	  	emit dirChanged(path); 		
		setPath(path);
	}
	
	/*
	if (!ac) return;
	
	QVariant var=ac->data();
	if(var.isNull())  return;
	
	int index=var.toInt();
  
  	if(index >=0 && index < items_.count())
	{
		QString path=items_.at(index)->fullName_;
			  
	  	//QString path;
		//for(int i=0; i < index; i++)
		//	path+="/"+items_[i].name_;
		
		path+="/" + ac->text();
		
		qDebug() << path;
		
		emit dirChanged(path); 
		
		setPath(path);
	}*/
}

QString MvQPathWidget::getPath(QToolButton *tb)
{
	foreach(MvQPathWidgetItem *item,items_)
	{
	  	if(item->nameTb_ == tb)
		{
	  		return item->fullName_;
		}
	}
	
	return QString();
}

QString MvQPathWidget::getPath(QAction *ac)
{	
	if (!ac) return QString();
	
	QVariant var=ac->data();
	if(var.isNull())  return QString();
	
	int index=var.toInt();
  
  	if(index >=0 && index < items_.count())
	{
		return items_.at(index)->fullName_ + "/" + ac->text();;
	}
	
	return QString();
}
 
void MvQPathWidget::paintEvent(QPaintEvent *)
 {
     QStyleOption opt;
     opt.init(this);
     QPainter p(this);
     style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
 }
 
void MvQPathWidget::slotIconDropped(QDropEvent* event)
{
  	if(QToolButton* tb=static_cast<QToolButton*>(sender()))
	{
	 	QString p=getPath(tb);
		if(Folder* f=Folder::folder(p.toStdString(),false))
		{
		  	MvQFolderViewBase::dropToFolder(f,event);
		}
	}
}	
 
//---------------------- 
// Bookmarks 
//----------------------

void MvQPathWidget::slotBookmark()
{
  	if(MvQBookmarks::isBookmark(path_))
	{
	  	MvQBookmarks::editItem(path_);
	}
	else
	{
	  	MvQBookmarks::addItem(path_); 		
	}
	
	updateBookmarkStatus();	
}  
 
void MvQPathWidget::updateBookmarkStatus()
{
 	if(MvQBookmarks::isBookmark(path_))
	{
	  	bookmarkTb_->setIcon(QPixmap(":/desktop/bookmark.svg"));
	        bookmarkTb_->setToolTip(tr("Edit this bookmark"));	
	}
	else
	{
	  	bookmarkTb_->setIcon(QPixmap(":/desktop/bookmark_empty.svg"));
		bookmarkTb_->setToolTip(tr("Bookmark current folder"));	
	}	
}	
