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

 Copyright 2014 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 <QDebug>

#include "MvQProcModel.h"
#include "MvQPixmapCache.h"

#include "MvProcNode.h"


MvQProcModel::MvQProcModel(QObject *parent) : 
      QAbstractItemModel(parent),
      rootItem_(0)
{
	pm_=new MvQPixmapCache(QPixmap());	
  
  	cpuYellow_=QColor(255,255,0);
	cpuOrange_=QColor(255,188,46);
	cpuRed_=QColor(255,102,102);
	textGrey_=QColor(100,100,100);
}

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


void MvQProcModel::setData(MvProcNode* data)
{	
	beginResetModel();
	rootItem_=data;
	rootItem_->setObserver(this);
	endResetModel();
}


void MvQProcModel::updateData()
{	
	//beginResetModel();
	endResetModel();
}

int MvQProcModel::columnCount( const QModelIndex& /* parent */ ) const
{
   	 return 5;
}

int MvQProcModel::rowCount( const QModelIndex& parent) const
{
	if(!rootItem_)
		return 0;

	MvProcNode* parentItem=itemForIndex(parent);
	return parentItem ? parentItem->childrenCount() : 0;
}


QVariant MvQProcModel::data( const QModelIndex& index, int role ) const
{
	if( !index.isValid() || 
	   (role != Qt::DisplayRole && role != Qt::BackgroundRole &&
	    role != Qt::DecorationRole && role != Qt::TextAlignmentRole && role != Qt::ForegroundRole ))
        {			
		return QVariant();
	}
	
	MvProcNode *item = itemForIndex(index);
	if(!item)
		return QVariant();
	
	MvProcStat *st=item->stats();
	if(!st && index.column() > 0)
		return QVariant();		
 
	if(role == Qt::DisplayRole)
	{  
		switch (index.column()) 
		{
     		case 0: return QString::fromStdString(item->niceName());
		case 1: return (st->cpu() > 1)?(QString::number(st->cpu()) + " %"):"< 1%";
		case 2: return QString::fromStdString(st->vmRss());
		case 3: return QString::fromStdString(st->elapsedTime());
		case 4: return "   " + QString::number(item->pid());	
		default: return QString();
    		}
	}
	else if(role ==  Qt::DecorationRole && index.column() == 0)
	{
	  	if(MvProcRequest *req=item->procRequest())
		{
		  	return pm_->pixmap(QString::fromStdString(req->className()));
		}
		else
		  	return QVariant();
	}		
	else if(role == Qt::BackgroundRole && index.column() == 1 )
	{  
		int cpu=st->cpu();
		if(cpu > 75)
		  	return cpuRed_;
		else if(cpu > 40)
		  	return cpuOrange_;		
	 	else if(cpu > 25)
		  	return cpuYellow_;
		else
		  	return QVariant();
	}
	else if(role == Qt::TextAlignmentRole)
	{
	  	if(index.column() == 0  || index.column() == 4)
		  	return QVariant();
		else
		  	return Qt::AlignRight;
	}
	else if(role == Qt::ForegroundRole)
	{
	  	if((index.column() == 1 && st->cpu() < 1) || index.column() == 4 )
		   	return textGrey_;
	}
	return QVariant();
} 


QVariant MvQProcModel::headerData( const int section, const Qt::Orientation orient , const int role ) const
{
	if ( orient != Qt::Horizontal)
      		  return QAbstractItemModel::headerData( section, orient, role );

   	if(role == Qt::DisplayRole)
	{
		switch ( section ) 
		{
  		case 0: return QObject::tr("Name");
		case 1: return QObject::tr("CPU %");
		case 2: return QObject::tr("Memory");
		case 3: return QObject::tr("Time");
		case 4: return QObject::tr("PID");
		default: return QVariant();
   		}
	}
	else if(role == Qt::ToolTipRole)
	{
		switch ( section ) 
		{
  		case 0: return QObject::tr("The process name");
		case 1: return QObject::tr("The current <b>CPU usage</b> of the process <br> per processor core core");
		case 2: return QObject::tr("The <b>resident set size</b> of memory <br> used by the process");
		case 3: return QObject::tr("The running time of the process");
		case 4: return QObject::tr("The unique process ID");
		default: return QVariant();
   		}
	}
	
	
    	return QVariant();
}

MvProcNode* MvQProcModel::itemForIndex(const QModelIndex& index) const
{
	if(index.isValid())
	{
	  	if(MvProcNode* item=static_cast<MvProcNode*>(index.internalPointer()))
		{
		  	return item;
		}
	}
	
	return rootItem_; 
}  

QModelIndex MvQProcModel::indexForItem(MvProcNode* proc,int column)
{
	if(!proc->parent())
	 	return QModelIndex();	
		
	else 
	{  	int row=proc->parent()->indexOfChild(proc);
		return createIndex(row,column,proc);
	}
}	

QModelIndex MvQProcModel::index( int row, int column, const QModelIndex & parent) const
{
	if(!rootItem_ || row <0 || column < 0)
	  	return QModelIndex();
  
	MvProcNode *parentItem=itemForIndex(parent);
	if(MvProcNode *item = parentItem->childAt(row))
	{
	  	QModelIndex index=createIndex(row,column,item);
	  	return index;
	}
	
	return QModelIndex();
}

QModelIndex MvQProcModel::parent( const QModelIndex& index) const
{		
	if(!index.isValid())
	  	return QModelIndex();
	
	if(MvProcNode* childItem= itemForIndex(index))
	{
	  	if(MvProcNode* parentItem =childItem->parent())
		{
		  	if(parentItem == rootItem_)
			{
			  	return QModelIndex();
			}
			else if(MvProcNode* grandParentItem = parentItem->parent())
			{  
			 	int row=grandParentItem->indexOfChild(parentItem);
				return createIndex(row,0,parentItem);
			}
		}
	}
	
	return QModelIndex();
	
}

void  MvQProcModel::infoChanged(MvProcNode* proc)
{
	if(!proc)
	  	return;
		
	emit dataChanged(indexForItem(proc,1),
			 indexForItem(proc,3));
			 
} 

//=======================================
//
// MvQProcFilterModel:
//
//=======================================

MvQProcFilterModel::MvQProcFilterModel(QObject *parent) :  QSortFilterProxyModel(parent)
{
}

bool MvQProcFilterModel::lessThan(const QModelIndex &left,
                                       const QModelIndex &right) const
{
	QVariant leftData,rightData;	
	if(left.column() == 2)
	{
	  	leftData = sourceModel()->data(left,Qt::UserRole);
     		rightData = sourceModel()->data(right,Qt::UserRole); 
		return leftData.toLongLong() <   rightData.toLongLong();
	}
	else
	  	return QSortFilterProxyModel::lessThan(left,right); 
}  




