#include "psmod.h"

#define	DEBUG_INPUT	"test.psdl"
#define	LOG_LEVEL	LOG_INFO

static char	*running_script_name = "NUL";
static char	*phase_component_names[PHASESPACE_COMPONENTS] = {"position","velocity"};

static vboolean
psmodSimulate(particle_system_p ps)
{
	CALLER_NAME(psmodSimulate)
	vboolean integration_result;
	solver_stage_p stage = &ps->solver.current_stage;
	solver_p solver = &ps->solver;
	if(!fifoCount(&solver->stages))
	{
		ERROR_GENERIC("no solver stages defined");
		return false;
	}
	solver->solver_handle = odeCreateSolver(
		PHASESPACE_DIM * stackCount(&ps->particles),
		solver->right_side,solver->verbose);
	if(solver->solver_handle == LIBV_INVALID_HANDLE)
	{
		ERROR_GENERIC("error creating ODE solver");
		return false;
	}
	while(fifoPop(&solver->stages,&stage))
	{
		if(solver->current_time >= stage->upper_time)
		{
			ERROR_INVALID_FLOAT("stage->upper_time",stage->upper_time);
			return false;
		}
		/* FIXME odeSetTimeout(solver->solver_handle,stage->RK_timeout); */
		assert(0);
		if(stage->load_file[0])
		{
			if(!phaseLoad(stage->load_file,running_script_name,
				&solver->current_time,ps->phase,
				PHASESPACE_COMPONENTS,stackCount(&ps->particles),
				phase_component_names))
			{
				ERROR_INVALID_STR("error loading phase from",stage->load_file);
				return false;
			}
		}
		if(!stage->monitor_cps)
		{
			WARNING_GENERIC("zero 'monitor_cps'");
			return false; // fixme
		}
		else
		{
			odeSetMonitor(solver->solver_handle,solver->main_monitor_routine,
				ps,(vec_t)1.0 / stage->monitor_cps,
				stage->exact_monitoring);
		}
		timerStart(solver->rt_timer);
		integration_result = odeIntegrate(solver->solver_handle,
			ps->phase,
			solver->current_time,
			stage->upper_time,
			stage->RK_tolerance,
			stage->initial_step,
			stage->minimal_step,ps);
		timerStop(solver->rt_timer);
		if(stage->save_file[0])
		{
			if(!phaseSave(stage->save_file,running_script_name,
				solver->current_time,ps->phase,
				PHASESPACE_COMPONENTS,
				stackCount(&ps->particles),phase_component_names))
			{
				ERROR_INVALID_STR("error saving phase to",stage->save_file);
				return false;
			}
		}
		if(!integration_result)
			break;
	}
	if(!integration_result)
	{
		/* integration terminated ??? fixme */
	}
	return true;
}

#ifndef DEBUG_INPUT
static int _main(int argc, char *argv[])
{
#else	/* DEBUG_INPUT */
static int _main(void)
{
	CALLER_NAME(main)
	int argc=2;
	char *argv[]={"psmod",DEBUG_INPUT};
#endif	/* DEBUG_INPUT */
	vboolean result;
	particle_system_p ps;
	logStartConsoleLog();
	logUpperLevel(LOG_LEVEL);
	if(argc != 2)
	{
		psdlHelp(argv[0],"--help");
		return -1;
	}
	if(!strncasecmp(argv[1],"--help",6))
		return psdlHelp(argv[0],argv[1]);
	ps = psAlloc();
	if(!psdlParseScript(argv[1],ps))
	{
		psDestroy(ps);
		ERROR_INVALID_STR("wrong script file",argv[1]);
		return -1;
	}
	running_script_name = argv[1];
	result = psmodSimulate(ps);
	psDestroy(ps);
#ifdef	DEBUG_INPUT	
	memPrintStats();
	memPrintMemStats();
	memPrintObjStats();
#endif	/* DEBUG_INPUT */
	return result ? 0 : -1;
}

extern void icsg_main(void);

int main(void)
{
	logStartConsoleLog();
	logUpperLevel(LOG_TRACE);
	
	/*
	{
		vec3_t res;
		vhandle_t sc = lexParseString("(const [1,2,3])","()[]");
		vec3_controller_p ctl;
		ctl = ctlParseVec3(sc);
		CALL_VEC3_CTL(ctl,NULL,res);
		printf("res: [%g,%g,%g]\n",res[0],res[1],res[2]);
		ctlFree(ctl);
		lexDestroy(sc);
	}
	*/
	
	/*
	{
		char *fnames[] = {"pos","vel"};
		// vec_t phase[12] = {1,2,3,4,5,6,7,8,9,10,11,12};
		// phaseSave("test.phase","somesrc",10,phase,2,2,fnames);
		vec_t phase[12];
		vec_t intime;
		if(phaseLoad("test.phase",NULL,&intime,phase,2,2,fnames))
			phaseSave("dupe.phase","somesrc",intime,phase,2,2,fnames);
	}
	*/
	icsg_main();

	memPrintStats();
	/*
	memPrintMemStats();
	memPrintObjStats();
	*/
	return 0;
}
