#ifndef PSYS_H
#define PSYS_H

#include "config.h"
#include "ctrl.h"
#include "iset.h"

/* FIXME */
#define MAX_BOUNDARY_PLANES	 256
/* FIXME */
#define MAX_BOUNDARY_SPHERES	256
/* FIXME */
#define MAX_MONITOR_DATA		1024

#define	memAllocVecs(n) ((vec_p)memAllocZ((n) * sizeof(vec_t)))

typedef struct particle_system_s
{
	int		random_seed;
	vhandle_t rhandle;
	char	name[_MAX_PATH];
	char	script_name[_MAX_PATH];
	char	outdir[_MAX_PATH];
	char	tmpname[_MAX_PATH];
	u32_t   num_particles;
	vec_t   *particle_radius;
	vec_t   *particle_density;
	vec_t   *particle_mass;
	vec_t	environment_density;
	vec_t	*particle_mass_delta;
	vec_t   *particle_reciprocal_mass; /* 1/m_j */
	vec_t   *particle_6_pi_eta_r; /* 6 * M_PI * env_eta * r_j */
	matrix_p dist;
	matrix_p surf_dist;
	matrix_p contact;
	u8_p	*connmatrix;
	vboolean tangent_forces; /* take into account tangent forces between particles' shells */
	vec_t	*dglue;
	vboolean percolation;
	vec_t	*percolation_distance;
	vec_t	percolation_ratio; /* ratio 0...1 of particles in percolation frame FIXME */
	vboolean clusters_updated;
	u32_t	num_clusters;
	iset_p	isolated;
	iset_p	*clusters;
	vec_t	hglue;
	u32_t   num_boundary_planes;
	u32_t   num_boundary_spheres;
	
	/* controllers can not be chared between particle systems */
	vp_stack_t float_controllers;
	vp_stack_t vec3_controllers;

	vec4_t  boundary_plane[MAX_BOUNDARY_PLANES];
	float_ctrl_p plane_interaction[MAX_BOUNDARY_PLANES];
	vec_t   plane_interaction_arg[MAX_BOUNDARY_PLANES][MAX_CTRL_ARGS];

	vec4_t  boundary_sphere[MAX_BOUNDARY_SPHERES];
	float_ctrl_p sphere_interaction[MAX_BOUNDARY_PLANES];
	vec_t   sphere_interaction_arg[MAX_BOUNDARY_PLANES][MAX_CTRL_ARGS];

	float_ctrl_p binary_interaction;
	vec_t   binary_interaction_arg[MAX_CTRL_ARGS];
	vec_t	binary_interaction_max_dist;
	vec_t	bskip_ratio; /* percentage of skipped binary interations due to dist >= binary_interaction_max_dist */
	vec_t   env_eta;
	vec3_ctrl_p    env_velocity;
	vec3_ctrl_p    env_velocity_arg[MAX_CTRL_ARGS];
	vec3_ctrl_p unary_force;
	vec_t   unary_force_arg[MAX_CTRL_ARGS];

	vec3_ctrl_p unary_accel;
	vec_t   unary_accel_arg[MAX_CTRL_ARGS];

	vec_t   solution_time_limit;
	vec_t   solution_realtime_limit;
	vec_t   solution_RK_tolerance;
	vec_t	solution_maximal_step;
	vec_t	solution_minimal_step;
	vec_t   solution_RK_timeout;
	vboolean nodraw;
	vboolean output_maxscript;
	vhandle_t kinetics_outfile;
	vhandle_t clusterdump_outfile;
	u32_t	num_nearest; /* for DN statistics */
	u32_t	cuboid_subdiv[3]; /* for NS statistics */
	vec_p	sums; /* for different statistics */
	matrix_p mon_dist; /* for different statistics */
	vp_stack_t monroutines;

	vec_t   *phase; /* positions & velocities of all particles */
	vec_t   cur_time;   /* as processed by ODE solver */
	vhandle_t rt_timer; /* used to measure elapsed time */
	vec_t   *cur_phase; /* as processed by ODE solver */
	u32_t   cur_idx; /* used by controller calls */
	vec3_t  *force; /* used by right-side routine */
	vboolean soft_particles; /* if true, positions may be corrected in compute_binary_dist_r() */
	u32_t	sp_max_recursions;
	vec_t	sp_repulsion_factor;

	vhandle_t ode_solver;
	u32_t   saves_per_second; /* model-time frequency of monitor calls */
	u32_t	shot_count; /* screenshot */
	u32_t	frameshot_count; /* periodic frame shot count: used by shot_periodic */
	u32_t	connmatrix_dump_count;
	u32_t	cluster_dump_count;
	vec_t	ms_global_scale; /* FIXME */
	u32_t	ms_frame_count;

	u32_t   nonview_skips;
	u32_t   nonview_skip_count;
	char	monitor_setup[MAX_MONITOR_DATA]; /* FIXME */
	vboolean (V_CALL *monitor)(struct particle_system_s *ps); /* FIXME */
	vboolean (V_CALL *end_monitoring)(struct particle_system_s *ps); /* FIXME */

	void_p  monitoring_context;
	vboolean (V_CALL *ode_monitor)(void_p arg,vec_t time,vec_t phase[]); /* FIXME */
	void_p  ode_monitor_arg;
	char	initial_filename[_MAX_PATH];
	char	final_filename[_MAX_PATH];
}   particle_system_t, *particle_system_p;

particle_system_p psLoad(vhandle_t lexer,char *target);
void	psFree(particle_system_p ps);

#endif  /* !PSYS_H */
