/***************************** 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 <QAction>
#include <QComboBox>
#include <QDebug>
#include <QHBoxLayout>
#include <QInputDialog>
#include <QLabel>
#include <QMessageBox>
#include <QPushButton>
#include <QSortFilterProxyModel>
#include <QToolButton>
#include <QVBoxLayout>

#include "MvKeyProfile.h"

#include "MvQKeyDialog.h"
#include "MvQKeyProfileTree.h"
#include "MvQKeyManager.h"
#include "MvQStepModel.h"
#include "MvQStepWidget.h"
#include "MvQTreeView.h"

#include "MgQPlotScene.h"
#include "MgQSceneItem.h"
#include "MgQStepMetaData.h"

class MgQPlotScene;

MvQStepWidget::MvQStepWidget(QWidget *parent) : QWidget(parent)
{
	activeScene_=0;
	
	QVBoxLayout *layout = new QVBoxLayout;
	setLayout(layout);

	//Combo box
	//We will add items + signal/slots later in "init"!
	/*QHBoxLayout *hb=new  QHBoxLayout;

	QPushButton *pbEdit=new QPushButton(tr("Edit"));
	hb->addWidget(pbEdit);
	hb->addStretch(2);

	connect(pbEdit,SIGNAL(clicked()),
		this,SLOT(slotManageKeyProfiles()));
	
f
	//Combo box for key profile selection
	QLabel *keyLabel = new QLabel(tr("Key profile:"));
	keyCombo_ = new QComboBox;
	keyLabel->setBuddy(keyCombo_);

	hb->addWidget(keyLabel);
	hb->addWidget(keyCombo_);
	
	layout->addLayout(hb);	*/
	
	//Create model
	model_= new MvQStepModel;
	

	sortModel_= new MvQKeyProfileSortFilterModel; //QSortFilterProxyModel;
        sortModel_->setSourceModel(model_);
	sortModel_->setDynamicSortFilter(true);
	//sortModel_->setFilterRole(Qt::UserRole);
	//messageSortModel_->setFilterRegExp(QRegExp("[1]"));
	//sortModel_->setFilterFixedString("1");
	//sortModel_->setFilterKeyColumn(0);
	
	//Create view	
	view_ = new MvQKeyProfileTree(model_,sortModel_);
	//We do not want to use the styel here so it is et to -1
	view_->setProperty("mvStyle",-1);

	connect(view_,SIGNAL(profileChanged(bool)),
		this,SLOT(slotProfileChanged(bool)));	

	/*view_ = new MvQTreeView;
	view_->setItemDelegate(new MvQStepDelegate());
	
	view_->setObjectName("stepTree");
	//view_->setProperty("mvStyle",0);
	view_->setSortingEnabled(true); 
	view_->sortByColumn (0,Qt::AscendingOrder); 
	//view->setAlternatingRowColors(true);
        view_->setAllColumnsShowFocus(true);
	view_->setModel(sortModel_);	
	//messageTree_->header()->setContextMenuPolicy(Qt::CustomContextMenu);
	view_->setActvatedByKeyNavigation(true);
	view_->setAcceptDrops(true);
	view_->setDragDropMode(QAbstractItemView::DropOnly);
	view_->setRootIsDecorated(false);*/

	/*view_->setDragEnabled(true);
 	view_->setAcceptDrops(true);
 	view_->setDropIndicatorShown(true);
	view_->setDragDropMode(QAbstractItemView::DragDrop);*/

	layout->addWidget(view_);

	//Buttons at the bottom
	
	QHBoxLayout *hb=new  QHBoxLayout;

	actionSave_ = new QAction(this);
        actionSave_->setObjectName(QString::fromUtf8("actionProfileSave"));
	actionSave_->setText(tr("&Save profile"));
	actionSave_->setToolTip(tr("Save key profile"));
	QIcon icon;
	icon.addPixmap(QPixmap(QString::fromUtf8(":/keyDialog/profile_save.svg")), QIcon::Normal, QIcon::Off);
 	actionSave_->setIcon(icon);
	actionSave_->setEnabled(false);

	/*QToolButton *tbNew=new QToolButton(this);
	tbNew->setIcon(QIcon(QPixmap(QString::fromUtf8(":/keyDialog/profile_new.svg"))));
	hb->addWidget(tbNew);*/

	QToolButton *tbSave=new QToolButton(this);
	//tbSave->setIcon(QIcon(QPixmap(QString::fromUtf8(":/keyDialog/profile_save.svg"))));
	//tbSave->setToolTip(tr("Save key profile"));
	tbSave->setDefaultAction(actionSave_);
	hb->addWidget(tbSave);

	//QToolButton *tbSaveAs=new QToolButton(this);
	//tbSaveAs->setIcon(QIcon(QPixmap(QString::fromUtf8(":/keyDialog/profile_saveas.svg"))));
	//hb->addWidget(tbSaveAs);

	QToolButton *tbEdit=new QToolButton(this);
	tbEdit->setIcon(QIcon(QPixmap(QString::fromUtf8(":/keyDialog/profile_manage.svg"))));
	tbEdit->setToolTip(tr("Manage key profiles"));
	hb->addWidget(tbEdit);
	hb->addStretch(2);

	//connect(actionNew, SIGNAL(triggered()), 
	//	this, SLOT(slotCreateNewProfile()));

	connect(actionSave_, SIGNAL(triggered()), 
		this, SLOT(slotSaveCurrentProfile()));

	//connect(tbSaveAs, SIGNAL(clicked()), 
	//	this, SLOT(slotSaveAsCurrentProfile()));

	connect(tbEdit,SIGNAL(clicked()),
		this,SLOT(slotManageKeyProfiles()));

	
	//Combo box
	//We will add items + signal/slots later in "init"!
	QLabel *keyLabel = new QLabel(tr("Key profile:"));
	keyCombo_ = new QComboBox;
	keyLabel->setBuddy(keyCombo_);

	hb->addWidget(keyLabel);
	hb->addWidget(keyCombo_);
	
	layout->addLayout(hb);	

	keyManager_ = new MvQKeyManager(MvQKeyManager::FrameType);
	keyManager_->loadProfiles();

	tmpProfile_=0;
}


MvQStepWidget::~MvQStepWidget()
{
	keyManager_->saveProfiles();
}

void MvQStepWidget::init(MgQPlotScene *scene,QString keyProfileName)
{
	scene_=scene;

	model_->setStepData(scene_->currentSceneItem()); //Just to have something!!!
	
	//----------------------------------
	// Initilaize the key profile list
	//---------------------------------
	
	//disconnect(keyCombo_,SIGNAL(currentIndexChanged(int)),this,SLOT(loadKeyProfile(int)));

   	int currentProfileIndex=0;
	for (unsigned int i=0; i < keyManager_->data().size();i++) 
	{
		QString str(keyManager_->data().at(i)->name().c_str());
		keyCombo_->addItem(str);
		if(keyProfileName==str)
		{
			currentProfileIndex=i;
		}
		if(keyManager_->data().at(i)->systemProfile())
		{
			keyCombo_->setItemIcon(i,QPixmap(QString::fromUtf8(":/window/metview_logo")));
		}
	}

	keyCombo_->setCurrentIndex(-1);
	
	connect(keyCombo_, SIGNAL(currentIndexChanged(int)),  
		this,SLOT(slotLoadKeyProfile(int)));

	//Select the first element	
	keyCombo_->setCurrentIndex(currentProfileIndex);

	//Get all keys
	vector<MvKeyProfile*> allKeyProf;
	keyManager_->loadAllKeys(allKeyProf);
	for(vector<MvKeyProfile*>::iterator it=allKeyProf.begin(); it != allKeyProf.end(); it++)
	{
		allKeys_ << *it;
	}
}

void MvQStepWidget::init(QString keyProfileName)
{
	//----------------------------------
	// Initilaize the key profile list
	//---------------------------------
	
	//disconnect(keyCombo_,SIGNAL(currentIndexChanged(int)),this,SLOT(loadKeyProfile(int)));

   	int currentProfileIndex=0;
	for (unsigned int i=0; i < keyManager_->data().size();i++) 
	{
		QString str(keyManager_->data().at(i)->name().c_str());
		keyCombo_->addItem(str);
		if(keyProfileName==str)
		{
			currentProfileIndex=i;
		}
		if(keyManager_->data().at(i)->systemProfile())
		{
			keyCombo_->setItemIcon(i,QPixmap(QString::fromUtf8(":/window/metview_logo")));
		}
	}

	keyCombo_->setCurrentIndex(-1);
	
	connect(keyCombo_, SIGNAL(currentIndexChanged(int)),  
		this,SLOT(slotLoadKeyProfile(int)));

	//Select the first element	
	keyCombo_->setCurrentIndex(currentProfileIndex);

	//Get all keys
	vector<MvKeyProfile*> allKeyProf;
	keyManager_->loadAllKeys(allKeyProf);
	for(vector<MvKeyProfile*>::iterator it=allKeyProf.begin(); it != allKeyProf.end(); it++)
	{
		allKeys_ << *it;
	}
}

QString MvQStepWidget::currentKeyProfile()
{
	return keyCombo_->currentText();
}

void MvQStepWidget::setCurrentKeyProfile(QString keyProfileName)
{
	if(keyCombo_->count() == 0)
		return;

	for(int i=0; i < keyCombo_->count(); i++)
	{
		if(keyCombo_->itemText(i) == keyProfileName)
		{
			keyCombo_->setCurrentIndex(i);
			return;
		}
	}
}


void MvQStepWidget::reset()
{
	//Get the current profile from the model 
	//MvKeyProfile* prof = model_->keyProfile();

	model_->setStepData(scene_->currentSceneItem()); 

	if(tmpProfile_)
		loadKeyProfile(tmpProfile_);
}

void MvQStepWidget::reset(MgQSceneItem* sceneItem)
{
	//Get the current profile from the model 
	//MvKeyProfile* prof = model_->keyProfile();
	
	activeScene_=sceneItem;	
	model_->setStepData(activeScene_); 

	if(tmpProfile_)
		loadKeyProfile(tmpProfile_);
}

void MvQStepWidget::reset(MvKeyProfile* prof)
{
	if(!prof)
		return;

	QStringList keys;
	QList<QPointF> posL;
	QList<int> posIndex;

	for(int i=0; i < static_cast<int>(prof->size()); i++)
	{
		QString s=QString::fromStdString(prof->at(i)->name());

		if(s.startsWith("MV_Value"))
		{
			float x=QString::fromStdString(prof->at(i)->metaData("x_coord")).toFloat();	
			float y=QString::fromStdString(prof->at(i)->metaData("y_coord")).toFloat();
			posL << QPointF(x,y);
			posIndex << i;
			keys << "MV_Value";
		}
		else
		{			
			keys << s;
		}
 	}

	//The model should be notified!!!!
	prof->clearKeyData();

	//Get metadata
	MgQStepMetaData *metaData=new MgQStepMetaData(keys);

	if(activeScene_)
		activeScene_->stepMetaData(metaData);
	
	for(int i=0; i< keys.count(); i++)
	{
		MvKey* kd=prof->at(i);
		int step=1;
		foreach(QString str,metaData->stepData(i))
		{
			if(str.endsWith('\n'))
			{
				str.remove(str.size()-1,1);
			}
			if(keys[i] == "MV_Frame")
			{
				str=QString::number(step);
			}
			else if(keys[i] == "MV_Index")
			{
				str=QString();
			}
			else if(keys[i] == "MV_Value")
			{
				str=QString();
			}
	
			kd->addValue(str.toStdString());

			step++;
		}
	}

	delete metaData;

#ifdef METVIEW_EXPERIMENTAL

#if 0
	if(scene_->stepNum() <= 0)
		return;
	//Get layerdata -> data values for given positions
	QMap<int,QList<QStringList> > layerData;
	for(int i=0; i < scene_->stepNum(); i++)
	{
		foreach(QPointF pp,posL)
		{
			layerData[i] << QStringList();
		}
	}

	scene_->collectLayerData(posL,layerData,false);
	
	for(int i=0; i< posIndex.count(); i++)
	{
		MvKey* kd=prof->at(posIndex[i]);	

		for(int step=0; step < scene_->stepNum(); step++)
		{
			QString t;
			foreach(QString str,layerData[step][i])
			{
				if(str.endsWith('\n'))
				{
					str.remove(str.size()-1,1);
				}
				t+=str + '\n';			
			}
			if(t.endsWith('\n'))
				t.remove(t.size()-1,1);

			kd->setValue(step,t.toStdString());
		}
	}
	
#endif

#endif

}



void MvQStepWidget::slotLoadKeyProfile(int index)
{
	//qDebug() << "loadKeyProfile " << index  << " " << keyManager_->data().size();

	saveProfileBeforeAction(false);

	if(index != -1 && keyManager_->isEmpty() == false) 
	{
		loadKeyProfile(keyManager_->data().at(index));
		//emit keyProfileLoaded(keyManager_->at(index));	
	}
}

void MvQStepWidget::loadKeyProfile(MvKeyProfile *prof)
{	
	if(!prof)
		return;

	//Get the current profile from the model (this will be the previous)
	//MvKeyProfile* prevProfile = model_->keyProfile();

	model_->keyProfileIsAboutToChange();

	//Create a tmp profile with contents of the current profile
	if(prof != tmpProfile_)
	{
		if(tmpProfile_)
		{
			delete tmpProfile_;
		}

		tmpProfile_= new MvKeyProfile(*prof);
	}
	else
	{
		tmpProfile_->clearKeyData();
	}
	
	//Update grib metadata with the new key profile
	reset(tmpProfile_);

	//---------------------
	// Update message tree
	//---------------------
	
	model_->setKeyProfile(tmpProfile_);

	for(int i=0;i < model_->columnCount()-1; i++)
	{ 
		view_->resizeColumnToContents(i);
	}

	view_->setCurrentIndex(sortModel_->index(0,0));

	if(prof->systemProfile())
	{
		view_->setEditable(false);
	}
	else
	{
		view_->setEditable(true);
	}

	emit keyProfileChanged(tmpProfile_);
}


void MvQStepWidget::slotProfileChanged(bool reload)
{
	actionSave_->setEnabled(true);
	if(reload)
	{
		loadKeyProfile(tmpProfile_);
	}
	else
	{
		emit keyProfileChanged(tmpProfile_); 
	}

	//keyManager_->saveProfiles();
}

void MvQStepWidget::slotSaveCurrentProfile()
{
	if(!tmpProfile_)
		return;

	keyManager_->changeProfile(tmpProfile_->name(),tmpProfile_);
	actionSave_->setEnabled(false);
}

void MvQStepWidget::slotSaveAsCurrentProfile()
{
	if(!tmpProfile_)
		return;

	bool ok;
     	QString text = QInputDialog::getText(0, tr("Duplicate profile"),
                                          tr("New profile name:"), QLineEdit::Normal,
                                          "", &ok);
	if(ok && !text.isEmpty())
        { 	
		keyManager_->addProfile(text.toStdString(),tmpProfile_);
		keyCombo_->addItem(text);
		actionSave_->setEnabled(false);
	}
}

int MvQStepWidget::stepNum()
{
	if(!activeScene_)
	  	return -1;
	
	return activeScene_->stepNum();
}  

void MvQStepWidget::updateStepForScenes(const QList<MgQSceneItem*>& scenesToStep)
{
	if(!activeScene_)
	  	return;
	
	int step=activeScene_->currentStep();
	
	foreach(MgQSceneItem* item,scenesToStep)
	{
	  	if(item != activeScene_ && item->stepNum() >0)
		{
			int current=step;
			if(current > item->stepNum()-1)
				current=current % item->stepNum();
			
			//We just load it and do not render it into the pixmap cache!!!
			item->setCurrentStep(current,false); 	
		}
	}	  
}  

int MvQStepWidget::setCurrentStep(int sortedStep,const QList<MgQSceneItem*>& scenesToStep)
{
	if(!activeScene_ || sortedStep <0 || sortedStep >= activeScene_->stepNum())
	{
	  	return -1;
	}
	
	//Get the original (unsorted) model index for the step num
	QModelIndex index=sortModel_->mapToSource(sortModel_->index(sortedStep,0)); 
	
	int step=index.row();
		
	bool oriCacheState=activeScene_->stepCached(step);
	activeScene_->setCurrentStep(step);
	if(oriCacheState != activeScene_->stepCached(step))
	{
		emit stepCacheStateChanged();
	}
		  
	foreach(MgQSceneItem* item,scenesToStep)
	{
	  	if(item != activeScene_ && item->stepNum() >0)
		{
			int current=step;
			if(current > item->stepNum()-1)
				current=current % item->stepNum();
					  
			item->setCurrentStep(current); 	
		}
	}	
	
	return sortedStep; //!!!!
}

int MvQStepWidget::currentStep() 
{
	if(!activeScene_)
	  	return -1;
	
	int currentStep=activeScene_->currentStep();
  	QModelIndex index=sortModel_->mapFromSource(model_->index(currentStep,0)); 
	int sortedStep=index.row();
	return sortedStep;
}

void MvQStepWidget::setViewToCurrentStep()
{	
	if(!activeScene_)
	  	return;
	
	int currentStep=activeScene_->currentStep();
	
	QModelIndex src=model_->index(currentStep,0);
	QModelIndex index=sortModel_->mapFromSource(model_->index(currentStep,0)); 
	QModelIndex current=view_->currentIndex();

	//qDebug() << model_->currentStep() << src << index;
	if(index.row() != current.row())
	{  
	 	view_->setCurrentIndex(index);

	}
}	

void MvQStepWidget::stepDataIsAboutToChange()
{
	model_->stepDataIsAboutToChange();
}

//==============================
// Key manager
//==============================

void MvQStepWidget::slotManageKeyProfiles()
{	
	if(saveProfileBeforeAction(false) == false)
		return;
	

	//Create a tmp copy of the whole manager (no data
	//values, just key descriptions)
	MvQKeyManager *tmpManager=keyManager_->clone();

	MvQKeyDialog profDialog(tr("Metview - Frame Key Profile Manager"),MvQKeyManager::FrameType,tmpManager,keyCombo_->currentIndex(),allKeys_);

	if(profDialog.exec()  == QDialog::Accepted)
	{
		//Save the current profile name
		string currentProfName=keyCombo_->currentText().toStdString(); 
		
		model_->keyProfileIsAboutToChange();
		model_->setKeyProfile(0);

		keyManager_->update(tmpManager);
		keyManager_->saveProfiles();

		disconnect(keyCombo_, SIGNAL(currentIndexChanged(int)),0,0);

		//Clear the profile list
		keyCombo_->clear();

		//resetMessageHeader();

		int i=0;
		int index=-1;
		for (vector<MvKeyProfile*>::const_iterator it=keyManager_->data().begin(); it != keyManager_->data().end(); it++) 
		{
			keyCombo_->addItem(QString((*it)->name().c_str() ));
			if((*it)->name()== currentProfName)
			{
				index=i;
			}
			if((*it)->systemProfile())
			{
				keyCombo_->setItemIcon(i,QPixmap(QString::fromUtf8(":/window/metview_logo")));
			}
			i++;
		}

		keyCombo_->setCurrentIndex(-1);

		connect(keyCombo_, SIGNAL(currentIndexChanged(int)),  
			this,SLOT(slotLoadKeyProfile(int)));

		if(index != -1)
		{
			keyCombo_->setCurrentIndex(index);
		}
		else
		{
			keyCombo_->setCurrentIndex(0);
		}
	}

	delete tmpManager;
}


bool MvQStepWidget::saveProfileBeforeAction(bool offerCancel)
{
	if(actionSave_->isEnabled() == false)
		return true;
	
	QString str=tr("The current key profile as been modified.<br>Do you want to save your changes or discard them?");

 	QMessageBox msgBox;
	msgBox.setWindowTitle(tr("Save changes to current profile"));
	msgBox.setText(str);
	msgBox.setIcon(QMessageBox::Warning);
 	if(offerCancel)
	{
 		msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
	}
	else
	{
		msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard);
	}

	msgBox.setDefaultButton(QMessageBox::Save);
	int ret=msgBox.exec();

	switch (ret) 
	{
   	case QMessageBox::Save:
		slotSaveCurrentProfile();				
     		break;
   	case QMessageBox::Cancel:
		return false;	
       		break;
   	default:
      	 	break;
	}

	actionSave_->setEnabled(false);

	return true;
}

