#ifndef PSYS_H
#define PSYS_H

#include "config.h"
#include "ctrl.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)))

#ifndef	STATIC_CLUSTERS

typedef struct iset_s
{
	u32_t	num_elems;
	u32_t	max_elems;
	u8_p	in;
	u32_p	list;
} iset_t, *iset_p;

#endif

typedef struct particle_system_s
{
	int	 random_seed;
	char	script_name[_MAX_PATH];
	char	outdir[_MAX_PATH];
	char	tmpname[_MAX_PATH];
	u32_t   num_particles;
	int		fail_counter;
	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_distance_defined;
	vec_t	*percolation_distance;
	vec_t	percolation_ratio; /* ratio 0...1 of particles in percolation frame FIXME */
#ifndef	STATIC_CLUSTERS
	u32_t	num_clusters;
	iset_p	isolated;
	iset_p	*clusters;
#endif
	vec_t	hglue;
	u32_t   num_boundary_planes;
	u32_t   num_boundary_spheres;
	
	vec4_t  boundary_plane[MAX_BOUNDARY_PLANES];
	float_controller_t plane_interaction[MAX_BOUNDARY_PLANES];
	vec_t   plane_interaction_arg[MAX_BOUNDARY_PLANES][MAX_CTRL_ARGS];

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

	float_controller_t 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_controller_t env_velocity;
	vec_t   env_velocity_arg[MAX_CTRL_ARGS];

	vec3_controller_t unary_force;
	vec_t   unary_force_arg[MAX_CTRL_ARGS];

	vec3_controller_t 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_RK_timeout;
	vboolean nodraw;
	vboolean output_maxscript;
	vhandle_t kinetics_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 */

	vhandle_t ode_solver;
	u32_t   saves_per_second; /* model-time frequency of monitor calls */
	u32_t	shot_count;
	u32_t	connmatrix_dump_count;
	u32_t	cluster_dump_count;
	u32_t	ms_frame_count;
	u32_t   ms_draw_skips; /* FIXME */
	vec_t	ms_global_scale; /* FIXME */
	u32_t   global_skips; /* FIXME */
	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[]);
	void_p  ode_monitor_arg;
	u32_t   step_rejection_count;
	char	initial_filename[_MAX_PATH];
	char	final_filename[_MAX_PATH];
}   particle_system_t, *particle_system_p;

particle_system_p psAlloc(u32_t num_particles);
void psFree(particle_system_p ps);
char_p psMakeOutname(particle_system_p ps,char_p file_ext);

#endif  /* !PSYS_H */
