///////////////////////////////////////////////////////////////////////////////
//                                                         
// FSM.cc
// ------
// Dragon final state machine implementation module
//                                                         
// Design and Implementation by Bjoern Lemke               
//                                                         
// (C)opyright 2007 by Bjoern Lemke
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; see the file COPYING.  If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
//
// IMPLEMENTATION MODULE
//
// Class: FSM
// 
// Description: implementation of a final state machine for lexical analysis
//
///////////////////////////////////////////////////////////////////////////////

// BASE INCLUDES
#include <lfc/Chain.h>
#include <lfc/ListT.h>

// DRAGON INCLUDES

#include "FSM.h"

/////////////////////////////////
// FSM Class Implementation //
/////////////////////////////////

FSM::EpsilonClosureMap::EpsilonClosureMap()
{
}

FSM::EpsilonClosureMap::EpsilonClosureMap(unsigned long state)
{
    _state = state;
}

FSM::EpsilonClosureMap::EpsilonClosureMap(unsigned long state, SetT<unsigned long>& closure)
{
    _state = state;
    _closure = closure;
    
}
      
FSM::EpsilonClosureMap  FSM::EpsilonClosureMap::operator = (const FSM::EpsilonClosureMap& m)
{
    _state = m._state;
    _closure = m._closure;
    return(*this);
}

bool FSM::EpsilonClosureMap::operator == (FSM::EpsilonClosureMap m)
{
    if (_state == m._state)
	return true;
    return false;
}

bool FSM::EpsilonClosureMap::operator < (FSM::EpsilonClosureMap m)
{
    if (_state < m._state)
	return true;
    return false;
}

bool FSM::EpsilonClosureMap::operator > (FSM::EpsilonClosureMap m)
{
    if (_state > m._state)
	return true;
    return false;
}

long FSM::EpsilonClosureMap::getState()
{
    return _state;
}

SetT<unsigned long>& FSM::EpsilonClosureMap::getClosure()
{
    return _closure;
}

FSM::FSM(TreeT<FSMState> * pStateTable, TreeT<FSMTransition> *pTransitionTable)
{
    _pStateTable = pStateTable;
    _pTransitionTable = pTransitionTable;
}

FSM::~FSM()
{
}

void FSM::epsilonFree()
{

    TreeT<EpsilonClosureMap> map;
    SetT<unsigned long> closureSet;

    unsigned long startState;

    TreeT<FSMTransition> tmpTransitionTable;

    FSMState *pState = _pStateTable->First();
    while (pState)
    {
	if (pState->Type() == START)
	    startState = pState->Num();

	SetT<unsigned long> closureSet;
	buildEpsilonClosure(pState->Num(), closureSet);
	EpsilonClosureMap c(pState->Num(), closureSet);
	map.Insert(c);
	pState = _pStateTable->Next();
    }

    FSMTransition *pTrans = _pTransitionTable->First();

    while (pTrans)
    {
	FSMState *pState = _pStateTable->First();
	while (pState)
	{
	    EpsilonClosureMap *pMap = map.Find(EpsilonClosureMap(pState->Num()));
	    
	    if (pMap)
	    {

		if (pMap->getClosure().Find(pTrans->Source()) && pTrans->Sign() != EPSILON )
		{
		    tmpTransitionTable.Insert(FSMTransition(pState->Num(),
							    pTrans->Target(),
							    pTrans->Sign()));
		}
	    }
	    pState = _pStateTable->Next();
	}
	pTrans = _pTransitionTable->Next();
	
    }


    TreeT<FSMState> newStateTable;
    TreeT<FSMTransition> newTransTable;

    // build up new state table


    EpsilonClosureMap *pMap = map.First();
    while (pMap)
    {

        SetT<unsigned long> c = pMap->getClosure();
	
	StateType stateType = NONE;
	Chain token;

	// find out new state type

	unsigned long *pCS = c.First();
	while (pCS)
	{
	    FSMState *pState = _pStateTable->First();
	    while (pState)
	    {
		if ( pState->Num() == *pCS )
		{

		    if (pMap->getState() == startState)
		    {
			switch (pState->Type())
			{
			case START:
			    if (stateType == NONE)
				stateType = START;
			    else if (stateType == FINAL)
				stateType = ANY;
			    break;
			case FINAL:
			    if (stateType == NONE)
				stateType = FINAL;
			    else if (stateType == START)
				stateType = ANY;
			    // token=Chain(pState->Token());
			    break;		       
			case ANY:
			  stateType = ANY;
			  // token=Chain(pState->Token());
			    break;
			case NONE:
			    break;
			}      
		    } 
		    else
		    {
			switch (pState->Type())
			{
			case FINAL:
			    stateType = FINAL;
			    // token=Chain(pState->Token());
			    break;
			case ANY:
			    stateType = FINAL;
			    // token=Chain(pState->Token());
			    break;
			case NONE:
			    break;
			case START:
			    break;
			}
		    }
		}

		pState = _pStateTable->Next();		
	    }

	    // insert new state
	    	    	    
	    pCS = c.Next();	    
	}


	newStateTable.Insert(FSMState(pMap->getState(), stateType, token));    

	pMap = map.Next();    
    }
   

    // build up new trans table
    
    SetT<unsigned long> todoStateSet;
    
    pState = _pStateTable->First();
    while (pState)
    {
	if (pState->Type() == START || pState->Type() == ANY)
	{
	    todoStateSet.Insert(pState->Num());
	    
	}
	pState = _pStateTable->Next();
    }
    

    SetT<unsigned long> doneStateSet;

    while ( ! todoStateSet.isEmpty())
    {

	unsigned long *pS = todoStateSet.First();
	if (pS)
	{
	    FSMTransition *pTrans = tmpTransitionTable.First();
	    while (pTrans)
	    {
		if (*pS == pTrans->Source())
		{
		    newTransTable.Insert(FSMTransition(pTrans->Source(), 
						       pTrans->Target(),
						       pTrans->Sign()));
		    
		    if (doneStateSet.Find(pTrans->Target()) == 0)
			todoStateSet.Insert(pTrans->Target());
		}
		pTrans = tmpTransitionTable.Next();
		
	    }
	}

	doneStateSet.Insert(*pS);
	todoStateSet.Remove(*pS);

    }
    
    _pStateTable->Empty();
    _pTransitionTable->Empty();
    
    // copy new tables

    // native copy of transitions

    pTrans = newTransTable.First();
    while (pTrans)
    {
	_pTransitionTable->Insert(*pTrans);
	pTrans = newTransTable.Next();
    }
    
    // check out reachable states during state table copy

    pState = newStateTable.First();
    while (pState)
    {
	pTrans = _pTransitionTable->First();
	bool notFound = true;
	while (pTrans && notFound)
	{
	    if (pTrans->Source() == pState->Num()
		|| pTrans->Target() == pState->Num())
	    {
	      _pStateTable->Insert(*pState);
		notFound = false;
	    }
	    pTrans = _pTransitionTable->Next();
	}
	pState = newStateTable.Next();	
    }
    
}

void FSM::buildEpsilonClosure(unsigned long state, SetT<unsigned long>& closureSet )
{

    closureSet.Insert(state);

    FSMTransition *pTrans = _pTransitionTable->First();
    while (pTrans)
    {
	void* treePointer = _pTransitionTable->getTreePointer();

	if (pTrans->Source() == state && pTrans->Sign() == EPSILON)
	{
	    closureSet.Insert(pTrans->Target());
	    SetT<unsigned long> tmpClosureSet;
	    
	    buildEpsilonClosure(pTrans->Target(), tmpClosureSet);
	    closureSet = closureSet + tmpClosureSet;
	}
	_pTransitionTable->setTreePointer(treePointer);
	pTrans = _pTransitionTable->Next();
    }
}


void FSM::invert()
{

    FSMState* pState = _pStateTable->First();
    while (pState)
    {

	if (pState->Type() == START)
	{
	    pState->setType(FINAL);
	} 
	else if (pState->Type() == FINAL)
	{
	    pState->setType(START);
	}



	pState = _pStateTable->Next();
    }    

    FSMTransition* pTrans = _pTransitionTable->First();
    while (pTrans)
    {	
	unsigned long swpNum = pTrans->Source();
	
	pTrans->setSource(pTrans->Target());	
	pTrans->setTarget(swpNum);	
	
	pTrans = _pTransitionTable->Next();
    }
    
}

void FSM::determinate()
{
    
    TreeT<char> signSet;
    FSMTransition* pTrans = _pTransitionTable->First();
    while (pTrans) 
    {	
	
	signSet.Insert(pTrans->Sign());	
	
	pTrans = _pTransitionTable->Next();
    }

    TreeT<FSMState> startStateSet;

    FSMState *pState = _pStateTable->First();
    while (pState)
    {
	if (pState->Type() == START || pState->Type() == ANY)
	{
	    startStateSet.Insert(*pState);
	}
	pState = _pStateTable->Next();
    }

    TreeT<PowerState> powerStateSet;
    TreeT<PowerTransition> powerTransTable;

    TreeT< TreeT<FSMState> > todoSet;
    TreeT< TreeT<FSMState> > doneSet;
    todoSet.Insert(startStateSet);
    
    while ( ! todoSet.isEmpty() )
    {

	TreeT<FSMState>* pSourceStateSet = todoSet.First();

	char* pSign = signSet.First();
	
	while (pSign)
	{

	    TreeT<FSMState> targetStateSet;

	    FSMState* pState = pSourceStateSet->First();
	    while (pState)
	    {
		
		FSMTransition *pTrans =  _pTransitionTable->First();
		while (pTrans)
		{
		    if (pTrans->Source() == pState->Num()
			&& pTrans->Sign() == *pSign)

		    {		
			FSMState *pTarget = _pStateTable->Find(FSMState(pTrans->Target()));
			if (pTarget)
			{
			    targetStateSet.Insert(*pTarget);
			}
		    }
		    pTrans = _pTransitionTable->Next();
		}
		pState = pSourceStateSet->Next();
	    }
	    
	    // insert new transition
	  
	    if (! targetStateSet.isEmpty())
	    {
		PowerTransition p( *pSourceStateSet, targetStateSet, *pSign);


		powerTransTable.Insert(p);
		
		if (! doneSet.Find(targetStateSet))
		{
		    todoSet.Insert(targetStateSet);
		}

	    }
	    pSign = signSet.Next();
	}
	doneSet.Insert(*pSourceStateSet);
	todoSet.Remove(*pSourceStateSet);
    }

    
    unsigned long nextId=0;
    PowerTransition *pPT = powerTransTable.First();
    while (pPT)
    {
	PowerState s(pPT->getSource(), nextId, NONE);
	
	if ( powerStateSet.Insert(s) )
	    nextId++;

	PowerState t(pPT->getTarget(), nextId, NONE);
	
	if ( powerStateSet.Insert(t) )
	    nextId++;
	
	pPT = powerTransTable.Next();
    }    
    
    PowerState *pPS = powerStateSet.First();

    while (pPS)
    {
	
	StateType stateType = NONE;
	Chain token;

	if ( startStateSet == (TreeT<FSMState>)pPS->getStateSet() )
	{
	    FSMState *pState = pPS->getStateSet().First();
	    while (pState)
	    {
		switch (pState->Type())
		{
		case ANY:
		    stateType = ANY;
		    token = pState->Token();
		    break;
		case START:
		    if (stateType == NONE)
			stateType = START;
		    else if (stateType == FINAL)		   
			stateType = ANY;		 
		    break;
		case FINAL:
		    if (stateType == NONE)
			stateType = FINAL;
		    else if (stateType == START)
			stateType = ANY;
		    token = pState->Token();
		    break;
		default:
		    break;
		}
		pState = pPS->getStateSet().Next();
	    }
	}
	else
	{
	    FSMState *pState = pPS->getStateSet().First();
	    while (pState)
	    {
		switch (pState->Type())
		{
		case FINAL:
		    stateType = FINAL;
		    token = pState->Token();
		    break;
		case ANY:
		    stateType = FINAL;
		    token = pState->Token();
		    break;		    
		default:
		    break;
		}
		pState = pPS->getStateSet().Next();
	    }
	}
	
	pPS->setType(stateType);
	pPS->setToken(token);
	
	pPS = powerStateSet.Next();
    }

    // build up origin tables

    _pStateTable->Empty();
    _pTransitionTable->Empty();

    pPS = powerStateSet.First();
    while (pPS)
    {
	FSMState s(pPS->getId(), pPS->getType(), pPS->getToken());
	_pStateTable->Insert(s);
	pPS = powerStateSet.Next();
    }


    pPT = powerTransTable.First();
    while (pPT)
    {
	PowerState *pS = powerStateSet.Find(PowerState(pPT->getSource()));
	PowerState *pT = powerStateSet.Find(PowerState(pPT->getTarget()));
	if (pS && pT)
	{
	    _pTransitionTable->Insert(FSMTransition(pS->getId(), 
						    pT->getId(), 
						    pPT->getSign()));
	}	
	pPT = powerTransTable.Next();
    }
}

unsigned long FSM::States()
{
    return _pStateTable->Size(); 
}

unsigned long FSM::Transitions()
{
    return _pTransitionTable->Size(); 
}

void FSM::printFsm()
{
    
    cout << "StateTable:" << endl;
    cout << "-----------" << endl;
    cout << "Num Type" << endl;
    
    FSMState* pState = _pStateTable->First();
    while (pState)
    {
	cout.width(3);
	cout << pState->Num() << " ";
	cout.width(5);
	switch (pState->Type())
	{
	case START:
	    cout << "START" << " ";	    
	    break;	   
	case FINAL:
	  cout << "FINAL" << "(" << pState->Token() << ")";
	    break;	    
	case ANY:
	    cout << "ANY" << "(" << pState->Token() << ")";
	    break;	    
	case NONE:
	    cout << "NONE" << " ";	    
	    break;	    
	}
	cout << endl;
	pState = _pStateTable->Next();	
    }

    
    cout << "TransitionTable:" << endl;
    cout << "----------------" << endl;
    cout << "Source Target Sign" << endl;
    
    FSMTransition* pTransition = _pTransitionTable->First();
    while (pTransition)    {
	cout.width(6);
	cout << pTransition->Source() << " ";
	cout.width(6);
	cout << pTransition->Target() << " ";
	cout.width(4);
	if (pTransition->Sign() == EPSILON)
	    cout << "EPL" << " ";
	else
	    cout << pTransition->Sign() << " ";
	cout << endl;

	pTransition = _pTransitionTable->Next();
    }

}



/////////////////////////////
// PowerState Methods //
////////////////////////////
    
FSM::PowerState::PowerState()
{
}

FSM::PowerState::~PowerState()
{
}
 
FSM::PowerState::PowerState(const TreeT<FSMState> &stateSet)
{
    _stateSet = stateSet;
}
   
FSM::PowerState::PowerState(const TreeT<FSMState> &stateSet, unsigned long id, StateType type)
{
    _stateSet = stateSet;
    _id = id;
    _type = type;
}

FSM::PowerState::PowerState(const FSM::PowerState& p)
{
    _stateSet = p._stateSet;
    _id = p._id;
    _type = p._type;
}

    
FSM::PowerState& FSM::PowerState::operator = (const FSM::PowerState& p)
{
    _stateSet = p._stateSet;
     _id = p._id;
     _type = p._type;
    return (*this);    
}

bool FSM::PowerState::operator == (FSM::PowerState p)
{
    if ( _stateSet == p._stateSet )
    {
	return true;
    }
    return false;    
}


bool FSM::PowerState::operator < (FSM::PowerState p)
{
    if ( _stateSet < p._stateSet )
    {
	return true;
    }
    return false;    
}

bool FSM::PowerState::operator > (FSM::PowerState p)
{
    if ( _stateSet > p._stateSet )
    {
	return true;
    }
    return false;    
}

void FSM::PowerState::setType(StateType type)
{
    _type = type;
}

void FSM::PowerState::setToken(const Chain& token)
{
    _token = token;
}

TreeT<FSMState>& FSM::PowerState::getStateSet()
{
    return _stateSet;
}

unsigned long FSM::PowerState::getId()
{
    return _id;
}

StateType FSM::PowerState::getType()
{
    return _type;
}

const Chain& FSM::PowerState::getToken()
{
    return _token;
}


/////////////////////////////
// PowerTransition Methods //
////////////////////////////
    
FSM::PowerTransition::PowerTransition()
{
}

FSM::PowerTransition::~PowerTransition()
{
}
    
FSM::PowerTransition::PowerTransition(const TreeT<FSMState> &source, const TreeT<FSMState>& target, char sign)
{
    _source = source;
    _target = target;
    _sign = sign;
}

FSM::PowerTransition::PowerTransition(const FSM::PowerTransition& x)
{
    _source = x._source;
    _target = x._target;
    _sign = x._sign;
}

    
FSM::PowerTransition& FSM::PowerTransition::operator = (const FSM::PowerTransition& x)
{
    _source = x._source;
    _target = x._target;
    _sign = x._sign;
    return (*this);    
}

bool FSM::PowerTransition::operator == (FSM::PowerTransition x)
{
    if ( _source == x._source && _target == x._target && _sign == x._sign)
    {
	return true;
    }
    return false;    
}

bool FSM::PowerTransition::operator > (FSM::PowerTransition x)
{
    if ( _source > x._source ) 
    {
	return true;
    } else if ( _source == x._source )
    {
	if ( _target > x._target ) 
	{
	    return true;
	} else if ( _target == x._target )
	{
	    if ( _sign > x._sign )
	    {
		return true;
	    }
	}
    } 

    return false;    
}

bool FSM::PowerTransition::operator < (FSM::PowerTransition x)
{
    if ( _source < x._source ) 
    {
	return true;
    } else if ( _source == x._source )
    {
	if ( _target < x._target ) 
	{
	    return true;
	} else if ( _target == x._target )
	{
	    if ( _sign < x._sign )
	    {
		return true;
	    }
	}
    } 

    return false;    
}


TreeT<FSMState>& FSM::PowerTransition::getSource()
{
    return _source;   
}

TreeT<FSMState>& FSM::PowerTransition::getTarget()
{
    return _target;
}

char FSM::PowerTransition::getSign()
{
    return _sign;
}





