/***************************** 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 <algorithm>

#include <QColor>
#include <QDebug>
#include <QPainter>
#include <QPixmap>

#include "MvQScmModel.h"

#include "MvScm.h"


MvQScmTableViewDelegate::MvQScmTableViewDelegate(QObject *parent) : QStyledItemDelegate(parent)
{  
}

void MvQScmTableViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
               const QModelIndex &index) const
{              
	//Paint the cell bg
	painter->fillRect(option.rect,index.data(Qt::BackgroundRole).value<QBrush>());
        
        //Paint the rest
	QStyledItemDelegate::paint(painter, option, index);
        
        // To draw a border on selected cells
       /* if(option.state & QStyle::State_Selected)
        {
            painter->save();
            QPen pen(Qt::black, 2, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin);
            int w = pen.width()/2;
            painter->setPen(pen);
            painter->drawRect(option.rect.adjusted(w,w,-w,-w));
            painter->restore();
        }*/
}

//=========================================
//
// MvQScmDataModel
//
//=========================================

MvQScmDataModel::MvQScmDataModel(QObject *parent) : QAbstractItemModel(parent)			
{
	step_=-1;
		
	rowColEdit1_=QColor("#FFE6BF");
	rowColEdit2_=QColor("#FFF2DE");
	rowCol1_=rowColEdit1_.darker(110);
	rowCol2_=rowColEdit2_.darker(110);
	editCol_=QColor(252,148,81);
}

void MvQScmDataModel::dataIsAboutToChange()
{
	beginResetModel(); 
}

void MvQScmDataModel::setStep(int step) 
{			
  	beginResetModel(); 
	
	if(step >= 0 && data_.size() > 0 && step < data_.at(0)->stepNum())
		step_=step;
	else
	  	step_=-1;
	
	endResetModel();
}

	
QModelIndex MvQScmDataModel::index( int row, int column, const QModelIndex & /*parent*/ ) const
{
	if(data_.size() == 0 || column < 0)
	{
		return QModelIndex();
	}
	
	return createIndex(row, column, (void*)0);
}

QModelIndex MvQScmDataModel::indexForChange(const MvScmProfileChange& item) const
{
  	return indexForVar(item.var(),item.step(),item.level());
}	

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

void MvQScmDataModel::reload()
{
  	//reset();
  	beginResetModel();
    endResetModel();
}	



//=========================================
//
// MvQScmSurfaceModel
//
//=========================================

MvQScmSurfaceModel::MvQScmSurfaceModel(QObject *parent)	: MvQScmDataModel(parent)
{
}

int MvQScmSurfaceModel::columnCount( const QModelIndex& /* parent */ ) const
{
	return 2;
}

int MvQScmSurfaceModel::rowCount( const QModelIndex& parent) const
{
	//Non-root
	if(parent.isValid() )
	{
		return 0;
	}
	//Root
	return static_cast<int>(data_.size());
}

QVariant MvQScmSurfaceModel::data(const QModelIndex& index, int role ) const
{	
  	if(role != Qt::DisplayRole && role != Qt::BackgroundRole && role !=  Qt::EditRole )
	{
	  	return QVariant();
	}
	
	if(index.column() != 0 && index.column() != 1)
	  	return QVariant();
	
	if( step_ == -1 ||  !index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(data_.size()))
	{
	  	return QVariant();
	}
	
	if(role == Qt::DisplayRole || role ==  Qt::EditRole)
	{	  	
		if(index.column() == 0)	  
	  		return data_.at(index.row())->data(step_).at(0);
		else
		  	return QString::fromStdString(data_.at(index.row())->units());
		
	}
	else if(role == Qt::BackgroundRole)
	{
	  	bool editable=(std::find(editableVars_.begin(),editableVars_.end(),data_.at(index.row())) != editableVars_.end())?true:false;
		
		if(editable)
		{  		
			if(data_.at(index.row())->changed(step_,0))
			{
		  		return editCol_;
			}
			else
			{
		  		return (index.row() % 2 == 0)?rowColEdit1_:rowColEdit2_;
			}			
		}
		else
		{
		  	return (index.row() % 2 == 0)?rowCol1_:rowCol2_;
		}		
	}
	  
	return QVariant();
		
}

bool MvQScmSurfaceModel::setData( const QModelIndex& index, const QVariant& value, int role)
{	
  	if( !index.isValid() || role != Qt::EditRole || index.column() !=0)
		return false;	
	
	float f=value.toFloat();
	data_.at(index.row())->fitToRange(f);
	
	MvScmProfileChange changeItem;
	
	data_.at(index.row())->setValue(step_,index.column(),f,changeItem);
	emit  dataChanged(index,index);
	emit  dataEdited(changeItem);
	return true;
}

void MvQScmSurfaceModel::setData(const vector<MvScmVar*>& data, int step) 
{			
  	beginResetModel(); 
	
	data_=data;
		
	if(step >= 0 && data_.size() > 0 && step < data_.at(0)->stepNum())
		step_=step;
	else
	  	step_=-1;
	
	endResetModel();
}

QVariant MvQScmSurfaceModel::headerData( const int section, const Qt::Orientation orient , const int role ) const
{
	if(role != Qt::DisplayRole && role != Qt::ToolTipRole)
      		  return QAbstractItemModel::headerData( section, orient, role );

 	if(orient == Qt::Vertical)	  
	{  
	  	if(section < 0 || section >= static_cast<int>(data_.size()))
			return QVariant();
	
		QString str=QString::fromStdString(data_.at(section)->name());
		//+
		//          "  [" + QString::fromStdString(data_.at(section)->units()) + "]" ;
	
		if(role == Qt::DisplayRole)
			return str;		
		else if(role == Qt::ToolTipRole)
	  		return QString::fromStdString(data_.at(section)->longName());
	}
	else if(orient == Qt::Horizontal)	  
	{  
		if(section ==0)
		  	return tr("Value");
		else if(section==1)
		  	return tr("Units");
	}
	
	return QString();
}

QModelIndex MvQScmSurfaceModel::indexForVar(MvScmVar *var, int step, int /*level*/) const
{
	if(step == step_)
	{
	  	for(unsigned int i=0; i < data_.size(); i++)
		{
			if(data_.at(i) == var)
			{
				return createIndex(i,0,(void*)0); 
			}	
		}	  			
	}
	
	return QModelIndex();
}


Qt::ItemFlags MvQScmSurfaceModel::flags ( const QModelIndex & index) const
{
	Qt::ItemFlags defaultFlags;

	defaultFlags=Qt::ItemIsEnabled |
		     Qt::ItemIsSelectable;
	
	if(index.column() ==0 && index.row() >= 0 && index.row() < static_cast<int>(data_.size()) &&
	   std::find(editableVars_.begin(),editableVars_.end(),data_.at(index.row())) != editableVars_.end())
	{  
		return defaultFlags | Qt::ItemIsEditable;
	}	
		
	return defaultFlags;
}

//=========================================
//
// MvQScmProfileModel
//
//=========================================

MvQScmProfileModel::MvQScmProfileModel(QObject *parent)	: MvQScmDataModel(parent)			
{
}

int MvQScmProfileModel::columnCount( const QModelIndex& /* parent */ ) const
{
	return data_.size();
}

int MvQScmProfileModel::rowCount( const QModelIndex& parent) const
{
	//Non-root
	if(parent.isValid() )
	{
		return 0;
	}
	//Root
	if (data_.size() >0)
	{
		return static_cast<int>(data_.at(0)->levelNum());		
	}		
	else
		return 0;	
}

QVariant MvQScmProfileModel::data( const QModelIndex& index, int role ) const
{	
  	if(role != Qt::DisplayRole && role != Qt::BackgroundRole && role !=  Qt::EditRole )
	{
	  	return QVariant();
	}
	
	if( step_ == -1 ||  !index.isValid() || index.column() < 0 || index.column() >= static_cast<int>(data_.size()))
	{
	  	return QVariant();
	}
	
	if(role == Qt::DisplayRole || role ==  Qt::EditRole)
	{	  	
		return data_.at(index.column())->data(step_).at(index.row());
	}
	else if(role == Qt::BackgroundRole)
	{
	  	bool editable=(std::find(editableVars_.begin(),editableVars_.end(),data_.at(index.column())) != editableVars_.end())?true:false;
		
		if(editable)
		{  		
			if(data_.at(index.column())->changed(step_,index.row()))
			{
		  		return editCol_;
			}
			else
			{
		  		return (index.row() % 2 == 0)?rowColEdit1_:rowColEdit2_;
			}			
		}
		else
		{
		  	return (index.row() % 2 == 0)?rowCol1_:rowCol2_;
		}		
	}
	  
	return QVariant();
		
}

bool MvQScmProfileModel::setData( const QModelIndex& index, const QVariant& value, int role)
{	
  	if( !index.isValid() || role != Qt::EditRole)
		return false;	
	
	float f=value.toFloat();
	data_.at(index.column())->fitToRange(f);
	
	MvScmProfileChange changeItem;
	
	data_.at(index.column())->setValue(step_,index.row(),f,changeItem);
	emit  dataChanged(index,index);
	emit  dataEdited(changeItem);
	return true;
}

void MvQScmProfileModel::setData(const vector<MvScmVar*>& data, int step,const vector<float>& levels, const string& levelName) 
{			
  	beginResetModel(); 
	
	data_=data;
	levels_=levels;
	levelName_=QString::fromStdString(levelName);
	
	if(step >= 0 && data_.size() > 0 && step < data_.at(0)->stepNum())
		step_=step;
	else
	  	step_=-1;
	
	endResetModel();
}

QVariant MvQScmProfileModel::headerData( const int section, const Qt::Orientation orient , const int role ) const
{
	if(role != Qt::DisplayRole && role != Qt::ToolTipRole)
      		  return QAbstractItemModel::headerData( section, orient, role );

 	if(orient == Qt::Horizontal)	  
	{  
	  	if(section < 0 || section >= static_cast<int>(data_.size()))
			return QVariant();
	
		QString str=QString::fromStdString(data_.at(section)->name()) + "\n" +
		          "[" + QString::fromStdString(data_.at(section)->units()) + "]" ;
	
		//bool editable=(std::find(editableVars_.begin(),editableVars_.end(),data_.at(section)) != editableVars_.end())?true:false;
				
		if(role == Qt::DisplayRole)
			return str;		
		else if(role == Qt::ToolTipRole)
	  		return QString::fromStdString(data_.at(section)->longName());
	  	//else if(role == Qt::BackgroundRole && editable)
	  	//	return QColor(Qt::red);
		//else if(role == Qt::DecorationRole && editable)
	  	//	return QPixmap(QString::fromUtf8(":/scmEditor/edit.svg"));
		
	}
	else if(orient == Qt::Vertical)	  
	{  
		if(section < 0 || section >= static_cast<int>(levels_.size()))
		  	return QVariant();
		
		QString str=QString::number(levels_.at(section));
		
		if(role == Qt::DisplayRole)
			return str;	
		else if(role == Qt::ToolTipRole)
		  	return levelName_ + " = " + str;		
	}
	
	return QVariant();
}

QModelIndex MvQScmProfileModel::indexForVar( MvScmVar *var, int step, int level) const
{
	if(step == step_)
	{
	  	for(unsigned int i=0; i < data_.size(); i++)
		{
			if(data_.at(i) == var)
			{
				return createIndex(level,i, (void*)0); 
			}	
		}	  			
	}
	
	return QModelIndex();
}

Qt::ItemFlags MvQScmProfileModel::flags ( const QModelIndex & index) const
{
	Qt::ItemFlags defaultFlags;

	defaultFlags=Qt::ItemIsEnabled |
		     Qt::ItemIsSelectable;
	
	if(index.column() >= 0 && index.column() < static_cast<int>(data_.size()) &&
	   std::find(editableVars_.begin(),editableVars_.end(),data_.at(index.column())) != editableVars_.end())
	{  
		return defaultFlags | Qt::ItemIsEditable;
	}	
		
	return defaultFlags;
}


MvQScmProfileFilterModel::MvQScmProfileFilterModel(QObject *parent) :  
    QSortFilterProxyModel(parent),
    showEditableOnly_(false)
{
}

void MvQScmProfileFilterModel::setShowEditableOnly(bool b)
{
  	showEditableOnly_=b;
  	//reset();
  	beginResetModel();
    endResetModel();
}

bool MvQScmProfileFilterModel::filterAcceptsColumn(int sourceColumn,
         const QModelIndex &) const
{	
  	if(showEditableOnly_)
		return sourceModel()->flags(sourceModel()->index(0,sourceColumn)) & Qt::ItemIsEditable;
	else
	  	return true;
}




