#include <v_lib.h>

static vec_t
get_random(int lower,int upper,vboolean exclude_zero)
{
	static int seed = 0;
	static ran_state_t rg;
	int num, range;
	V_ASSERT(lower <= upper);
	range = upper - lower;
	switch(range)
	{
		case 0:
			return (vec_t)lower;
		case 1:
			if(exclude_zero)
			{
				if(!lower)
					return (vec_t)upper;
				if(!upper)
					return (vec_t)lower;
			}
			break;
		default:
			break;
	}
	if(!seed)
	{
		seed = 1 + timeTickCount();
		ranInitState(&rg, seed);
	}
	range++;
	do
	{
		num = lower + (ranGenerateNext(&rg) % range);
	}	while(exclude_zero && !num);
	return (vec_t)num;
}

#define choose_baseplane()	(int)get_random(0,2,false)

static int lower,upper;

vboolean reject_base(vec3_t base[],vec_t mins)
{
	vec_t s;
	vec3_t ab, ac, cross;
	vec3Sub(ab,base[1],base[0]);
	vec3Sub(ac,base[2],base[0]);
	vec3Cross(cross,ab,ac);
	s=.5f * vec3Abs(cross);
	return s < mins;
}

void generate_base(vec3_t dest[],int baseplane)
{
	int i, i1, i2;
	vec_t baseheight, len=(vec_t)(upper - lower);
	vec_t mins=len * len / 3;
	i1 = (baseplane + 1)%3;
	i2 = (baseplane + 2)%3;
	baseheight = get_random(lower,upper,true);
	do
	{
		for(i = 0;i < 3;i++)
		{
			dest[i][i1] = get_random(lower,upper,false);
			dest[i][i2] = get_random(lower,upper,false);
			dest[i][baseplane] = baseheight;
		}
	} while(reject_base(dest,mins));
}

vec_t round(vec_t x)
{
	vec_t u,l;
	u = (vec_t)ceil(x);
	l = (vec_t)floor(x);
	if((u-x) > (x-l))
		return l;
	else
		return u;
}

void snap_to_nearest(vec3_t dest,vec3_t src)
{
	dest[0] = round(src[0]);
	dest[1] = round(src[1]);
	dest[2] = round(src[2]);
}

void generate_hedra(vec3_t dest[])
{
	int baseplane = choose_baseplane();
	generate_base(dest,baseplane);
	vec3Add(dest[3],dest[0],dest[1]);
	vec3Add(dest[3],dest[3],dest[2]);
	vec3Scale(dest[3],dest[3],.333333f);
	snap_to_nearest(dest[3],dest[3]);
	dest[3][baseplane] = 
		dest[0][baseplane]+(vec_t)get_random(lower,upper,true);
}

int main(int argc,char *argv[])
{
	vec3_t hedra[4];
	char *vertnames="ABCD";
	int i,j,n;
	vhandle_t out, clean_out;
	if(argc < 4)
	{
		puts(
			"Generator of hedras for task #2.\n"
			"Copyright (C) Vladimir A. Smirnov, 1997-2001.");
		puts("Usage: t2g <lower limit> <upper limit> "
			"<number of systems> [output file name] [file name for clean output]");
		return -1;
	}
	lower = atoi(argv[1]);
	upper = atoi(argv[2]);
	n = atoi(argv[3]);
	out = fileOpenWrite(argc < 5 ? "CON" : argv[4]);
	clean_out = fileOpenWrite(argc < 6 ? "clean.out" : argv[5]);
	filePrintf(out,";\t%d hedras produced by %s\n",n,argv[0]);
	for(i = 0;i < n;i++)
	{
		generate_hedra(hedra);
		filePrintf(out,"---- %d ----\n",i+1);
		for(j=0;j<4;j++)
		{
			filePrintf(clean_out,"%g;%g;%g\n",hedra[j][0],hedra[j][1],hedra[j][2]);
			filePrintf(out,"%c(%g;%g;%g)\n",vertnames[j],hedra[j][0],hedra[j][1],hedra[j][2]);
		}
	}
	fileClose(out);
	fileClose(clean_out);
	return 0;
}
