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

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

void
run_simulation(particle_system_p ps)
{
	ps->ode_solver = odeCreateSolver(ps->num_particles * PHASESPACE_DIM,
		problem_right_side,true);
	if(!ps->ode_solver)
		return;
	if(!init_monitoring(ps))
	{
		odeDestroySolver(ps->ode_solver);
		return;
	}
	odeSetMonitor(ps->ode_solver,ps->ode_monitor,
		ps->ode_monitor_arg,(vec_t)1.0 / ps->saves_per_second,true);
	odeSetTimeout(ps->ode_solver,ps->solution_RK_timeout);
	timerStart(ps->rt_timer);
	odeIntegrate(ps->ode_solver,ps->phase,0,ps->solution_time_limit,
		ps->solution_RK_tolerance,1e-4,1e-14,ps);
	timerStop(ps->rt_timer);
	shutdown_monitoring(ps);
	odeDestroySolver(ps->ode_solver);
}

void help_main(char *self)
{
	puts("Particle system simulation program ver. 0.2");
	printf("Usage: %s <scriptfile>, where scriptfile is an PSDL script.\n",
		self);
	puts("For brief description of PSDL, try --help-PSDL.");
	puts("For brief description of controllers, try --help-controllers.");
}

V_LOCAL char *psdl_syntax=
	"# comment\n"
	"random_seed <integer random_seed>\n"
	"number_of_particles <integer>\n"
	"particle_radius <uniform float_min float_max>\n"
	"particle_density <uniform float_min float_max>\n"
	"particle_minimal_distance <float minimal_distance>\n"
	"particle_distribution_domain <sphere <vec3 pos> <float radius>> \\\n"
	"\t| <box <vec3 pos> <vec3 extents>> \\\n"
	"\t| <cylinder <vec3 lower_base_center> <float radius <float height>>\n"
	"boundary <vec3 plane_normal> <float dist> <float_controller signed_scalar_f_for_given_distance>\n"
	"binary_interaction <float_controller unsigned_scalar_f_for_given_distance>\n"
	"environmental_interaction <viscous <ETA> <vec3_controller ENV_V>>\n"
	"unary_force <vec3_controller force>\n"
	"unary_accel <vec3_controller accel>\n"
	"saves_per_second <integer saves_per_second>\n"
	"solution_time_limit <float time_limit>\n"
	"solution_realtime_limit <float realtime_limit>\n"
	"solution_RK_tolerance <float tolerance>\n"
	"solution_RK_timeout <float timeout>\n"
	"[output_psy | output_maxscript]\n\n";

void help_PSDL(void)
{
	fwrite(psdl_syntax,strlen(psdl_syntax),1,stdout);
}

#ifndef DEBUG_INPUT
int main(int argc, char *argv[])
{
#else	/* DEBUG_INPUT */
int main(void)
{
	int argc=2;
	char *argv[]={"main",DEBUG_INPUT};
#endif	/* DEBUG_INPUT */
	particle_system_p ps;

	logStartConsoleLog();
	logUpperLevel(LOG_LEVEL);

	if(argc != 2)
	{
		help_main(argv[0]);
		return -1;
	}
	if(!strcasecmp(argv[1],"--help"))
	{
		help_main(argv[0]);
		return 0;
	}
	if(!strcasecmp(argv[1],"--help-PSDL"))
	{
		help_PSDL();
		return 0;
	}
	if(!strcasecmp(argv[1],"--help-controllers"))
	{
		help_controllers();
		return 0;
	}
	util_init();
	ps = parse_psdl_script(argv[1]);
	if(ps == NULL)
	{
		util_shutdown();
		conlPrintf(LOG_ERROR,"main(): error parsing '%s'\n",argv[1]);
		return -1;
	}
	run_simulation(ps);
	free_particle_system(ps);
	util_shutdown();

#ifdef	DEBUG_INPUT	
	memPrintStats();
	memPrintMemStats();
	memPrintObjStats();
#endif	/* DEBUG_INPUT */

	return 0;
}
