/*
 * Copyright (C) 2019 CERN (www.cern.ch)
 * Author: Jean-Claude BAU - CERN
 *
 * Released according to the GNU LGPL, version 2.1 or any later version.
 *
 */

#include <string.h>

#include <libwr/wrs-msg.h>
#include <libwr/generic_fsm.h>


static char * fsm_generic_build_events( fsm_t *pfg, int *eventMask );

/* Generic engine used by all ports states machine */
int fsm_generic_run( fsm_t *pfg) {
	int ret=0;
	if ( 1 /*pfg->ps->in_use*/ ) {
       int  eventMask,isNewState;

		char *evtStr=fsm_generic_build_events(pfg, &eventMask);

		pfg->lastEventMask = eventMask;

		isNewState=fsm_has_pending_state(pfg);

		/* Check if state has changed */
		if ( isNewState ) {
			fsm_consume_state(pfg); // update the current state with the scheduled one
		}

//		printf("ps i %d newstate %d pmask %x state_idx %d gs %d\n", pfg->ps->hw_index, isNewState, eventMask, pfg->pt->state, _getState(pfg));
		/* Call state entry */
		if (eventMask || isNewState) {
			fsm_state_table_entry_t *pt;;
			
			for( pt = pfg->state_table; pt->state >= 0; pt++)
			{
				if (pt->state == fsm_get_state(pfg) ) {
/*					if ( FSM_GEN_DEBUG  && pt->fctName!=NULL)
						printf("%s:  Calling %s (newState=%d, evts=%s),\n",
								pfg->fsm_name,
								pt->fctName, isNewState,evtStr);*/
					ret= (*pt->handler)(pfg,eventMask,isNewState);
					if ( fsm_has_pending_state(pfg) ) {
						/* Consume state immediately */
						return fsm_generic_run(pfg);
					}
					break;
				}
			}
		}
	}
	return ret;
}

static char * fsm_generic_build_events( fsm_t *pfg, int *eventMask) 
{
	*eventMask=0;

//	printf("************call genbuildedvents\n");

	if ( pfg->build_events_handler )
		*eventMask=(*pfg->build_events_handler)(pfg);
	if ( FSM_GEN_DEBUG ) {
		static char str[128];
		int copy=*eventMask;


		fsm_event_table_entry_t *pe;

		str[0]=0;

		for( pe = pfg->event_table; pe->evtMask > 0; pe++)
		{
			if (copy==0) break;
			if ( (pe->evtMask & copy) !=0 ) {
				if ( str[0]!=0)
					strcat(str,"+");
				strcat(str,pe->evtName);
				copy &=~pe->evtMask;
			}
		}
		return str;
	} else {
		static char str[1]="";
		return str;
	}
}

fsm_t fsm_generic_create(
	const char *name,
	fsm_build_event_handler_t build_events_handler,
	fsm_state_table_entry_t *state_table,
	fsm_event_table_entry_t *event_table,
	void *priv)
	{
		fsm_t rv;

		rv.fsm_name = strdup(name);
		rv.event_table = event_table;
		rv.state_table = state_table;
		rv.build_events_handler = build_events_handler;
		rv.enabled = 1;
		rv.priv = priv;
		rv.st.state = -1;
		rv.st.nextState = -1;

		return rv;
	}
