/*
 * GedDesHelper.cpp
 *
 *  Created on: Jun 1, 2009
 *      Author: alex
 */

#include "GedDesHelper.h"

#include "DistCommon.h"

namespace DESpot
{

const QPointF GedDesHelper::NOTEXIST = QPointF(-1, -1);

GedDesState* GedDesHelper::insertState(const DesState* myState, QPointF pos, QPointF labelPos)
{
	GedDesState *gedState = new GedDesState(*myState, null);
	gedState->setBrush(Qt::black);
	gedState->setZValue(1000.0);
	//addItem(gedState); GedDesScene will insert the state
	gedState->setPos(pos);
	gedState->setDesState(myState);

	if (DistCommon::GUI_Enabled)
		gedState->setLabelPos(labelPos);

	m_pStateMap->insert(myState,gedState);
	return gedState;

}

GedDesTrans* GedDesHelper::insertTransInternal
	(const DesTransition *desTrans, bool& isNew, bool isCurve)
{
	const GedDesState* sState = m_pStateMap->value(&(desTrans->fromState()));
	GedDesState* startState = const_cast<GedDesState*> (sState);

	const GedDesState* eState = m_pStateMap->value(&(desTrans->toState()));
	GedDesState* endState = const_cast<GedDesState*> (eState);

	GedDesTrans* gTrans = gedTrans(startState, endState);
	isNew = false;
	if (!gTrans)
	{
		gTrans = new GedDesTrans(m_pDes, startState, endState,
			null, null, null, isCurve);
		startState->addGedDesTrans(gTrans);
		endState->addGedDesTrans(gTrans);
		gTrans->setZValue(-1000.0);
		isNew = true;
	}

	if (DistCommon::GUI_Enabled)
	{
		gTrans->insertDesTrans(desTrans);
		startState->addTrans(&(desTrans->event()), gTrans);
	}
	return gTrans;
}


GedDesTrans* GedDesHelper::insertTrans(const DesTransition *desTrans,
	bool& isNew, bool isCurve)
{
	if (!DistCommon::GUI_Enabled)
		return NULL;

	GedDesTrans* tran=insertTransInternal(desTrans, isNew, isCurve);
	tran->updatePosition();
	return tran;
}

GedDesTrans* GedDesHelper::insertTrans(const DesTransition *desTrans,
	QList<QPointF> pos, QPointF labelPos, bool& isNew, bool isCurve)
{
	if (!DistCommon::GUI_Enabled)
		return NULL;

	GedDesTrans* tran=insertTransInternal(desTrans, isNew, isCurve);

	if (isNew)
	{
		tran->setTransShape(pos);
		tran->updatePosition();
	}

	tran->setLabelPos(labelPos);
	return tran;
}

GedDesTrans* GedDesHelper::insertTrans(const DesTransition *desTrans,
	qreal angle, QPointF labelPos, bool& isNew, bool isCurve)
{
	if (!DistCommon::GUI_Enabled)
		return NULL;

	GedDesTrans* tran=insertTransInternal(desTrans, isNew, isCurve);
	tran->setAngle(angle);
	tran->updatePosition();
	tran->setLabelPos(labelPos);
	tran->rotateSelfLoop(angle); //cannot handle this in updatePostion
	return tran;
}

// There is only one graphic transition between two graphic states
// Each transition may represents mutliple DES transition with different
// events. That is, only one transition line is visible in graphic scene
GedDesTrans* GedDesHelper::gedTrans(GedDesState *startState,
									  GedDesState *endState)
{
	// To find there is a gedTrans between these two gedState
	QList<GedDesTrans *> trans = startState->getTrans();
	QList<GedDesState *> states;
	foreach (GedDesTrans *tran, trans)
		if (startState == tran->getStartState() &&
			endState == tran->getEndState())  // We added trans to end item as well
			return tran;
    return 0;
}

// Note, this and the next one matches event as well while the above one does NOT
GedDesTrans* GedDesHelper::gedTrans(GedDesState *startState, const DesEvent *ev,
									  GedDesState *endState)
{
	//We first find the gedTrans
	GedDesTrans *trans = gedTrans(startState,endState);
	if (trans)
		if(trans->findEvent(ev))   //if the event is defined in this gedTrans
			return trans;
	return 0;
}

GedDesTrans* GedDesHelper::gedTrans(const DesTransition *desTrans, bool useEvent)
{
	const GedDesState *sState = m_pStateMap->value(&(desTrans->fromState()));
	GedDesState *startState=const_cast<GedDesState*>(sState);

	const GedDesState *eState = m_pStateMap->value(&(desTrans->toState()));
	GedDesState *endState=const_cast<GedDesState*>(eState);

	if (!(startState && endState)) { return 0; }

	if (useEvent)
	{
		const DesEvent* ev = &(desTrans->event());
		if (!ev) { return 0; }
		return gedTrans(startState, ev, endState);
	}
	else
	{
		return gedTrans(startState, endState);
	}
}

//Utility functions for save/open
QPointF GedDesHelper::statePos(const DesState &state)
{
	const GedDesState* gedstate = 0;
	if (m_pStateMap->contains(&state))
		gedstate = m_pStateMap->value(&state);

	if (gedstate)
		return gedstate->scenePos();
	else
		return NOTEXIST;
}

QPointF GedDesHelper::stateLabelPos(const DesState &state)
{
	const GedDesState* gedstate = 0;
	if (m_pStateMap->contains(&state))
		gedstate = m_pStateMap->value(&state);

	if (gedstate)
		return gedstate->labelPos();
	else
		return NOTEXIST;
}

QList<QPointF> GedDesHelper::transPos(const DesTransition &trans)
{
	QList<QPointF> pt_lst;

	const GedDesState *gState = gedState(&trans.fromState());
	const GedDesTrans* gTrans = gState->gedTrans(&(trans.event()));

	if (gTrans)
		return gTrans->getPos();
	else
		return pt_lst;
}

QPointF GedDesHelper::transLabelPos(const DesTransition &trans)
{
	const GedDesTrans* gedtrans = gedTrans(&trans);
	assert(gedtrans);

	if (gedtrans){
		return gedtrans->labelPos();
	}
	else
		return NOTEXIST;
}

qreal GedDesHelper::selfloopPos(const DesTransition &trans)
{

	const GedDesTrans* gedtrans = gedTrans(&trans);
	assert(gedtrans);

	if (gedtrans)
		return gedtrans->angle();
	else
		return -1;
}

const GedDesState* GedDesHelper::gedState(const DesState *state) const
{
	if (m_pStateMap->contains(state))
		 return m_pStateMap->value(state);
	else
		return 0;
}


}
