#include "TuringMachine.h"
#include "ListFuns.h"

const int DEBUGTM = 1;

//************  TuringMachineState   **************************
TuringMachineState::TuringMachineState(Boolean isFinal, unsigned int serNum)
:	_neighbors(),
	_isFinal(isFinal),	
	_serialNumber(serNum)
{ 
}

/*
TuringMachineState::TuringMachineState(const TuringMachineState &d)
:	_isFinal(d._isFinal),
	_neighbors(d._neighbors),
	_serialNumber(d._serialNumber)
{
}

TuringMachineState::~TuringMachineState()
{	// nothing;
}

TuringMachineState & TuringMachineState::operator =(TuringMachineState &d)
{	if(this != &d)
	{	_isFinal = d._isFinal;
		_neighbors = d._neighbors;
		_serialNumber = d._serialNumber;
	}
	return *this;
}
*/

void TuringMachineState::run(String tape, unsigned int head)
{	if(DEBUGTM) cout << "node " <<_serialNumber << " tape "<< tape <<endl;
	if(_isFinal)
		cout <<"Finished: " << tape <<"\n";
	else 
	{	transition nbrInfo;
		if(_neighbors.at(tape[head], nbrInfo))
		{	tape[head] = nbrInfo.symbol;
			if (nbrInfo.which == rightMove) head++;
			else if(nbrInfo.which == leftMove) head--;
			if (head < 0 || head >= tape.length())
				userERROR ("Turing Machine tape error.");
			nbrInfo.to->run(tape, head);
		}
		else
			cout << "No transition. Error. \n";
	}
}

void TuringMachineState::addNeighbor
(	char on, 
	TuringMachineState * to, 
	tapeMove d , 
	char symbol
)
{	transition result;
	result.to = to;
	result.which = d;
	result.symbol = symbol;
	_neighbors.atPut(on,result);
}


//************  TuringMachine   **************************
TuringMachine::TuringMachine()
:	_initial(NULL),
	_nodes(0),
	_nodeList()
{
}

TuringMachine::TuringMachine(const TuringMachine &d){ copy(d); }

TuringMachine::~TuringMachine(){ free(); }

TuringMachine & TuringMachine::operator =(const TuringMachine &d)
{	if(this != &d)
	{	free();
		copy(d);
	}
	return *this;
}

TuringMachineState * TuringMachine::newNode(Boolean isFinal)
{	TuringMachineState *result = new TuringMachineState(isFinal,_nodes++);
	if(_initial == NULL) _initial = result;
	_nodeList = _nodeList.consElement(result);
	return result;
}

void TuringMachine::run(String tape)
{	_initial->run(tape, 0);
}


ostream& operator <<(ostream& out, TuringMachineState * )
{	out << "a TuringMachineState";
	return out;
}

ostream& operator <<(ostream& out, transition * )
{	out << "a Transition";
	return out;
}

void TuringMachine::free() // Delete all of the nodes. 
{	while(!_nodeList.empty())
	{	TuringMachineState * n = _nodeList.head();
		_nodeList = _nodeList.tail();
		delete n;
	}
	_initial = NULL;
}

void TuringMachine::copy(const TuringMachine & D)
{	if(! D._nodeList.empty())
	{	_initial = insertAll(_nodeList, D._nodeList);
	}
}


