#include <v_lib.h>
#include "rgcache.h"

#ifdef	MATH_NO_MACRO
#error	MATH_NO_MACRO defined. This slows code TWICE.
#endif

#if 0

typedef struct
{
	vec3_t	bbox[2]; /* bounding box */
	vec_t	vf;	/* volumetric content of the fibers */

#endif
	
#define MAXFIB	100000
#define MAXC	(10 * MAXFIB)

/*
 * Size of simulation box
 */
#define BOXEXT	(vec_t)1e-6
vec3_t bbox[2] = {{-BOXEXT,-BOXEXT,-BOXEXT},{BOXEXT,BOXEXT,BOXEXT}};

int		num_fibers = 10000;
vec_t	fiber_len = (vec_t)2e-7;
vec_t	fiber_diameter = (vec_t)2e-9;

vec3_t	fib[MAXFIB][2];

typedef struct fc_info_s
{
	int fn1, fn2;	/* indices of contacting fibers */
	vec_t dist;		/* minimal distance between fibers */
	vec3_t cp;		/* contact point */
}	fc_info_t, *fc_info_p;

int	num_contacts = 0;
fc_info_t fc[MAXC];

static rgcache_p rgc = NULL;

static void
fill_box_with_fibers()
{
	int i;
	vec_t hlen = 0.5f * fiber_len;
	vec3_t fo; /* center of the fiber */
	vec3_t halfdir; /* half of the fiber length */
	rgc = rgcReset(rgc,-BOXEXT,BOXEXT,0,1);
	for(i = 0;i < num_fibers;i++)
	{
		vec3Set(fo,rgcNext(rgc),rgcNext(rgc),rgcNext(rgc));
		ranDirection(rgc->rg,halfdir);
		vec3Scale(halfdir,halfdir,hlen);
		vec3Sub(fib[i][0],fo,halfdir);
		vec3Add(fib[i][1],fo,halfdir);
	}
}

/* volumetric rate of fibers */
static vec_t fiber_vrate()
{
	vec_t fvol, vol;
	vec3_t bs;
	vec3Sub(bs, bbox[1], bbox[0]);
	vol = bs[0] * bs[1] * bs[2];
	fvol = num_fibers * M_PI * fiber_diameter * fiber_diameter * (vec_t)0.25 * fiber_len;
	return fvol / vol;
}

static int
check_for_contacts()
{
	int i, j;
	vec3_t cp;
	vec_t cd;
	num_contacts = 0;
	for(i = 0;i < num_fibers;i++)
		for(j = i + 1;j < num_fibers;j++)
		{
			if(!segCrossing(fib[i][0],fib[i][1],fib[j][0],fib[j][1],&cd,cp))
				continue;
			if(cd > fiber_diameter)
				continue;
			if(num_contacts >= MAXC)
			{
				puts("Too many contacts!");
				return num_contacts;
			}
			fc[num_contacts].fn1 = i;
			fc[num_contacts].fn2 = j;
			fc[num_contacts].dist = cd;
			vec3Copy(fc[num_contacts].cp, cp);
			num_contacts++;
		}
	return num_contacts;
}

int		nums_fibers[] = {/*1000,2000,5000,*/10000/*,20000,50000,100000*/};
vec_t	fiber_lens[] = {(vec_t)50e-9,/*(vec_t)100e-9,*/(vec_t)200e-9};
vec_t	fiber_diameters[] = {(vec_t)1e-9,(vec_t)2e-9,(vec_t)10e-9,(vec_t)20e-9};

void onerun()
{
	char *ptr, buf[1024];
	fill_box_with_fibers();
	check_for_contacts();
	sprintf(buf,"%i;%g;%g;%g;%i",
			num_fibers,
			fiber_len,fiber_diameter,
			fiber_vrate(),
			num_contacts);
	for(ptr = buf;*ptr;ptr++)
		if(*ptr == '.')
			*ptr = ',';
	puts(buf);
	fflush(stdout);
}

void longrun()
{
	int i, j, k;
	int im = sizeof(nums_fibers) / sizeof(int);
	int jm = sizeof(fiber_lens) / sizeof(vec_t);
	int km = sizeof(fiber_diameters) / sizeof(vec_t);
	printf("Starting longrun: %i total iterations\n", im * jm * km);
	for(i = 0;i < im;i++)
	{
		num_fibers = nums_fibers[i];
		assert(num_fibers <= MAXFIB);
		for(j = 0;j < jm;j++)
		{
			fiber_len = fiber_lens[j];
			puts("num_fibers;fiber_len;fiber_diameter;fiber_vrate;num_contacts");
			for(k = 0;k < km;k++)
			{
				fiber_diameter = fiber_diameters[k];
				onerun();
			}
			/* puts("INNER COMPLETE"); */
		}
		/* puts("MID COMPLETE"); */
	}
	/* puts("OUTER COMPLETE"); */
}

int main(int argc, char *argv[])
{
	logStartConsoleLog();
	logUpperLevel(LOG_TRACE);
	longrun();
	rgcDestroy(rgc);
	memPrintStats();
	return 0;
}
