#include "psmod.h"

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

vboolean
psmodLoadPhase(char *file_name,vec_t *phase,u32_t len)
{
	return icReadFloatFile(file_name,phase,sizeof(vec_t),len);
}

vboolean
psmodSavePhase(char *file_name,vec_t *phase,u32_t len)
{
	return icWriteFloatFile(file_name,phase,sizeof(vec_t),len);
}

vboolean
psmodSimulate(particle_system_p ps)
{
#ifdef	CHECKED_BUILD
	static char *caller = "psmodSimulate";
#endif	/* CHECKED_BUILD */
	u32_t phase_len = stackCount(&ps->particles) * PHASESPACE_DIM;
	vboolean integration_result;
	solver_stage_p stage = &ps->solver.current_stage;
	solver_p solver = &ps->solver;
	if(!fifoCount(&solver->stages))
	{
		ERROR_GENERIC(caller,"no solver stages defined");
		return false;
	}
	solver->solver_handle = odeCreateSolver(
		phase_len,
		solver->right_side,solver->verbose);
	if(solver->solver_handle == LIBV_INVALID_HANDLE)
	{
		ERROR_GENERIC(caller,"error creating ODE solver");
		return false;
	}
	while(fifoPop(&solver->stages,&stage))
	{
		if(solver->current_time >= stage->upper_time)
		{
			ERROR_INVALID_FLOAT(caller,"stage->upper_time",stage->upper_time);
			return false;
		}
		odeSetTimeout(solver->solver_handle,stage->RK_timeout);
		if(stage->load_file[0])
		{
			if(!psmodLoadPhase(stage->load_file,ps->phase,phase_len))
			{
				ERROR_INVALID_STR(caller,"unable to open file",stage->load_file);
				return false;
			}
		}
		if(IsZero(stage->monitor_cps))
		{
			WARNING_GENERIC(caller,"zero 'monitor_cps'");
			return false;
		}
		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(!psmodSavePhase(stage->save_file,ps->phase,phase_len))
			{
				ERROR_INVALID_STR(caller,"unable to save file",stage->save_file);
				return false;
			}
		}
		if(!integration_result)
			break;
	}
	if(!integration_result)
	{
		/* integration terminated */
	}
	return true;
}

#ifndef DEBUG_INPUT
int _main(int argc, char *argv[])
{
#else	/* DEBUG_INPUT */
int _main(void)
{
	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("main","wrong script file",argv[1]);
		return -1;
	}
	result = psmodSimulate(ps);
	psDestroy(ps);
#ifdef	DEBUG_INPUT	
	memPrintStats();
	memPrintMemStats();
	memPrintObjStats();
#endif	/* DEBUG_INPUT */
	return result ? 0 : -1;
}

extern void tmain(void);
void main(void)
{
	logStartConsoleLog();
	logUpperLevel(LOG_TRACE);
	ctlHelp();
	memPrintStats();
	memPrintMemStats();
	memPrintObjStats();
}
