/*************************************************************************************************
** Project:     FSMGenerator
** Package:     FSMGenerator
** Module:      FSMGenerator::generator
** File:        FSMJavaGenerator.cpp
** Date:        2002.08.01
** Author:      Pavel Bekkerman (chpavel@tx.technion.ac.il)
** Copyright:   Copyright (C) 2002 Pavel Bekkerman
** License:
**              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 of
**              the License, 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; if not, write to the Free Software
**              Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
**
** Contact:     Pavel Bekkerman (chpavel@tx.technion.ac.il)
*************************************************************************************************/

#include "FSMJavaGenerator.h"

using namespace std;

const string STATE_FILE_NAME = "FSMIDStates.java";
const string EVENT_FILE_NAME = "FSMIDEvents.java";
const string TRANS_FILE_NAME = "FSMIDTransitions.java";
const string CALLS_FILE_NAME = "FSMIDCallbacks.java";

#define    FSM_FILE_NAME        (m_fsmDb.Name()+".java")

// ********************************************************************* FSMJavaGenerator

// *********************************************** Constructor
FSMGenerator::FSMJavaGenerator::FSMJavaGenerator(const FSMDB& fsmDb, const string& strPath)
			: FSMFileGenerator(fsmDb,strPath)
{
}

// *********************************************** Destructor

FSMGenerator::FSMJavaGenerator::~FSMJavaGenerator()
{
}

// *********************************************** File Generators

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ _stateFileGenerator

bool
FSMGenerator::FSMJavaGenerator::_stateFileGenerator()const
{
	const string strFileName = m_strDestinationPath+STATE_FILE_NAME;

	ofstream file(strFileName.c_str(),ios::trunc);
	if(!file)
		return false;

	file<<"package "<<m_fsmDb.Name()<<";"<<endl<<endl;

	file<<"/*****************************************"	<<endl
		<<"* Title: FSMIDStates Interface"					<<endl
		<<"* Description: State Enumerator interface."	<<endl
		<<"******************************************/"	<<endl
		<<endl
		<<"// created from configuration file"<<endl
		<<endl
		<<"public interface FSMIDStates"<<endl
		<<'{'<<endl;

	file<<"\tint "<<STATE_PRE<<"\t= 0;\t\t// the NULL State."<<endl;	

	int state;
	for( state = 0; state < m_fsmDb.m_dvStates.size(); ++state )
		file<<"\tint "<<STATE_PRE<<m_fsmDb.m_dvStates[state].Name()<<"\t= "
		    <<m_fsmDb.m_dvStates[state].GetID()<<';'<<endl;	

	file<<'}'<<endl;

	return true;
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ _eventFileGenerator

bool
FSMGenerator::FSMJavaGenerator::_eventFileGenerator()const
{
	
	const string strFileName = m_strDestinationPath+EVENT_FILE_NAME;

	ofstream file(strFileName.c_str(),ios::trunc);
	if(!file)
		return false;

	file<<"package "<<m_fsmDb.Name()<<";"<<endl<<endl;

	file<<"/*****************************************"	<<endl
		<<"* Title: FSMIDEvents Interface"					<<endl
		<<"* Description: Event Enumerator interface."	<<endl
		<<"******************************************/"	<<endl
		<<endl
		<<"// created from configuration file"<<endl
		<<endl
		<<"public interface FSMIDEvents"<<endl
		<<'{'<<endl;

	file<<"\tint "<<EVENT_PRE<<"\t= 0;\t\t// the NULL Event."<<endl;	

	int event;
	for( event = 0; event < m_fsmDb.m_dvEvents.size(); ++event )
		file<<"\tint "<<EVENT_PRE<<m_fsmDb.m_dvEvents[event].Name()<<"\t= "
		    <<m_fsmDb.m_dvEvents[event].GetID()<<';'<<endl;	

	file<<'}'<<endl;
	return true;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ _transFileGenerator

bool
FSMGenerator::FSMJavaGenerator::_transFileGenerator()const
{
	
	const string strFileName = m_strDestinationPath+TRANS_FILE_NAME;

	ofstream file(strFileName.c_str(),ios::trunc);
	if(!file)
		return false;

	file<<"package "<<m_fsmDb.Name()<<";"<<endl<<endl;

	file<<"/**********************************************"	<<endl
		<<"* Title: FSMIDTransitions Interface"				<<endl
		<<"* Description: Transition Enumerator interface."	<<endl
		<<"***********************************************/"<<endl
		<<endl
		<<"// created from configuration file"<<endl
		<<endl
		<<"public interface FSMIDTransitions"<<endl
		<<'{'<<endl;

	file<<"\tint "<<TRANS_PRE<<"\t\t= 0;\t// the NULL Transition."<<endl;	

	for(int trans = 0; trans < m_fsmDb.m_dvTransitions.size(); ++trans)	
		file<<"\tint "<<TRANS_PRE<<m_fsmDb.m_dvTransitions[trans].Name()<<"\t= "
		    <<m_fsmDb.m_dvTransitions[trans].GetID()<<';'<<endl;	

	file<<'}'<<endl;
	return true;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ _callsFileGenerator

bool
FSMGenerator::FSMJavaGenerator::_callsFileGenerator()const
{
	
	const string strFileName = m_strDestinationPath+CALLS_FILE_NAME;

	ofstream file(strFileName.c_str(),ios::trunc);
	if(!file)
		return false;

	file<<"package "<<m_fsmDb.Name()<<";"<<endl<<endl;

	file<<"/********************************************"	<<endl
		<<"* Title: FSMIDCallbacks Interface"					<<endl
		<<"* Description: Callback Enumerator interface."	<<endl
		<<"*********************************************/"	<<endl
		<<endl
		<<"// created from configuration file"<<endl
		<<endl
		<<"public interface FSMIDCallbacks"<<endl
		<<'{'<<endl;

	file<<"\tint "<<CALL_PRE<<"\t= 0;\t\t// the NULL Callback."<<endl;	

	for(int call = 1; call < m_fsmDb.m_dvCallbacks.size(); ++call)	
		file<<"\tint "<<CALL_PRE<<m_fsmDb.m_dvCallbacks[call].Name()<<"\t= "
		    <<m_fsmDb.m_dvCallbacks[call].GetID()<<';'<<endl;	

	file<<'}'<<endl;
	return true;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ _mainFileGenerator

bool
FSMGenerator::FSMJavaGenerator::_mainFileGenerator()const
{
	
	const string strFileName = m_strDestinationPath+FSM_FILE_NAME;

	ofstream file(strFileName.c_str(),ios::trunc);
	if(!file)
		return false;

	file<<"package "<<m_fsmDb.Name()<<";"<<endl<<endl;

	file<<"/******************************************"	<<endl
		<<"* Title: class "<<m_fsmDb.Name()				<<endl
		<<"* Description: The main class of the FSM"	<<endl
		<<"*******************************************/"<<endl
		<<endl
		<<"// created from configuration file"<<endl
		<<endl;

		file<<"import FSMGenerator.*;\n"<<endl;
	// FSM class
		file<<"public class "<<m_fsmDb.Name()<<" implements AbstractFSM"<<endl
		<<'{'<<endl;

	// generate all member functions.
	_mainGetStartStateGenerator		(file);
	file<<endl;
	_mainGetNextIncarnationGenerator(file);
	file<<endl;
	_mainIsFinalStateGenerator		(file);
	file<<endl;
	_mainProcessStateEnterGenerator	(file);
	file<<endl;
	_mainProcessStateExitGenerator	(file);
	file<<endl;
	_mainProcessEventGenerator		(file);
	file<<endl;
	_mainProcessTransitionGenerator	(file);
	file<<endl;
	_mainProcessCallbackGenerator	(file);
	file<<endl;

	// end of FSM class.
	file<<"}\t //class "<<m_fsmDb.Name()<<endl;
	return true;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ _mainGetStartState

void
FSMGenerator::FSMJavaGenerator::_mainGetStartStateGenerator(ofstream& file)const
{
	file<<"\tpublic int _getStartState() throws FSMException\n"
	"\t{\n\t\treturn FSMIDStates.STATE_"<<m_fsmDb.m_dvStates[m_fsmDb.m_indStart].Name()<<";\n"
	"\t}\n";	
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ _mainGetNextIncarnation

void
FSMGenerator::FSMJavaGenerator::_mainGetNextIncarnationGenerator(ofstream& file)const
{
	file<<"\tpublic IDPair _getNextIncarnation( int idState, int idEvent ) throws FSMException\n"
		  "\t{\n"
		  "\t\tIDPair idpair = new IDPair();\n\n"
		  "\t\tswitch( idState )\n"
		  "\t\t{"<<endl;

	int state;
	for( state = 0; state<m_fsmDb.m_dvStates.size(); ++state )
	{
		const State& current = m_fsmDb.m_dvStates[state];
		file<<"\t\t\tcase FSMIDStates.STATE_"<<current.Name()<<":\n";
		file<<"\t\t\t\tswitch( idEvent )\n"
			  "\t\t\t\t{"<<endl;
		list<INDEX>::const_iterator citr;
		for(citr = current.transitions.begin(); citr != current.transitions.end(); ++citr)
		{
			const Transition& trans = m_fsmDb.m_dvTransitions[*citr];
			file<<"\t\t\t\t\tcase FSMIDEvents.EVENT_"<<m_fsmDb.m_dvEvents[trans.WithEvent()].Name()<<":\n"
				  "\t\t\t\t\t\tidpair.idFirst  = FSMIDTransitions.TRANSITION_"<<trans.Name()<<";\n"
				  "\t\t\t\t\t\tidpair.idSecond = FSMIDStates.STATE_"<<m_fsmDb.m_dvStates[trans.ToState()].Name()<<";\n"
			      "\t\t\t\t\tbreak;\n"<<endl;
		}

		file<<"\t\t\t\t\tdefault:\n"
              "\t\t\t\t\t\tthrow new FSMException( \"Illegal event.\" );\n"
			  "\t\t\t\t}\n"
			  "\t\t\tbreak;\n"<<endl;
	}

	file<<"\t\t\tdefault:\n"
          "\t\t\t\tthrow new FSMException( \"Illegal state.\" );\n"
		  "\t\t}\n"<<endl;

	file<<"\t\t return idpair;\n"
		  "\t}\n";
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ _mainIsFinalStateGenerator

void
FSMGenerator::FSMJavaGenerator::_mainIsFinalStateGenerator(ofstream& file)const
{
	file<<"\tpublic boolean _isFinalState( int idState ) throws FSMException\n"
		"\t{\n"
		"\t\tswitch( idState )\n"
		"\t\t{\n";

	int state;
	for( state=0; state < m_fsmDb.m_dvStates.size(); ++state )
		if(m_fsmDb.m_dvStates[state].IsFinal())
			file<<"\t\t\tcase FSMIDStates.STATE_"<<m_fsmDb.m_dvStates[state].Name()<<":\n";
	file<<"\t\t\t\treturn true;\n"<<endl;

	for( state=0; state < m_fsmDb.m_dvStates.size(); ++state )
		if(!m_fsmDb.m_dvStates[state].IsFinal())
			file<<"\t\t\tcase FSMIDStates.STATE_"<<m_fsmDb.m_dvStates[state].Name()<<":\n";
	file<<"\t\t\t\treturn false;\n"<<endl;

	file<<"\t\t\tdefault:\n"
		  "\t\t\t\tthrow new FSMException( \"Illegal state.\" );\n";
	file<<"\t\t}\n"
		  "\t}\n";
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ _mainProcessStateEnterGenerator

void
FSMGenerator::FSMJavaGenerator::_mainProcessStateEnterGenerator(ofstream& file)const
{
	file<<"\tpublic void _processStateEnter( int idState ) throws FSMException\n"
		  "\t{\n"
		  "\t\ttry\n"
		  "\t\t{\n"
		  "\t\t\tswitch( idState )\n"
		  "\t\t\t{\n";

	int state;
	for( state=0; state < m_fsmDb.m_dvStates.size(); ++state )
	{
		const State& current = m_fsmDb.m_dvStates[state];
		file<<"\t\t\t\tcase FSMIDStates.STATE_"<<current.Name()<<":\n"
			  "\t\t\t\t\t_processCallback( FSMIDCallbacks.CALLBACK_"<<m_fsmDb.m_dvCallbacks[current.EnterCall()].Name()<<" );\n"
			  "\t\t\t\tbreak;\n"<<endl;
	}
    file<<"\t\t\t\tdefault:\n"
		  "\t\t\t\t\tthrow new FSMException( \"Illegal state.\" );\n"
		  "\t\t\t}\n"
		  "\t\t}\n"
		  "\t\tcatch( FSMException e )\n"
		  "\t\t{\n"
		  "\t\t\tthrow e;\n"
		  "\t\t}\n"
		  "\t}\n";
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ _mainProcessStateExitGenerator

void
FSMGenerator::FSMJavaGenerator::_mainProcessStateExitGenerator(ofstream& file)const
{
	file<<"\tpublic void _processStateExit( int idState ) throws FSMException\n"
		  "\t{\n"
		  "\t\ttry\n"
		  "\t\t{\n"
		  "\t\t\tswitch( idState )\n"
		  "\t\t\t{\n";

	int state;
	for( state=0; state < m_fsmDb.m_dvStates.size(); ++state )
	{
		const State& current = m_fsmDb.m_dvStates[state];
		file<<"\t\t\t\tcase FSMIDStates.STATE_"<<current.Name()<<":\n"
			  "\t\t\t\t\t_processCallback( FSMIDCallbacks.CALLBACK_"<<m_fsmDb.m_dvCallbacks[current.ExitCall()].Name()<<" );\n"
			  "\t\t\t\tbreak;\n"<<endl;
	}
    file<<"\t\t\t\tdefault:\n"
		  "\t\t\t\t\tthrow new FSMException( \"Illegal state.\" );\n"
		  "\t\t\t}\n"
		  "\t\t}\n"
		  "\t\tcatch( FSMException e )\n"
		  "\t\t{\n"
		  "\t\t\tthrow e;\n"
		  "\t\t}\n"
		  "\t}\n";
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ _mainProcessEventGenerator

void
FSMGenerator::FSMJavaGenerator::_mainProcessEventGenerator(ofstream& file)const
{
	file<<"\tpublic void _processEvent( int idEvent ) throws FSMException\n"
		  "\t{\n"
		  "\t\ttry\n"
		  "\t\t{\n"
		  "\t\t\tswitch( idEvent )\n"
		  "\t\t\t{\n";
	for(int event=0; event < m_fsmDb.m_dvEvents.size(); ++event)
	{
		const Event& current = m_fsmDb.m_dvEvents[event];
		file<<"\t\t\t\tcase FSMIDEvents.EVENT_"<<current.Name()<<":\n"
			  "\t\t\t\t\t_processCallback( FSMIDCallbacks.CALLBACK_"<<m_fsmDb.m_dvCallbacks[current.Callback()].Name()<<" );\n"
			  "\t\t\t\tbreak;\n"<<endl;
	}
    file<<"\t\t\t\tdefault:\n"
		  "\t\t\t\t\tthrow new FSMException( \"Illegal event.\" );\n"
		  "\t\t\t}\n"
		  "\t\t}\n"
		  "\t\tcatch( FSMException e )\n"
		  "\t\t{\n"
		  "\t\t\tthrow e;\n"
		  "\t\t}\n"
		  "\t}\n";
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ _mainProcessTransitionGenerator

void
FSMGenerator::FSMJavaGenerator::_mainProcessTransitionGenerator(ofstream& file)const
{
	file<<"\tpublic void _processTransition( int idTransition ) throws FSMException\n"
		  "\t{\n"
		  "\t\ttry\n"
		  "\t\t{\n"
		  "\t\t\tswitch( idTransition )\n"
		  "\t\t\t{\n";
	for(int trans=0; trans < m_fsmDb.m_dvTransitions.size(); ++trans)
	{
		const Transition& current = m_fsmDb.m_dvTransitions[trans];
		file<<"\t\t\t\tcase FSMIDTransitions.TRANSITION_"<<current.Name()<<":\n"
			  "\t\t\t\t\t_processCallback( FSMIDCallbacks.CALLBACK_"<<m_fsmDb.m_dvCallbacks[current.Callback()].Name()<<" );\n"
			  "\t\t\t\tbreak;\n"<<endl;
	}
    file<<"\t\t\t\tdefault:\n"
		  "\t\t\t\t\tthrow new FSMException( \"Illegal transition.\" );\n"
		  "\t\t\t}\n"
		  "\t\t}\n"
		  "\t\tcatch( FSMException e )\n"
		  "\t\t{\n"
		  "\t\t\tthrow e;\n"
		  "\t\t}\n"
		  "\t}\n";
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ _mainProcessCallbackGenerator

void
FSMGenerator::FSMJavaGenerator::_mainProcessCallbackGenerator(ofstream& file)const
{
	file<<"\tpublic void _processCallback( int idCallback ) throws FSMException\n"
		  "\t{\n"
		  "\t\tswitch( idCallback )\n"
		  "\t\t{\n";

	// add the case for the 'empty' callback.
	file<<"\t\t\tcase FSMIDCallbacks.CALLBACK_:\n"
		  "\t\t\t\t// The 'NULL' callback - nothing to be done.\n"
		  "\t\t\tbreak;\n"<<endl;


	for(int call=1; call < m_fsmDb.m_dvCallbacks.size(); ++call) // skip the 1st 'empty'.
	{
		const Callback& current = m_fsmDb.m_dvCallbacks[call];
		file<<"\t\t\tcase FSMIDCallbacks.CALLBACK_"<<current.Name()<<":\n"
			  "\t\t\t\t"<<current.Function()<<"();\n"
			  "\t\t\tbreak;\n"<<endl;
	}

	file<<"\t\t\tdefault:\n"
          "\t\t\t\tthrow new FSMException( \"Illegal callback.\" );\n"
		  "\t\t}\n"
		  "\t\treturn;\n"
		  "\t}\n";
}

