/*	Author: Xu Han
	Supervisor: Dr. Ryan Leduc
	

	2010
*/

#include "newSyncAlgo.h"
#include "Des.h"

namespace DESpot
{

const std::wstring newSyncAlgo::cSyncAlgoDesc = L"the new sync Algorithm";
const std::wstring newSyncAlgo::cSyncIntegError = L"Input DES '%ls' is either not valid or not verified to be valid.";

//_________________________________________________________________________________________________


newSyncAlgo::newSyncAlgo(bool checkIntegrity /*= true*/) : DesAlgo(cSyncAlgoDesc)
{
	m_checkDesIntegrity = checkIntegrity;	
	m_integrity=true;

 tranMap=NULL;
 turpleStorage=NULL;
 main_pendinglist=NULL;

}
newSyncAlgo::newSyncAlgo(const Des* des1, const Des* des2, bool checkIntegrity /*= true*/) : DesAlgo(cSyncAlgoDesc)
{
	m_checkDesIntegrity = checkIntegrity;
	addInputDes(des1);
	addInputDes(des2);
	m_integrity=false;

tranMap=NULL;
 turpleStorage=NULL;
 main_pendinglist=NULL;

}
newSyncAlgo::newSyncAlgo(DesProject::DesIteratorPtr desIterator, bool checkIntegrity /*= true*/): DesAlgo(cSyncAlgoDesc)
{
	m_checkDesIntegrity = checkIntegrity;	
	addInputDes(desIterator);
	m_integrity=false;

tranMap=NULL;
 turpleStorage=NULL;
 main_pendinglist=NULL;

}
newSyncAlgo::~newSyncAlgo(void)
{

		if(tranMap!=null)
		{
			delete tranMap;
			tranMap=null;
		}
		if(turpleStorage!=null)
		{
			delete turpleStorage;
			turpleStorage=null;
		}
		if(main_pendinglist!=null)
		{
			delete main_pendinglist;
			main_pendinglist=null;
		}

}

void newSyncAlgo::setIntegrity(bool in_m_integrity)
{
	m_integrity = in_m_integrity;
}

//_________________________________________________________________________________________________

void newSyncAlgo::addInputDes(DesProject::DesIteratorPtr desIterator)
{
	for(desIterator->first(); desIterator->notDone(); desIterator->next())
	{
		addInputDes(&desIterator->currentItem());
	}
}
void newSyncAlgo::addInputDes(const Des* inDes)
{
	//Make sure the same Des is not added twice
	for (unsigned int iDes = 0; iDes < m_inDesSet.size(); ++iDes)
	{
		if (inDes == m_inDesSet[iDes])
		{
			throw EX("A DES with the same name already exists in the list of input DES. Cannot add.")
		}
	}
	m_inDesSet.push_back(inDes);
}
//_________________________________________________________________________________________________

void newSyncAlgo::loadProductDes() //--1
	{
		
		//load ProductTransitionMap
		tranMap= new ProductTransitionMap(m_inDesSet);
        DesNum=tranMap->getDesNum();
		EventNum=tranMap->getEventNum();
        StateMaxNum=tranMap->getStateMaxNum();
        transitionMatrix=tranMap->getTransitionMatrix();

       //load turpleStorage
		turpleStorage=new AlgoTrie(m_inDesSet);
		main_pendinglist=new PendingList(DesNum);

		
	}

void newSyncAlgo::createInitialStateTuple() //--2
	{
		SrcStateTuple tuple(DesNum);
		for(short i=0;i<DesNum;i++)
		{
			const unsigned long long itmp=m_inDesSet[i]->getInitialState().getId().id();
            unsigned long long tmp=itmp;
			tuple[i]=(short)tmp;
		}

	   //put into finishlist
        turpleStorage->insert(&tuple);
       //put into the pending list:
		
		//pendinglistClear();
		//pushPending(&tuple);
		main_pendinglist->PushPending(tuple);

		

	}



//_________________________________________________________________________________________________
void newSyncAlgo::prepareRun()
{
	//startAlgo();

	if (m_inDesSet.size() < 2)
	{
		throw EX("The MEET algorithm requires at least two input DES.");
	}
	if (m_checkDesIntegrity)
	{
		for (unsigned int iDes = 0; iDes < m_inDesSet.size(); ++iDes)
		{
			const Des* crtDes = m_inDesSet[iDes];
			if (crtDes->getIntegrity() != eIntegYes)
			{			
				//throw errorMessage(cSyncIntegError, crtDes->getName());
				throw EX("Either all DES are not valid, or integrity has not yet been checked.");
			}
		}
	}	

	loadProductDes();
    createInitialStateTuple();
	
}

//_________________________________________________________________________________________________

//--------change one---(done)-----------------
bool newSyncAlgo::runAlgo()
{
	//ProgressUpdater updater(m_progress);
	if (m_integrity == false)
	{
		throw EX("Either project is not valid, or integrity \
has not yet been checked.");
		 return false;
	}


	prepareRun();
		
     //----------------------major loop---------------------------
	while(main_pendinglist->isEmpty()==false)
	 {
		  SrcStateTuple crtSrcStateTuple(DesNum);
		  main_pendinglist->PopPending(crtSrcStateTuple);
		  for(short i=1;i<EventNum;i++)
		  { 
			  SrcStateTuple temptuple(DesNum); 
			  for(short j=0;j<DesNum;j++)
			  {
				  short from_state=crtSrcStateTuple[j];
				  short to_state=transitionMatrix[j][i][from_state];
				 
				  if(to_state!=-1)
				  {
					  temptuple[j]=to_state;
				  }
				  else
				  {
					 
					  onEventBlocked(i,crtSrcStateTuple,j);
					  break;
				  }

				  if(j==DesNum-1)
				  {  // at end of the entry; the whole tuple is finished
					 
					  if(turpleStorage->search(&temptuple)==false)
					  {
						  turpleStorage->insert(&temptuple);
						  main_pendinglist->PushPending(temptuple);
					  }
				  }

			  }
		  }
		
		  
	 }
	 //updateProgress();
     //------------------------------------------------------------------------------
		    delete main_pendinglist;
	    main_pendinglist=null;
	return true;
}


void newSyncAlgo::onEventBlocked(short eventId,  SrcStateTuple& srcStateTuple, short iSrc)
{

}


}//End of namespace DESpot

