/*************************************************************************
 * This file is part of Graphic des EDitor project    
 *
 * Project created in conformity with the requirements for the Degree of
 * Master of Engineering in Software Engineering, Computing and Software
 * Department, McMaster University 2004 - 2008
 *
 * Author:	Xiao Ma
 * Supervisor: Dr. Ryan Leduc
*************************************************************************/

/* 
 NAME
   GedDesTrans.cpp - Ged DES transition function. 
 FUNCTION
   The class provides the graphic transition function. 
 NOTES
 MODIFIED
   xma	    04/01/07 - CREATION 
*/
#include <math.h>
#include <assert.h>
#include "GedDesTrans.h"
#include "GedTextItem.h"
#include "Des.h"

// for debug
// #include <iostream>


namespace DESpot
{

static const double Pi = 3.14159265358979323846264338327950288419717;
static const double TwoPi = 2.0 * Pi;
static const double HalfPi = Pi / 2.0;
static const double Square_root_of_2 = 1.4142135623730950488016887242097;
static const qreal sz_sl = 50; // size of self loop rect
static const qreal ArrowSize = 12.5;
  //static const qreal ArrowSize = 20;

//TODO: where is this method supposed to be used? Since it is static, it can only be used in this file where it is not used
/*static qreal normalizeAngle(qreal angle)
{
     while (angle < 0)
         angle += TwoPi;
     while (angle > TwoPi)
         angle -= TwoPi;
     return angle;
}*/

void GedDesTrans::setReadOnly(bool readOnly)
{
	setFlag(QGraphicsItem::ItemIsMovable, !readOnly);
	setFlag(QGraphicsItem::ItemIsSelectable, !readOnly);
	label->setFlag(QGraphicsItem::ItemIsMovable, !readOnly);
	label->setFlag(QGraphicsItem::ItemIsSelectable, !readOnly);
}

void GedDesTrans::initTransProps()
{
    setFlag(QGraphicsItem::ItemIsSelectable, true);

    // next needed for changes made to qt 4.6 and greater
#ifdef  __QT_Vers_gteq_4_6__
    setFlag(QGraphicsItem::ItemSendsGeometryChanges);
#endif

    //myColor = Qt::black;
    setPen(QPen(Qt::black, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
	line=0;

	// set to default value so can tell when position has been
	//assigned 
	//	currentAngle=0;
	currentAngle = defaultGedItemValue;
	if (startState == endState) 
	{
		label = new GedDesLabel(this);
		//label->setParentItem(0);
		
	}
	else
		label = new GedDesLabel(this);
}

GedDesTrans::GedDesTrans(Des* des,GedDesState *startState, GedDesState *endState, 
						 QMenu *contextMenu, QGraphicsItem *parent, 
						 QGraphicsScene *scene)
    : QGraphicsPathItem(parent, scene),
        startState(startState),
        endState(endState),
        contextMenu(contextMenu),
        des(des),
        m_pEligEvents(0),
        m_pPrevEvent(0),
        m_pNextEvent(0)
{
        m_lastStartPos = startState->pos();
	m_lastEndPos = endState->pos();
	initTransProps();
	assert(label);
}


QVariant  GedDesTrans::itemChange(GraphicsItemChange change, const
QVariant &value)
{

  if (change == QGraphicsItem::ItemSelectedChange) {

    // value is a boolean giving new selected state
    // this part added to allow movement of entire DES at once
    // This prevents a selfloop transition to be moved (whic moves
    // its label as well)  and then have the a second movement applied
    // toi label itself.
    if (value.toBool()) {
      if ((label->isSelected()) && (isSelfLoop())) {
	label->setFlag(QGraphicsItem::ItemIsMovable,false);
      }      
    } else {
      // ensures when only label selected, it can be repositioned
      label->setFlag(QGraphicsItem::ItemIsMovable,true);
    }
  }

  return value;

}

void GedDesTrans::updatePosition()
{
    QLineF myLine;


    // Self loop
	if (startState == endState)
	{

	        resetTransform();
		myLine = createCircle();
		//label->setParentItem(0); //We don't want rotate the label
		// How much do we need to rotate
		if (line != 0 ) 
		{

			/*
			//QLineF line1 = QLineF(QPointF(0,0),mapFromScene(line->p1()));
			QLineF line2 = QLineF(QPointF(0,0),mapFromScene(line->p2()));

			//qreal rotateAngle = acos(line2.dy()/line2.length());	
			qreal rotateAngle = atan(line2.p2().y()/line2.p2().x());	

			//rotateAngle = abs(normalizeAngle(rotateAngle));
			rotateAngle = abs((rotateAngle));
			currentAngle = rotateAngle;

			qreal x = line2.p2().x();
			qreal y = line2.p2().y();
			if(x<0 && y>0) 
				currentAngle = Pi - currentAngle;
			if(x<0 && y<0)
				currentAngle = Pi + currentAngle;
			if(x>0 && y<0)
				currentAngle = TwoPi - currentAngle;
			currentAngle -= HalfPi/2.0;
			//Move out so that the currentAngle will be used when reading from file
			*/

			QLineF line2 = QLineF(QPointF(0,0),mapFromScene(line->p2()));

			qreal x = line2.p2().x();
			qreal y = line2.p2().y();
			qreal angle;
			
			    if (y == 0) 
			      if (x >= 0) 
				currentAngle = 0;
			      else
				currentAngle = 180;
			    else
			      if (x == 0)
				currentAngle = 0;
			      else
				{
				  angle = atan(y/x);
				  //1st ok, no change needed
				  //2nd. atan < 0, => +pi
				  if(x<0 && y>0) 
				    angle = Pi + angle;
				  //3nd
				  if(x<0 && y<0)
				    angle = Pi + angle;
				  if(x>0 && y<0)
				    angle = TwoPi + angle;
				  currentAngle = angle * (180.0/Pi);
				  currentAngle -= 45.0;
				}

			line=0;

		}



		// make sure current angle not left at defaul if 
		// line ==0

		if (currentAngle <= defaultGedItemValue)
		  {
		    // this rotates selfloop so it is baove the state
		    currentAngle = 225;
		  }

		// must always do a rotate as transform was reset.
		rotateSelfLoop(currentAngle);

		//updatePosition<-GedDesState.itemChange()<-moveItem()
		//So do NOT call rotate here, otherwise, the circle will
		//keep rotating while moving mouse.
		//rotate(currentAngle*(180.0/Pi));
		//label->setParentItem(this);
		//label->rotate(-currentAngle*(180.0/Pi));
		/*
		scene()->removeItem(label);
		delete label;
		label = new GedDesLabel(this);
		updateLabel();
		*/
		
	}
	
	// Normal transition, i.e  not self loop
	if (startState != endState)
	{
		if(naPath.elementCount() == 0)
			myLine = createLine();
		else 
			myLine = changeLine();
	}

	//arrow head
	double angle = ::acos(myLine.dx() / myLine.length());
    if (myLine.dy() >= 0)
        angle = (Pi * 2) - angle;

    QPointF arrowP1 = myLine.p1() + QPointF(sin(angle + Pi / 3) * ArrowSize,
                                    cos(angle + Pi / 3) * ArrowSize);
    QPointF arrowP2 = myLine.p1() + QPointF(sin(angle + Pi - Pi / 3) * ArrowSize,
                                    cos(angle + Pi - Pi / 3) * ArrowSize);

    arrowHead.clear();
    arrowHead << myLine.p1() << arrowP1 << arrowP2 ;
	//arrowHead << myLine.p1() << arrowP1 << arrowP2 <<myLine.p1();

	QPainterPath myPath = naPath;
	myPath.addPolygon(arrowHead);
	setPath(myPath);

	//Relocate the label
    // NOTE: the following code is due to 2 bug fixes
	   /*  basic concept
	       1) label is initialized as a child of trans
		   2) when rotate self-loop, we set label parent to 0
                      (this is no longer done)
		   so we need the following code
		   1) selfloop && there is parent => selfloop created, not rotated
		   2) selfloop && no parent => selfloop has been rotated.
	   */

	//RJL: add check here to prevent label pos changing if not default.
	QPointF tmpPoint(label->pos());
	if ((tmpPoint.x() <= defaultGedItemValue) && (tmpPoint.y() <=
	defaultGedItemValue))
	  {
	    QLineF labelPosLine = QLineF(myLine.p1(),arrowP1);
	    labelPosLine.setLength(labelPosLine.length()*1.8);
	    if (startState == endState) //self-loop => label has no parent
	      {
		if (label->parentItem())
		  label->setPos(labelPosLine.p2());
		else
		  label->setPos(labelPosLine.p2() + mapToScene(QPointF(0,0)));
	      }
	    else
	      label->setPos(labelPosLine.p2());
	  }

}

void GedDesTrans::rotateSelfLoop(qreal angle)
{

	/*
	rotate(angle*(180.0/Pi));
	label->rotate(-angle*(180.0/Pi));
	*/
        // label->setParentItem(0);
	//QGraphicsItem *item =label->parentItem();
	resetTransform();
	rotate(angle);
	//resetTransform();
	//label->setParentItem(this);
	//label->rotate(-angle);

}

  // this function should only be called by simulator, never by 
  // graphical des editor

  void GedDesTrans::draw(QPainter* painter, QPointF& offset)
{
	if (isSelfLoop())
	{
		painter->save();
		painter->translate(getStartState()->pos()- offset);
		painter->rotate(angle());
		drawTrans(painter, true);
		painter->restore();
	}
	else
	{
		painter->save();
		painter->translate(-offset);
		drawTrans(painter, true);
		painter->restore();
	}

	if (label)
	{
		painter->save();
		painter->translate(mapToScene(label->pos())- offset);

		QRectF rect = label->boundingRect();

		QFontMetrics fm = painter->fontMetrics();

                int x = (int)rect.x();
		int y = 0;
                int w = (int)rect.width();
                int h = (int)fm.height();

		foreach (SimLabel lbl, simLabels)
		{
			if (lbl.prev && simType == PrevSimTrans)
				// BH - This condition doesn't work with multiple events in a transition,
				// and colour now handled in updateLabel(), but leaving as a just in case for transitions
				// with single events.
				painter->setPen(Qt::magenta);
			else if (lbl.next && simType == SelectedSimTrans)
				painter->setPen(Qt::green);
			else
				painter->setPen(lbl.color);

			const QFont& oldFont = painter->font();
			if (lbl.controllable)
			{
				QFont font = QFont(painter->font());
				font.setItalic(true);
				painter->setFont(font);
			}

			painter->drawText(QRect(x, y, w, h), lbl.text,
					QTextOption(Qt::AlignBottom | Qt::AlignHCenter));

			if (lbl.prev)
			{
				painter->setPen(Qt::magenta);
				painter->drawText(QRect(w, y, fm.width("*"), h),
						"*", QTextOption(Qt::AlignBottom | Qt::AlignHCenter));
			}

			y += painter->fontMetrics().lineSpacing();

			painter->setFont(oldFont);
		}
		painter->restore();
	}
}


void GedDesTrans::drawTrans(QPainter* painter, bool simMode)
{
	painter->setRenderHint(QPainter::Antialiasing);

	if (startState != endState &&
		startState->collidesWithItem(endState))
		return;

	QColor color = Qt::black;
	QColor brushColor = Qt::black;
	if (simMode)
	{
		if (simType == EligibleSimTrans) {
			brushColor = color = Qt::blue;
		} else if (simType == PrevSimTrans) {
			brushColor = color = Qt::magenta;
		} else if (simType == EligiblePrevSimTrans) {
			color = Qt::blue;
			brushColor = Qt::magenta;
		} else if (simType == SelectedSimTrans) {
			color = Qt::green;
		}
	}
	QPen myPen = QPen(color, 1, Qt::SolidLine);
	painter->setPen(myPen);

	//painter->setBrush(Qt::black);

	QPainterPath myPath=path();
	painter->drawPath(myPath);
	QPainterPath arrowHeadPath;
	arrowHeadPath.addPolygon(arrowHead);
	painter->fillPath(arrowHeadPath, QBrush(brushColor));

	/* debug selfloop - draw coordinator
	painter->setPen(QPen(Qt::red, 6, Qt::DashLine));
	painter->drawLine(QLineF(QPointF(0,0),QPointF(0,20)));
	painter->drawLine(QLineF(QPointF(0,0),QPointF(20,0)));
	*/

	if (isSelected() && !simMode)
	{
		painter->setPen(QPen(color, 1, Qt::DashLine));
		if(startState == endState)
		{
			QRectF myRect = myPath.boundingRect();
			painter->drawRect(myRect);
		}
		else
		{
			//painter->drawPath(selectShape());
			//painter->drawPath(shape());

			QList<QPointF> pos = getPos();
			//painter->setBrush(Qt::Dense3Pattern);
			painter->setBrush(Qt::SolidPattern);
			foreach(QPointF pnt, pos)
				painter->drawRect(QRectF(pnt.x()-4,pnt.y()-4,8,8));
		}

		//painter->setPen(QPen(Qt::red, 3, Qt::DashLine));
		//painter->drawPath(shape());

		label->setSelected(true);
	}
}

void GedDesTrans::paint(QPainter *painter, const QStyleOptionGraphicsItem *,
          QWidget *)
{
	drawTrans(painter, false);
}

QLineF GedDesTrans::createCircle()
{
	//Move origin to state origin
	setPos(startState->pos());

	// Draw a circle. 10.0 is length of radian of state
	QPainterPath myPath;
	qreal r = (10.0/(Square_root_of_2-1));
	myPath.addEllipse(0,0,2*r,2*r);

	// Line for arrow header
	QLineF myLine=QLineF(
		QPointF(10.0/Square_root_of_2,10.0/Square_root_of_2),
		QPointF(r,0));

	naPath = myPath;
	return myLine;
}

/*  old version
QLineF GedDesTrans::createCircle()
{
	QPointF p = startState->pos();

	// Draw a circle
	// rotateLine, from origin to line.p2
	QLineF rotateLine, myLine;
	qreal dx =0;
	qreal dy =0;
	if (line != 0 ) {
		rotateLine = QLineF(p,line->p2());
		rotateLine.setLength(25*1.414);
		dx = rotateLine.dx();
		dy = rotateLine.dy();
		line=0;
	}

	QPointF newStartP;
	if ( dx == 0 && dy == 0) 
		newStartP = QPointF(p.x(),p.y());
	else
		newStartP = QPointF( p.x() - (25-dx),
							 p.y() - (25-dy));

	QPainterPath myPath;
	myPath.addEllipse(newStartP.x(),newStartP.y(),50,50);

	// Calculate a line, the line is used to draw the arrow head
	double ang;
	double pct;
	if (dx==0 && dy==0)
		ang = (180.0 + 45.0)/180*Pi;
	else
		ang = abs(::atan(dy/dx));
	if (dx > 0) 
		if (dy>0)
			pct = (Pi + ang)/(2*Pi);
		else
			pct = (Pi - ang)/(2*Pi);
	else 
		if (dy>0)
			pct = (2*Pi - ang)/(2*Pi);
		else 
			pct = (ang)/(2*Pi);
	
	myLine=QLineF(myPath.pointAtPercent(pct),
		myPath.pointAtPercent(abs(pct-0.25/2)));

	naPath = myPath;
	return myLine;
}
*/


QLineF GedDesTrans::createLine()
{
	QPainterPath myPath;

	QLineF centerLine(startState->pos(), endState->pos());
	QPolygonF endPolygon = endState->polygon();
	QPointF p1 = endPolygon.first() + endState->pos();
	QPointF p2;
	QPointF intersectPoint;
	QLineF polyLine;
	for (int i = 1; i < endPolygon.count(); ++i) {
		p2 = endPolygon.at(i) + endState->pos();
		polyLine = QLineF(p1, p2);
		QLineF::IntersectType intersectType =
			polyLine.intersect(centerLine, &intersectPoint);
		if (intersectType == QLineF::BoundedIntersection)
			break;
		p1 = p2;
	}
	
	//Because path item does not seem respecting zvalue,
	//We do this for start state as well
	QPolygonF startPolygon = startState->polygon();
	p1 = startPolygon.first() + startState->pos();
	QPointF startIntersectPoint;
	for (int i = 1; i < startPolygon.count(); ++i) {
		p2 = startPolygon.at(i) + startState->pos();
		polyLine = QLineF(p1, p2);
		QLineF::IntersectType intersectType =
			polyLine.intersect(centerLine, &startIntersectPoint);
		if (intersectType == QLineF::BoundedIntersection)
			break;
		p1 = p2;
	}

	myPath.moveTo(intersectPoint);
	myPath.lineTo(startIntersectPoint);
	//myPath.lineTo(startState->pos());

	naPath = myPath;
	QLineF myLine = QLineF(intersectPoint,startState->pos());

	return myLine;
}

/******************************************************************
If exists, we break the line
We iterator all elements in the PainterPath
Get the subpath (line for now) that intersect with the given 
line (paramters). Break this line into two lines.	
		 NOTE: for now, we only consider line 
How do I change a line?
1. if in scene, in line mode, we draw a line
2. the scene set class number myLine and pass the line to trans
3. if the start point of the line belongs to an existing line
4.   we break the line and change the line shape
We paint the shape of the trans using naPath + arrow
5.  intermediate points make the same delta move as the start and end states.
******************************************************************/
QLineF GedDesTrans::changeLine()
{
	QPainterPath myPath = naPath;
	int ec = myPath.elementCount();
	assert(ec > 0);

	if (line != 0){

		int subIdx=0;
		bool foundExist=false; //we will move an existing interfection
		                       //if it is in the selection rect

		QRectF rect = QRectF(line->p1().x()-5,line->p1().y()-5,10,10);
		for(int i=1; i<naPath.elementCount()-1; i++){  //don't include the staring and end pt
			const QPainterPath::Element ele = naPath.elementAt(i);
			if (rect.contains(ele.x,ele.y))
			{
				subIdx = i;
				foundExist = true;
				break;
			}
		}

		if(foundExist) // We just need to move an existing interfection
		{
			QPainterPath myNewPath;
			for (int i = 0; i <= subIdx-1; i++)
			{
				QPainterPath::Element e = myPath.elementAt(i);
				if (e.isMoveTo())
					myNewPath.moveTo(e.x,e.y);
				if (e.isLineTo())
					myNewPath.lineTo(e.x,e.y);
			}
			myNewPath.lineTo(line->p2());
			for (int i = subIdx+1; i< ec; i++)
			{
				QPainterPath::Element e = myPath.elementAt(i);
				if (e.isMoveTo())
					myNewPath.moveTo(e.x,e.y);
				if (e.isLineTo())
					myNewPath.lineTo(e.x,e.y);
			}
			myPath=myNewPath;

		}
		else  //We add a new interfection into the path
		{
			bool found=false;
			for (int i = 0; i< ec; i++)  //find which subpath is choosen
				if (myPath.elementAt(i).isLineTo())
				{
					QLineF centerLine(myPath.elementAt(i-1).x,myPath.elementAt(i-1).y,
									  myPath.elementAt(i).x,myPath.elementAt(i).y);	
					QLineF line1 = QLineF(line->p2(),line->p1());
					line1.setLength(line->length() + 20);  // add some extra
					QPointF ip;
					QLineF::IntersectType it = centerLine.intersect(line1,&ip);
					if (it == 1) {found=true; subIdx = i; break;}
				}
				
			if (found)
			{
				QPainterPath myNewPath;
				for (int i = 0; i < subIdx; i++)
				{
					QPainterPath::Element e = myPath.elementAt(i);
					if (e.isMoveTo())
						myNewPath.moveTo(e.x,e.y);
					if (e.isLineTo())
						myNewPath.lineTo(e.x,e.y);
				}
				myNewPath.lineTo(line->p2());
				for (int i = subIdx; i< ec; i++)
				{
					QPainterPath::Element e = myPath.elementAt(i);
					if (e.isMoveTo())
						myNewPath.moveTo(e.x,e.y);
					if (e.isLineTo())
						myNewPath.lineTo(e.x,e.y);
				}
				myPath=myNewPath;
			}
		}
	}

	// Adjust start / end point for move
	// Note: element[0] - endState central point
	//       element[1] - if straight line, central pt of startState
	ec = myPath.elementCount();
	QLineF centerLine(QPointF(myPath.elementAt(1).x,
							  myPath.elementAt(1).y),
					endState->pos());
	QPolygonF endPolygon = endState->polygon();
	QPointF p1 = endPolygon.first() + endState->pos();
	QPointF p2;
	QPointF intersectPoint;
	QLineF polyLine;
	for (int i = 1; i < endPolygon.count(); ++i) {
		p2 = endPolygon.at(i) + endState->pos();
		polyLine = QLineF(p1, p2);
		QLineF::IntersectType intersectType =
			polyLine.intersect(centerLine, &intersectPoint);
		if (intersectType == QLineF::BoundedIntersection)
			break;
		p1 = p2;
	}

	//Because path item does not seem respecting zvalue,
	//We do this for start state as well
	centerLine=QLineF(QPointF(myPath.elementAt(ec-2).x,
							  myPath.elementAt(ec-2).y),
					startState->pos());
	QPolygonF startPolygon = startState->polygon();
	p1 = startPolygon.first() + startState->pos();
	QPointF startIntersectPoint;
	for (int i = 1; i < startPolygon.count(); ++i) {
		p2 = startPolygon.at(i) + startState->pos();
		polyLine = QLineF(p1, p2);
		QLineF::IntersectType intersectType =
			polyLine.intersect(centerLine, &startIntersectPoint);
		if (intersectType == QLineF::BoundedIntersection)
			break;
		p1 = p2;
	}

	myPath.setElementPositionAt(0,intersectPoint.x(),intersectPoint.y());
	myPath.setElementPositionAt(ec-1,startIntersectPoint.x(),startIntersectPoint.y());

	delete line;
	line=0;

	// need to update intermiediate points due to movement of
	// start and end states.  Calculate net x and y movement
	// for a given state, then divide in two, and move the
	// intermediate points this amount.
	QPointF lastStartPos = m_lastStartPos;
	QPointF lastEndPos = m_lastEndPos;
	QPointF newStartPos = startState->pos();
	QPointF newEndPos = endState->pos();

	// update stored last  start/end positions
	m_lastStartPos = newStartPos;
	m_lastEndPos = newEndPos;

	// calculate relative movement of start/end state - div 2.0
	QPointF chngStartPos = (newStartPos - lastStartPos)/2.0;
	QPointF chngEndPos = (newEndPos - lastEndPos)/2.0;


	// update intermediate points
	for (int i = 1; i < ec - 1; ++i) {
	  QPointF tmpPoint = myPath.elementAt(i);
	  tmpPoint += chngStartPos + chngEndPos;
	  myPath.setElementPositionAt(i,tmpPoint.rx(),tmpPoint.ry());
	}

	QPainterPath::Element e1 = myPath.elementAt(0);
	QPainterPath::Element e2 = myPath.elementAt(1);

	QLineF myLine=QLineF(QPointF(e1.x,e1.y),QPointF(e2.x,e2.y));

	naPath=myPath;
	return myLine;

} 

void GedDesTrans::setTransShape(QList<QPointF> pos)
{
	naPath.moveTo(pos[0]);
	for(int i=1; i<pos.count(); i++){
		naPath.lineTo(pos.at(i));
		QPointF p=pos.at(i);
		//int j=0;
	}
}

void GedDesTrans::setAngle(qreal angle)
{
	currentAngle=angle;
}

void GedDesTrans::restoreDefaultShape()
{

	//it's straight line already
	if (startState == endState)
		if (currentAngle==0) 
			return;
		else{
			currentAngle=0;
			updatePosition();
			setSelected(false);
		}
	else
		if(naPath.elementCount() == 2) 
			return;
		else{
			createLine();
			updatePosition();
			setSelected(false);
		}
}

// This is called by GedDesScene when drawing a line to insert 
// a new trans. This is NOT the same as insertEvent as in this 
// case, we have inserted DesTransition to DES already; this is 
// not the case in insertEvent()
void GedDesTrans::insertDesTrans(const DesTransition* desTrans)
{
	desEventList.append(&desTrans->event());
	updateLabel();
}

void GedDesTrans::setDesEvents(QList<const DesEvent* > events)
{
	QListIterator<const DesEvent* > i(desEventList);
	while (i.hasNext()) {
		deleteEvent(i.next());
	}
	
	QListIterator<const DesEvent* > j(events);
	while (j.hasNext()) {
		insertEvent(j.next());
	}
	updateLabel();
}

bool GedDesTrans::findEvent(const DesEvent *ev)
{
	return desEventList.contains(ev);
}

void GedDesTrans::clearEvents()
{

	QListIterator<const DesEvent* > i(desEventList);
	while (i.hasNext()) {
		deleteEvent(i.next());
	}

	//The item will be deleted from the scene so no updateLable() is needed.
	//updateLabel();
}


// the event must be valid at this point. This two function itself does not verify it
void GedDesTrans::insertEvent(const DesEvent* ev)
{
	const DesState* fromState = startState->getDesState();
	const DesState* toState = endState->getDesState();
	DesTransition *trans = new DesTransition(*fromState,*ev,*toState);
	des->addTransition(*trans);
	desEventList.append(ev);
}

void GedDesTrans::deleteEvent(const DesEvent* ev)
{
	const DesState* fromState = startState->getDesState();
	const DesState* toState = endState->getDesState();
	DesTransition *trans = new DesTransition(*fromState,*ev,*toState);
	des->deleteTransition(*trans);
	desEventList.removeAll(ev);
}

//To support delete event
void GedDesTrans::deleteEventOnly(const DesEvent* ev)
{
	assert(findEvent(ev));
	desEventList.removeAll(ev);
}

void GedDesTrans::updateLabel()
{
	QString text;
	simLabels.clear();
	foreach (const DesEvent *ev, desEventList)
	{
		SimLabel lbl;
		QString  uEventSymbol = "!";

		if (!ev->isControllable())
		{
		  // prepend uncontrollable event names by "!"
		  lbl.text = uEventSymbol + QString::fromStdWString(ev->getName());
		}
		else
		{
		  lbl.text = QString::fromStdWString(ev->getName());	
		}

		//		lbl.text = QString::fromStdWString(ev->getName());
		lbl.color = Qt::black;
		lbl.controllable = false;
		lbl.prev = false;
		lbl.next = false;

		if (m_pEligEvents)
		{
			// Try to mark all eligible events
			std::set<ProjectEvent*>::iterator it = m_pEligEvents->begin();
			for (; it != m_pEligEvents->end(); ++it)
			{
				ProjectEvent* pProjectEvent = *it;
				if (pProjectEvent->findSourceEvent(ev))
				{
					// Found GedEvent in a given transition and it's eligible
					// BH - Comparing against the transition type instead of a 'found' bool, and assuming
					// the sim type is set to a default normal trans value before.  If not, might need to 
					// re-introduce a found bool but outside of the event for loop
					if (simType == PrevSimTrans)
						setSimType(EligiblePrevSimTrans);
					else if (simType != EligiblePrevSimTrans)
						setSimType(EligibleSimTrans);
					lbl.color = Qt::blue;
				}
			}
		}

		// Mark previous event that was used to get to current state
		if (m_pPrevEvent)
		{
			if (m_pPrevEvent->findSourceEvent(ev))
			{
				lbl.prev = true;
				lbl.color = Qt::magenta;

				// BH - Handle if an event in this transition was also an eligible event
				if (simType == EligibleSimTrans || simType == PrevSimTrans)
				{
					setSimType(EligiblePrevSimTrans);
				}
				else if (simType != EligiblePrevSimTrans)
				{
					setSimType(PrevSimTrans);
				}
			}
		}

		// Mark next event that will be taken. Only set in history mode
		if (m_pNextEvent)
		{
			if (m_pNextEvent->findSourceEvent(ev))
			{
				lbl.next = true;
				setSimType(SelectedSimTrans);
			}
		}

		text.append("<div>");

		if (!ev->isControllable())
		{
			lbl.controllable = true;
			text.append("<i>");
			text.append(lbl.text);
			text.append("</i>");
		}
		else
		{
			text.append(lbl.text);
		}
		text.append("</div>");

		simLabels.push_back(lbl);
	}	
	label->setHtml(text);
	label->update();
}


// The position of the transition (no arrow)
const QList<QPointF> GedDesTrans::getPos() const
{
	QList<QPointF> pt_lst;
	
	int cnt = naPath.elementCount();

	for(int i=0; i<cnt; i++){
		const QPainterPath::Element ele = naPath.elementAt(i);
		pt_lst.append(QPointF(ele.x,ele.y));
	}
	return pt_lst;
}

void GedDesTrans::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
	if (!contextMenu) { return; }

    scene()->clearSelection();
    setSelected(true);
    contextMenu->exec(event->screenPos());
}

void GedDesTrans::setLine(const QLineF &ln) 
{ 
	if (line==0) 
		line = new QLineF(ln);
}

void GedDesTrans::setSimType(GedSimType type)
{
	simType = type;
}

//This function is not currently used.
QPainterPath GedDesTrans::selectShape() const
{
	QPainterPath path;
	if (startState == endState)
	{
		 path.addRect(this->boundingRect());
		 return path;
	}

	int ec = naPath.elementCount();

	qreal extra = (pen().width() + 20) / 2.0;


	for (int i = 0; i< ec; i++)  //find which subpath is choosen
		if (naPath.elementAt(i).isLineTo()){
			QLineF cline(naPath.elementAt(i-1).x,naPath.elementAt(i-1).y,
							  naPath.elementAt(i).x,naPath.elementAt(i).y);	
			path.addRect(QRectF(cline.p1(), QSizeF(cline.p2().x() - cline.p1().x(),
                                                   cline.p2().y() - cline.p1().y()))
								.normalized()
								.adjusted(-extra, -extra, extra, extra)
						);
			}

    return path;
} 

QPainterPath GedDesTrans::shape() const
{
	//return this->path();
	//return naPath;
	QPainterPathStroker p;
	//return p.createStroke(naPath);
	p.setWidth(8);
	return p.createStroke(path());

} 
}
