#include <QtCore>
#include <map>

#include "SimStateNode.h"
#include "SimStateParser.h"
#include "DesSubsystem.h"
#include "DesInterface.h"

namespace DESpot
{

SimStateParser::SimStateParser(const DesProject *proj, const SimWorkspace::SimGedViewerMap* pSimGedViewers)
{
    m_pProject = proj;
    m_pSimGedViewers = pSimGedViewers;
	this->globalState = 0;
	hierProject = 0;
	flatProject = 0;
    if(m_pProject->getType()==eHierProject){
		hierProject =  dynamic_cast<DesHierProject*>(const_cast<DesProject*>(m_pProject));
        projectType = eHierProject;
		}
	else {
		flatProject =  dynamic_cast<DesFlatProject*>(const_cast<DesProject*>(m_pProject));
        projectType = eFlatProject;
	}
}

Node *SimStateParser::parse(ParseType type)
{
    this->type = type;
	this->globalState = 0;
    if(projectType == eHierProject && type == Hier)
		return parseHierProject();
    if(projectType == eHierProject && type == Flat)
		return parseAsFlat();
    if(projectType == eFlatProject && type == Flat)
		return parseFlat();
	return 0;
}

Node *SimStateParser::parse(SimCompState::StateTuple *globalSta, ParseType type)
{
    this->type = type;
	this->globalState = globalSta;
    if(projectType == eHierProject && type == Hier)
		return parseHierProject();
    if(projectType == eHierProject && type == Flat)
		return parseAsFlat();
    if(projectType == eFlatProject && type == Flat)
		return parseFlat();
	return 0;
}

// Parse hier project as flat
Node *SimStateParser::parseAsFlat()
{
	QString projName = QString::fromStdWString(m_pProject->getName());
	Node *node = new Node(projName);

	Node *tupleNode = new Node("State Tuple");
	tupleNode->type = Node::StateTuple;
	tupleNode->initCol = isStateTupleInit()?"X":"";
	tupleNode->markedCol = isStateTupleMarked()?"X":"";
    addChild(node,tupleNode);

	//Add supervisor
	Node *node1 = new Node("Supervisors");
	addChild(tupleNode,node1);
	//High level
	const DesSubsystem& highLevelSubsys=hierProject->getRootSubsys();
    DesSubsystem::DesIteratorPtr supDesIt = highLevelSubsys.createDesIterator(eSupervisorDes);
	addDesNodes(node1,supDesIt); 

	//Low level
	//DesSubsystem::DependIteratorPtr lowSubsysIt = hierProject->getRootSubsys().createDependsIterator();
	DesHierProject::SubsysIteratorPtr lowSubsysIt = hierProject->createSubsysIterator();
	for(lowSubsysIt->first(); lowSubsysIt->isDone() == false; lowSubsysIt->next())
	{
		if(lowSubsysIt->currentItem().isRoot()==false)
		{
		/*const DesInterface&  interf = */(lowSubsysIt->currentItem().getInterface());
		const DesSubsystem&  lowSubsys = (lowSubsysIt->currentItem());
		
		//QString itemText = QString::fromStdWString(lowSubsys.getName());
		//QString itemTooltip = stateName_SUBSYS_ITEM_TOOLTIP(itemText, "0", "0");
		
		//Node* node1 = new Node(itemText);
		//addChild(node,node1);

		//Node *node2 = new Node("Supervisor");
		//addChild(node1,node2);
		//load all the supervisor DES belonging to this subsystem
        supDesIt = lowSubsys.createDesIterator(eSupervisorDes);
		addDesNodes(node1, supDesIt); 	
		}
	}
	
	// Interface Des
	Node *node2 = new Node("Interface");
	addChild(tupleNode,node2);
	DesHierProject::InterfIteratorPtr interfIt = hierProject->createInterfIterator();
	for(interfIt->first(); interfIt->isDone() == false; interfIt->next())
	{
		const DesInterface& interf = interfIt->currentItem();
		//onInterfaceAdded(interf);
		//	QString itemText = QString::fromStdWString(interf.getName());
			//QString itemTooltip = stateName_SUBSYS_ITEM_TOOLTIP(itemText, "0", "0");
			
			//add an item in the level view
			{
			//	Node* interfNode = new Node(itemText);
			//	addChild(node,interfNode);
				
				DesInterface::DesIteratorPtr desIt = interf.createDesIterator();
				addDesNodes(node2, desIt);
			}
	}

	//Add plants
	Node *node3 = new Node("Plants");
	addChild(tupleNode,node3);
	// High level plants
    DesSubsystem::DesIteratorPtr plantDesIt = highLevelSubsys.createDesIterator(ePlantDes);
	addDesNodes(node3,plantDesIt); 

	// Low level plants
	for(lowSubsysIt->first(); lowSubsysIt->isDone() == false; lowSubsysIt->next())
	{
		if(lowSubsysIt->currentItem().isRoot()==false)
		{
		/*const DesInterface&  interf = */(lowSubsysIt->currentItem().getInterface());
		const DesSubsystem&  lowSubsys = (lowSubsysIt->currentItem());
        plantDesIt = lowSubsys.createDesIterator(ePlantDes);
		addDesNodes(node3, plantDesIt);
		}
	}

	return node;
}

Node *SimStateParser::parseFlat()
{
	QString projName = QString::fromStdWString(m_pProject->getName());
	Node *node = new Node(projName);

	Node *tupleNode = new Node("State Tuple");
	tupleNode->type = Node::StateTuple;
	tupleNode->initCol = isStateTupleInit()?"X":"";
	tupleNode->markedCol = isStateTupleMarked()?"X":"";
    addChild(node,tupleNode);

	//Add supervisor
	Node *node1 = new Node("Supervisors");
	addChild(tupleNode,node1);
    DesProject::DesIteratorPtr desIt = flatProject->createDesIterator(eSupervisorDes);
	addDesNodes(node1,desIt);

	//Add plants
	Node *node2 = new Node("Plants");
	addChild(tupleNode,node2);
    desIt = flatProject->createDesIterator(ePlantDes);
	addDesNodes(node2,desIt);

	return node;
}

Node *SimStateParser::parseHierProject()
{
	//create the root item for the project
	QString projName = QString::fromStdWString(m_pProject->getName());
	Node *node = new Node(projName);

	Node *tupleNode = new Node("State Tuple");
	tupleNode->type = Node::StateTuple;
	tupleNode->initCol = isStateTupleInit()?"X":"";
	tupleNode->markedCol = isStateTupleMarked()?"X":"";
    addChild(node,tupleNode);

	addChild(tupleNode,parseHighLevel());
	
	addChild(tupleNode, parseInterface());

	addChild(tupleNode,parseLowLevel());

	return node;
}

Node *SimStateParser::parseHighLevel()
{

	Node *node = new Node("High Level");
	const DesSubsystem& highLevelSubsys=hierProject->getRootSubsys();
	QString itemText = QString::fromStdWString(highLevelSubsys.getName());			
	Node *node1 = new Node(itemText);
	addChild(node,node1);

	//Add high level supervisor
	Node *node2 = new Node("Supervisor");
	addChild(node1,node2);
    DesSubsystem::DesIteratorPtr supDesIt = highLevelSubsys.createDesIterator(eSupervisorDes);
	addDesNodes(node2,supDesIt); 

	//Add high level plants
	Node *node3 = new Node("Plants");
	addChild(node1,node3);
    DesSubsystem::DesIteratorPtr plantDesIt = highLevelSubsys.createDesIterator(ePlantDes);
	addDesNodes(node3, plantDesIt); 

	return node;

}

Node *SimStateParser::parseInterface()
{
    Node *node = new Node("Interface");

	//load all interfaces
	DesHierProject::InterfIteratorPtr interfIt = hierProject->createInterfIterator();
	for(interfIt->first(); interfIt->isDone() == false; interfIt->next())
	{
		const DesInterface& interf = interfIt->currentItem();
		//onInterfaceAdded(interf);
			QString itemText = QString::fromStdWString(interf.getName());
			//QString itemTooltip = stateName_SUBSYS_ITEM_TOOLTIP(itemText, "0", "0");
			
			//add an item in the level view
			{
				Node* interfNode = new Node(itemText);
				addChild(node,interfNode);
				
				DesInterface::DesIteratorPtr desIt = interf.createDesIterator();
				addDesNodes(interfNode, desIt);
			}
	}
    return node;
}

Node *SimStateParser::parseLowLevel()
{
    Node *node = new Node("Low Level Subsystem");

	//load all low-level subsystems dependent on the high-level one

	//DesSubsystem::DependIteratorPtr lowSubsysIt = hierProject->getRootSubsys().createDependsIterator();
	DesHierProject::SubsysIteratorPtr lowSubsysIt = hierProject->createSubsysIterator();
	for(lowSubsysIt->first(); lowSubsysIt->isDone() == false; lowSubsysIt->next())
	{
		if(lowSubsysIt->currentItem().isRoot() == false)
		{
		/*const DesInterface&  interf = */(lowSubsysIt->currentItem().getInterface());
		const DesSubsystem&  lowSubsys = (lowSubsysIt->currentItem());
		
		QString itemText = QString::fromStdWString(lowSubsys.getName());
		//QString itemTooltip = stateName_SUBSYS_ITEM_TOOLTIP(itemText, "0", "0");
		
		Node* node1 = new Node(itemText);
		addChild(node,node1);

		Node *node2 = new Node("Supervisor");
		addChild(node1,node2);
		//load all the supervisor DES belonging to this subsystem
        DesSubsystem::DesIteratorPtr supDesIt = lowSubsys.createDesIterator(eSupervisorDes);
		addDesNodes(node2, supDesIt); 

		Node *node3 = new Node("Plants");
		addChild(node1,node3);
		//load all the plant DES belonging to this subsystem
        DesSubsystem::DesIteratorPtr plantDesIt = lowSubsys.createDesIterator(ePlantDes);
		addDesNodes(node3, plantDesIt); 	
		}
	}
    return node;
}

void SimStateParser::addChild(Node *parent, Node *child)
{
    parent->children += child;
    //parent->stateName += child->stateName;
    child->parent = parent;
}

void SimStateParser::addDesNodes(Node *parent,DesProject::DesIteratorPtr& desIt)
{
	
	//add DES items to the given container item
	for(desIt->first(); desIt->isDone() == false; desIt->next())
	{
		const Des& des = desIt->currentItem();

		//create a new item and add it to the parent
		QString itemText = QString::fromStdWString(des.getName());
		QString desFileName = QString::fromStdWString(des.getFileName());
		QString itemTooltip =  itemText + " - " + desFileName;
		
		const DesState* sta;
		if (globalState){
			Des* pDes = const_cast<Des*>(&des);
			sta = (*globalState)[pDes];
		}
		else
			sta = &(des.getInitialState());

		bool viewerVisible = false;
		if (m_pSimGedViewers) {
			SimGedViewer* pView = m_pSimGedViewers->value(&des, 0);
			viewerVisible = pView && !pView->isHidden();
		}

		//add the newly created item to the proper parent depending on the type (sup or plant) and
		//update the tooltip of the parent item with the number of DESs
		//createFlatViewDesItem(itemText,itemTooltip, item, &des); 
		Node* node=new Node(Node::DES,&des,sta, viewerVisible);
		addChild(parent,node);
	}

	//item->setToolTip(0, stateName_PROJ_stateNameUCT_SUP_ITEM_TOOLTIP(item->childCount()));
	
}

bool SimStateParser::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 SimStateParser::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;
}	

DesHierProject* SimStateParser::project()
{
	return dynamic_cast<DesHierProject*>(const_cast<DesProject*>(m_pProject));
}

}
