#include <v_lib.h>
#include "config.h"
#include "psdl.h"
#include "util.h"
#include "psys.h"
#include "ctrl.h"
#include "rh_side.h"
#include "monitor.h"
#include "phasesp.h"

vboolean nofilelog = false;

void usage(char *me)
{
	conPrintf("Usage: %s <scriptfile>, where scriptfile is an PSDL script.\n",me);
/*	conPuts("For brief description of PSDL, try --help-psdl.\n"); */
	conPuts("Try --help-controllers | --help-monitors.\n");
}

void help_PSDL(void)
{
	/* TODO */
}

V_LOCAL void
runGoal(particle_system_p ps)
{
	CALLER_NAME(runGoal)
	vec_t step_min, step_max, step_guess;
	if(ps->solution_maximal_step > 0)
		step_max = ps->solution_maximal_step;
	else
		step_max = 1;
	if(ps->solution_minimal_step > 0)
		step_min = ps->solution_minimal_step;
	else
		step_min = step_max * 1e-10;
	step_guess = 0.1 * (step_min + step_max);
	conlPrintf(LOG_INFO, "%s(): minimal allowed step is %g, maximal is %g, initial is %g\n",
		caller_name,step_min,step_max,step_guess);
	ps->ode_solver = odeCreateSolver(ps->num_particles * PHASESPACE_DIM,
		problem_right_side,false);
	if(!ps->ode_solver)
		return;
	if(!monitorInit(ps))
	{
		odeDestroySolver(ps->ode_solver);
		ps->ode_solver = LIBV_INVALID_HANDLE;
		return;
	}
	odeSetMonitor(ps->ode_solver,ps->ode_monitor,
		ps->ode_monitor_arg,(vec_t)1.0 / ps->saves_per_second,true);
	odeSetReal(ps->ode_solver,ODE_TIMEOUT,ps->solution_RK_timeout);
	odeSetReal(ps->ode_solver,ODE_MAXIMAL_STEP,step_max);
	timerStart(ps->rt_timer);
	odeIntegrate(ps->ode_solver,
		ps->phase,
		ps->cur_time,
		ps->solution_time_limit,
		ps->solution_RK_tolerance,
		step_guess, /* estimation for step */
		step_min, /* minimal allowed step */
		ps);
	timerStop(ps->rt_timer);
	monitorShutdown(ps);
	odeDestroySolver(ps->ode_solver);
	ps->ode_solver = LIBV_INVALID_HANDLE;
}

int main(int argc, char *argv[])
{
	CALLER_NAME(main)
	int i;
	size_t leak;
	vboolean nodraw = false;
	char *fname = NULL;
	particle_system_p ps;
	logStartConsoleLog();
	logUpperLevel(LOG_LEVEL);
	conPrintf("%s\n", PSMOD_DESCRIPTION);
	if(argc == 1)
	{
		usage(argv[0]);
		return -1;
	}
	for(i = 1;i < argc;i++)
	{
		if(argv[i][0] == '-' && argv[i][1] == '-')
		{
			if(!strcasecmp(argv[i],"--help"))
			{
				usage(argv[0]);
				return 0;
			}
			if(!strcasecmp(argv[i],"--help-psdl"))
			{
				help_PSDL();
				return 0;
			}
			if(!strcasecmp(argv[i],"--help-controllers"))
			{
				helpControllers();
				return 0;
			}
			if(!strcasecmp(argv[i],"--help-monitors"))
			{
				listMonitorRoutines();
				return 0;
			}
			if(!strcasecmp(argv[i],"--nodraw"))
			{
				nodraw = true;
				continue;
			}
			if(!strcasecmp(argv[i],"--nofilelog"))
			{
				nofilelog = true;
				continue;
			}
			conlPrintf(LOG_WARNING,"%s(): unknown option \"%s\"\n", caller_name, argv[i]);
		}
		else
		{
			if(fname)
				conlPrintf(LOG_WARNING,"%s(): extra file name given: \"%s\", ignoring \"%s\".\n",
					caller_name,
					argv[i], fname);
			fname = argv[i];
		}
	}
	if(!fname)
	{
		conlPrintf(LOG_ERROR,"main(): no file name given.\n");
		return -1;
	}
	ps = parse_psdl_script(fname);
	if(ps)
	{
		ps->nodraw = nodraw;
		runGoal(ps);
		psFree(ps);
	}
	else
		conlPrintf(LOG_ERROR,"main(): error parsing '%s'\n",fname);
	if(!nofilelog)
		logStopFileLog();
	logUpperLevel(LOG_TRACE);
	/*
	memStats(&leak,NULL,NULL);
	printf("psmod run completed: leak %u byte(s).\n", (u32_t)leak);
	*/
	memPrintObjStats();
	memPrintMemStats();
	
	logStopConsoleLog();
	return 0;
}
