#include <v_lib.h>
#include "config.h"
#include "phasesp.h"
#include "ctrl.h"
#include "psys.h"

/* FIXME */
extern vboolean
psy_save_pos(particle_system_p ps, char *filename, vboolean msform);

V_LOCAL u8_p *connmatAlloc(u32_t size)
{
	u8_p *rows;
	u32_t i;
	rows = (u8_p*)memAllocZ(size * sizeof(u8_p) + size * size);
	rows[0] = (u8_p)(&rows[size]);
	for(i = 1;i < size;i++)
		rows[i] = rows[i-1] + size;
	return rows;
}

#ifndef	STATIC_CLUSTERS

iset_p	isetAlloc(u32_t max_elems)
{
	iset_p iset = (iset_p)memAllocZ(sizeof(iset_t) + max_elems + max_elems * sizeof(u32_t));
	iset->max_elems = max_elems;
	iset->in = (u8_p)(iset + 1);
	iset->list = (u32_p)(&iset->in[max_elems]);
	return iset;
}

iset_p	*isetsAlloc(u32_t size)
{
	u32_t i;
	iset_p *isets = (iset_p*)memAllocZ(size * sizeof(iset_p));
	for(i = 0;i < size;i++)
		isets[i] = isetAlloc(size);
	return isets;
}

void	isetsFree(iset_p *isets)
{
	u32_t i, size = isets[0]->max_elems;
	for(i = 0;i < size;i++)
		memFree(isets[i]);
	memFree(isets);
}

#endif /* STATIC_CLUSTERS */

particle_system_p
psAlloc(u32_t num_particles)
{
	particle_system_p ps = NULL;
	ps = memAllocZ(sizeof(particle_system_t));
	ps->num_particles = num_particles;
	ps->particle_radius = memAllocVecs(num_particles);
	ps->particle_density = memAllocVecs(num_particles);
	ps->particle_mass = memAllocVecs(num_particles);
	ps->particle_mass_delta = memAllocVecs(num_particles);
	ps->particle_reciprocal_mass = memAllocVecs(num_particles);
	ps->particle_6_pi_eta_r = memAllocVecs(num_particles);
	ps->sums = memAllocVecs(num_particles);
	ps->dist = matAlloc(num_particles, num_particles);
	ps->surf_dist = matAlloc(num_particles, num_particles);
	ps->mon_dist = matAlloc(num_particles, num_particles);
	ps->phase = memAllocVecs(num_particles * PHASESPACE_DIM);
	ps->force = (vec3_t*)memAllocZ(num_particles * sizeof(vec3_t));
	ps->tangent_forces = false;
	ps->dglue = memAllocVecs(num_particles);
	ps->percolation_distance = memAllocVecs(num_particles);
	ps->hglue = 0;
	ps->contact = matAlloc(num_particles, num_particles);
	ps->saves_per_second = 10;
	ps->solution_RK_tolerance = 1e-2;
	ps->solution_RK_timeout = 10;
	ps->num_nearest = NUM_NEAREST;
	ps->cuboid_subdiv[0] = CUBOID_SUBDIV_X;
	ps->cuboid_subdiv[1] = CUBOID_SUBDIV_Y;
	ps->cuboid_subdiv[2] = CUBOID_SUBDIV_Z;
	ps->solution_maximal_step = MAXFLOAT;
	ps->binary_interaction_max_dist = MAXFLOAT;
	ps->connmatrix = connmatAlloc(num_particles);
	vpsInit(&ps->monroutines);
	ps->rt_timer = timerCreate();
	strCopy(ps->script_name,"[null]",_MAX_PATH);
#ifndef	STATIC_CLUSTERS
	ps->isolated = isetAlloc(num_particles);
	ps->clusters = isetsAlloc(num_particles);
#endif
	return ps;
}

void
psFree(particle_system_p ps)
{
	if(!ps)
		return;
	if(ps->final_filename[0])
	{
		char buf1[_MAX_PATH];
		char buf2[_MAX_PATH];
		sprintf(buf1,"%s/final_state/%s.ms",ps->outdir,ps->final_filename);
		sprintf(buf2,"%s/final_state/%s.csv",ps->outdir,ps->final_filename);
#pragma message("BUGBUG ==================== psy_save_pos() call causes sigsegv")
		/*
		psy_save_pos(ps, buf1, true);
		psy_save_pos(ps, buf2, false);
		*/
	}
	if(LIBV_INVALID_HANDLE != ps->rt_timer)
		timerDestroy(ps->rt_timer);
	if(ps->particle_radius)
		memFree(ps->particle_radius);
	if(ps->particle_density)
		memFree(ps->particle_density);
	if(ps->particle_mass)
		memFree(ps->particle_mass);
	if(ps->particle_mass_delta)
		memFree(ps->particle_mass_delta);
	if(ps->particle_reciprocal_mass)
		memFree(ps->particle_reciprocal_mass);
	if(ps->particle_6_pi_eta_r)
		memFree(ps->particle_6_pi_eta_r);
	if(ps->phase)
		memFree(ps->phase);
	if(ps->dglue)
		memFree(ps->dglue);
	if(ps->percolation_distance)
		memFree(ps->percolation_distance);
	if(ps->force)
		memFree(ps->force);
	if(ps->contact)
		memFree(ps->contact);
	if(ps->dist)
		memFree(ps->dist);
	if(ps->surf_dist)
		memFree(ps->surf_dist);
	if(ps->sums)
		memFree(ps->sums);
	if(ps->mon_dist)
		memFree(ps->mon_dist);
	if(ps->connmatrix)
		memFree(ps->connmatrix);
	vpsClear(&ps->monroutines);
	if(LIBV_INVALID_HANDLE != ps->kinetics_outfile)
		fileClose(ps->kinetics_outfile);
#ifndef	STATIC_CLUSTERS
	memFree(ps->isolated);
	isetsFree(ps->clusters);
#endif
	memFree(ps);
}
