#include <QtCore>

#include "SimStateModel.h"
#include "SimStateParser.h"

namespace DESpot
{
SimStateModel::SimStateModel(SimCompState::StateTuple gstate, QObject *parent)
    : QAbstractItemModel(parent),readOnly(false), showViewCol(false)
{
    rootNode = 0;
	globalState = SimCompState::StateTuple(gstate);
}

SimStateModel::SimStateModel(QObject *parent)
    : QAbstractItemModel(parent),readOnly(false), showViewCol(false)
{
    rootNode = 0;
}


SimStateModel::~SimStateModel()
{
    delete rootNode;
}

void SimStateModel::setStateTuple(SimCompState::StateTuple gstate)
{
	globalState = SimCompState::StateTuple(gstate);
}

void SimStateModel::setRootNode(Node *node)
{
    delete rootNode;
    rootNode = node;
    reset();
}

QModelIndex SimStateModel::index(int row, int column,
                               const QModelIndex &parent) const
{
    if (!rootNode)
        return QModelIndex();
    Node *parentNode = nodeFromIndex(parent);
    return createIndex(row, column, parentNode->children[row]);
}

QModelIndex SimStateModel::parent(const QModelIndex &child) const
{
    Node *node = nodeFromIndex(child);
    if (!node)
        return QModelIndex();
    Node *parentNode = node->parent;
    if (!parentNode)
        return QModelIndex();
    Node *grandparentNode = parentNode->parent;
    if (!grandparentNode)
        return QModelIndex();

    int row = grandparentNode->children.indexOf(parentNode);
    return createIndex(row, child.column(), parentNode);
}

int SimStateModel::rowCount(const QModelIndex &parent) const
{
    Node *parentNode = nodeFromIndex(parent);
    if (!parentNode)
        return 0;
    return parentNode->children.count();
}

int SimStateModel::columnCount(const QModelIndex & /* parent */) const
{
    return showViewCol ? 5 : 4;
}

QVariant SimStateModel::data(const QModelIndex &index, int role) const
{
    if (role != Qt::DisplayRole && role != Qt::TextColorRole && role != Qt::FontRole)
        return QVariant();

    Node *node = nodeFromIndex(index);
    if (!node)
        return QVariant();

    if (role == Qt::TextColorRole)
	{
		return node->isBlockingDes ? Qt::red : Qt::black;
	}

    if (role == Qt::FontRole)
	{
    	QFont font;
    	font.setBold(node->isBlockingDes);
		return font;
	}

    if (index.column() == 0) {
        switch (node->type) {
        case Node::MetaData:
        case Node::DES:
		case Node::StateTuple:
            return node->desName;
        default:
            return tr("Unknown");
        }
    } else if (index.column() == 1) {
		if(node->type == Node::DES)
			return node->stateName;
		else 
			return "";
    } else if (index.column() == 2) {
		if(node->type == Node::DES || node->type == Node::StateTuple)
			return node->initCol;
		else 
			return "";
    } else if (index.column() == 3) {
		if(node->type == Node::DES || node->type == Node::StateTuple)
			return node->markedCol;
		else 
			return "";
    } else if (showViewCol && index.column() == 4) {
    	if (node->type == Node::DES)
    		return node->viewerVisible ? "Y" : "N";
    	else
    		return "";
    }
    return QVariant();
}

QVariant SimStateModel::headerData(int section,
                                 Qt::Orientation orientation,
                                 int role) const
{
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
        if (section == 0) {
            return tr("DES");
        } else if (section == 1) {
            return tr("State");
        } else if (section == 2) {
            return tr("I");
        } else if (section == 3) {
            return tr("M");
        } else if (showViewCol && section == 4) {
        	return tr("Viewer Visible");
        }
    }
    return QVariant();
}

Node *SimStateModel::nodeFromIndex(const QModelIndex &index) const
{
    if (index.isValid()) {
        return static_cast<Node *>(index.internalPointer());
    } else {
        return rootNode;
    }
}

Qt::ItemFlags SimStateModel::flags(const QModelIndex &index) const
{

	if (index.column()==1){
		Node *node = nodeFromIndex(index);
		if(node->type == Node::MetaData || readOnly)
			return 0;
		else
			return (Qt::ItemIsEnabled|Qt::ItemIsSelectable|Qt::ItemIsEditable);
	}
	else 
		return (Qt::ItemIsEnabled|Qt::ItemIsSelectable);
}

bool SimStateModel::setData ( const QModelIndex & index, const QVariant & value, int /*role*/)
{
	Node *node = nodeFromIndex(index);
	QString staName = value.toString();
	node->stateName = staName;
	const DesState *sta = 0;
	if (!((node->des)->findState(staName.toStdWString(),sta))) 
	  {
	    assert(false);  //never should get here.
	  }

	node->state = sta;
	node->initCol = (sta->isInit())?"X":"";
	node->markedCol= (sta->isMarked())?"X":"";
	globalState[const_cast<Des*>(node->des)]=const_cast<DesState*>(sta);
	
	QModelIndex tupleNodeIdx=index;
	while (tupleNodeIdx.parent().isValid())
	{
		tupleNodeIdx = parent(tupleNodeIdx);
	}
	Node* tupleNode = nodeFromIndex(tupleNodeIdx);
	tupleNode->initCol = isStateTupleInit()?"X":"";
	tupleNode->markedCol = isStateTupleMarked()?"X":"";
	emit dataChanged(tupleNodeIdx,tupleNodeIdx);
	

	emit dataChanged(index,index);
	return true;
}

bool SimStateModel::isStateTupleInit()
{
	std::map<Des*,DesState*>::const_iterator it = globalState.begin();
	bool initState = true;
	for (; it != globalState.end(); ++it){
		/*Des* des = */it->first;
		DesState* state = it->second;
		if (!state->isInit()){
			initState = false;
			break;
		}
	}
	return initState;
}

bool SimStateModel::isStateTupleMarked()
{
	std::map<Des*,DesState*>::const_iterator it = globalState.begin();
	bool marked = true;
	for (; it != globalState.end(); ++it){
		/*Des* des = */it->first;
		DesState* state = it->second;
		if (!state->isMarked()){
			marked = false;
			break;
		}
	}
	return marked;
}	

}
