#include "procutil.h"
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "errorlog.h"

static uint32 lastRandomNumber = 0xA2A9; // that's a prime

void ProcUtil_Randomize( void )
{
uint32 cnt;
	cnt = clock();
	cnt &= 0xFFFF;
	while(cnt--)
	{
		lastRandomNumber = lastRandomNumber*65539+3;
		lastRandomNumber = lastRandomNumber*1009 +7;
	}
}

uint32 ProcUtil_Rand( uint32 max )
{
uint32 a;

	lastRandomNumber = lastRandomNumber*65539+3;

	a = lastRandomNumber>>16;

return a%max;
}

float ProcUtil_SinTable[TABLE_SIZE];
float ProcUtil_CosTable[TABLE_SIZE];

int   ProcUtil_ByteSinTable[TABLE_SIZE];
int   ProcUtil_ByteCosTable[TABLE_SIZE];

void ProcUtil_Init(void)
{
	int i;
	double radVal;
	
	for (i = 0; i < TABLE_SIZE; i ++)
	{
		radVal = i * (TWO_PI / TABLE_SIZE );
		
		ProcUtil_SinTable[i] = (float)sin(radVal);
		ProcUtil_CosTable[i] = (float)cos(radVal);
	}

	for (i = 0; i < 256; i ++)
	{
		radVal = i * (TWO_PI / 256.0);
		
		ProcUtil_ByteSinTable[i] = (int) (127.0 * (sin(radVal) + 1.0) + 0.49);
		ProcUtil_ByteCosTable[i] = (int) (127.0 * (cos(radVal) + 1.0) + 0.49);
	}
}


//====================================================================================
//	Utilities for many Procedurals
//====================================================================================

jeBoolean ProcUtil_SetPaletteFromUserData(jeBitmap * Bitmap, palTable parms)
{
	jeBitmap_Info Info;
	jeBitmap_Palette *Pal;
	void * PalData = NULL;
	jePixelFormat PalFormat;
	int PalSize;

	assert(parms.type);
	assert(parms.R);
	assert(parms.G);
	assert(parms.B);

	assert(Bitmap);

	Pal = jeBitmap_Palette_Create(JE_PIXELFORMAT_32BIT_ARGB,256);
	if ( ! Pal )
		goto fail;
	if ( ! jeBitmap_SetPalette(Bitmap,Pal) )
		goto fail;
	jeBitmap_Palette_Destroy(&Pal);

	jeBitmap_GetInfo(Bitmap,&Info,NULL);

	if ( ! (Pal = jeBitmap_GetPalette(Bitmap)) )
		goto fail;

	if ( ! jeBitmap_Palette_Lock(Pal,&PalData, &PalFormat, &PalSize) )
		goto fail;
	if ( PalSize < 256 )
		goto fail;

	//START METHOD CHECKING
	
	if ( strnicmp(parms.type,"list",4) == 0 )
	{
		int p,lp,r,g,b,a;
		uint8 * PalPtr;
		int NumColors;
		double pr,pg,pb,pa;
		double nr,ng,nb,na;
		double cstep,nextc,icstep;

		NumColors = 3;
		
		cstep = 256.0 / (NumColors - 1);
		nextc = 0.0;
		icstep = 1.0 / cstep;

		NumColors--;
		nr = parms.R[0];
		ng = parms.R[1];
		nb = parms.R[2];
		na = parms.R[3];
			
		PalPtr = PalData;
		for(p=0;p<256;p++)
		{
			int temp = 0;

			if ( p >= (int)nextc )
			{
				pr = nr;
				pg = ng;
				pb = nb;
				pa = na;

				switch(temp)
				{
				case 0:
					{
						nr = parms.G[0];
						ng = parms.G[1];
						nb = parms.G[2];
						na = parms.G[3];
						break;
					}
				case 1:
					{
						nr = parms.B[0];
						ng = parms.B[1];
						nb = parms.B[2];
						na = parms.B[3];
						break;
					}
				}
				
				nextc += cstep;
				lp = p;
			}

			// <> use Spline or Bezier instead !

			r = (int)(pr + (nr - pr)*(p - lp)*icstep);
			g = (int)(pg + (ng - pg)*(p - lp)*icstep);
			b = (int)(pb + (nb - pb)*(p - lp)*icstep);
			a = (int)(pa + (na - pa)*(p - lp)*icstep);

			jePixelFormat_PutColor(PalFormat,&PalPtr,min(r,255),min(g,255),min(b,255),min(a,255));
			temp++;
			if(temp = 2)
				temp = 0;
		}	
	}
	else if ( strnicmp(parms.type,"pow",4) == 0 )
	{
		int p,r,g,b,a;
		uint8 * PalPtr;
		double pr,pg,pb,pa,frac;
		double nr,ng,nb,na;

		
		nr = ((parms.R[0] + parms.R[1] + parms.R[2] + parms.R[3]) / 4);
		ng = ((parms.G[0] + parms.G[1] + parms.G[2] + parms.G[3]) / 4);
		nb = ((parms.B[0] + parms.B[1] + parms.B[2] + parms.B[3]) / 4);
		na = ((nr + ng + nb) / 3);
		
		pr = pg = pb = pa = 0.5;

		PalPtr = PalData;
		for(p=0;p<256;p++)
		{
			frac = (double)p * (1.0/256.0);
			r = (int)( nr * pow( frac, pr) );
			g = (int)( ng * pow( frac, pg) );
			b = (int)( nb * pow( frac, pb) );
			a = (int)( na * pow( frac, pa) );
			jePixelFormat_PutColor(PalFormat,&PalPtr,min(r,255),min(g,255),min(b,255),min(a,255));
		}
	}
	else if ( strnicmp(parms.type,"trig",4) == 0 )
	{
		int p,r,g,b,a;
		uint8 * PalPtr;
		float r_mult,g_mult,b_mult,a_mult;
		float r_freq,g_freq,b_freq,a_freq;
		float r_base,g_base,b_base,a_base;
		float frac;

		r_mult = (float)parms.R[0];
		g_mult = (float)parms.G[0];
		b_mult = (float)parms.B[0];
		a_mult = (float)parms.R[3];

		r_freq = (float)parms.R[1];
		g_freq = (float)parms.G[1];
		b_freq = (float)parms.B[1];
		a_freq = (float)parms.G[3];

		r_base = (float)parms.R[2]; r_base *= TWO_PI;
		g_base = (float)parms.G[2]; g_base *= TWO_PI;
		b_base = (float)parms.B[2]; b_base *= TWO_PI;
		a_base = (float)parms.B[3]; a_base *= TWO_PI;

		PalPtr = PalData;
		for(p=0;p<256;p++)
		{
			frac = (float)p * (TWO_PI/256.0f);
			r = (int)( r_mult * (cos( r_freq * frac + r_base ) + 1.0) );
			g = (int)( g_mult * (cos( g_freq * frac + g_base ) + 1.0) );
			b = (int)( b_mult * (cos( b_freq * frac + b_base ) + 1.0) );
			a = (int)( a_mult * (cos( a_freq * frac + a_base ) + 1.0) );
			jePixelFormat_PutColor(PalFormat,&PalPtr,min(r,255),min(g,255),min(b,255),min(a,255));
		}
	}
	else
	{
		jeErrorLog_AddString(-1,"ProcEng_MakePalette : no palette type!",NULL);
	}

	PalData = NULL;

	if ( ! jeBitmap_Palette_UnLock(Pal) )
		return JE_FALSE;

	return JE_TRUE;

fail:

	if ( PalData )
		jeBitmap_Palette_UnLock(Pal);

	return JE_FALSE;

}

//---------------------------------------------------------------------------------

jeBoolean ProcUtil_SetPaletteFromString(jeBitmap * Bitmap,char ** pParams)
{
	jeBitmap_Info Info;
	jeBitmap_Palette *Pal;
	void * PalData = NULL;
	jePixelFormat PalFormat;
	int PalSize;

	char ParamWork[1024];
	char *pstr;
	const char * strbreakers = " ,\t\n\r\34\39\09";

	#define nextparam()	do { if ( ! pstr ) { jeErrorLog_AddString(-1,"ProcEng_CreatePalette : params insufficient",NULL); goto fail; }; pstr = strtok(NULL,strbreakers); } while(0)
	#define getint()	( pstr == NULL ) ? 0 : atol(pstr); nextparam();
	#define getfloat()	( pstr == NULL ) ? 0.0f : (float)atof(pstr); nextparam();

	if ( pParams )
	{
		assert(*pParams);
		strcpy(ParamWork,*pParams);
	}
	else
	{
		strcpy(ParamWork,"list, 3, 0,0,0,0, 200,50,0,100, 255,100,50,255");
	}

	pstr = strtok(ParamWork,strbreakers);

	assert(Bitmap);

	Pal = jeBitmap_Palette_Create(JE_PIXELFORMAT_32BIT_ARGB,256);
	if ( ! Pal )
		goto fail;
	if ( ! jeBitmap_SetPalette(Bitmap,Pal) )
		goto fail;
	jeBitmap_Palette_Destroy(&Pal);

	jeBitmap_GetInfo(Bitmap,&Info,NULL);

	if ( ! (Pal = jeBitmap_GetPalette(Bitmap)) )
		goto fail;

	if ( ! jeBitmap_Palette_Lock(Pal,&PalData, &PalFormat, &PalSize) )
		goto fail;
	if ( PalSize < 256 )
		goto fail;

	if ( strnicmp(pstr,"list",4) == 0 )
	{
	int p,lp,r,g,b,a;
	uint8 * PalPtr;
	int NumColors;
	int pr,pg,pb,pa;
	int nr,ng,nb,na;
	double cstep,nextc,icstep;

		nextparam();
		NumColors = getint();
		if ( NumColors == 0 )
		{
			*pParams += (int)(pstr - ParamWork);
			pParams = NULL;
			strcpy(ParamWork,"list, 3, 0,0,0,0, 200,50,0,100, 255,100,50,255");
		}
		else if ( NumColors < 2 )
			goto fail;

		cstep = 256.0 / (NumColors - 1);
		nextc = 0.0;
		icstep = 1.0 / cstep;

		NumColors--;
		nr = getint();
		ng = getint();
		nb = getint();
		na = getint();
	
		PalPtr = PalData;
		for(p=0;p<256;p++)
		{
			if ( p >= (int)nextc )
			{
				pr = nr;
				pg = ng;
				pb = nb;
				pa = na;
				nr = getint();
				ng = getint();
				nb = getint();
				na = getint();
				nextc += cstep;
				lp = p;
			}

			// <> use Spline or Bezier instead !

			r = (int)(pr + (nr - pr)*(p - lp)*icstep);
			g = (int)(pg + (ng - pg)*(p - lp)*icstep);
			b = (int)(pb + (nb - pb)*(p - lp)*icstep);
			a = (int)(pa + (na - pa)*(p - lp)*icstep);

			jePixelFormat_PutColor(PalFormat,&PalPtr,min(r,255),min(g,255),min(b,255),min(a,255));
		}	
	}
	else if ( strnicmp(pstr,"pow",4) == 0 )
	{
	int p,r,g,b,a;
	uint8 * PalPtr;
	double pr,pg,pb,pa,frac;
	int nr,ng,nb,na;

		nextparam();

		nr = getint();
		ng = getint();
		nb = getint();
		na = getint();
		if ( pstr )
		{
			pr = getfloat();
			pg = getfloat();
			pb = getfloat();
			pa = getfloat();
		}
		else
		{
			pr = pg = pb = pa = 0.5;
		}

		PalPtr = PalData;
		for(p=0;p<256;p++)
		{
			frac = (double)p * (1.0/256.0);
			r = (int)( nr * pow( frac, pr) );
			g = (int)( ng * pow( frac, pg) );
			b = (int)( nb * pow( frac, pb) );
			a = (int)( na * pow( frac, pa) );
			jePixelFormat_PutColor(PalFormat,&PalPtr,min(r,255),min(g,255),min(b,255),min(a,255));
		}
	}
	else if ( strnicmp(pstr,"trig",4) == 0 )
	{
	int p,r,g,b,a;
	uint8 * PalPtr;
	float r_mult,g_mult,b_mult,a_mult;
	float r_freq,g_freq,b_freq,a_freq;
	float r_base,g_base,b_base,a_base;
	float frac;

		nextparam();

		r_mult = getfloat();
		g_mult = getfloat();
		b_mult = getfloat();
		a_mult = getfloat();
		r_freq = getfloat();
		g_freq = getfloat();
		b_freq = getfloat();
		a_freq = getfloat();
		r_base = getfloat(); r_base *= TWO_PI;
		g_base = getfloat(); g_base *= TWO_PI;
		b_base = getfloat(); b_base *= TWO_PI;
		a_base = getfloat(); a_base *= TWO_PI;

		PalPtr = PalData;
		for(p=0;p<256;p++)
		{
			frac = (float)p * (TWO_PI/256.0f);
			r = (int)( r_mult * (cos( r_freq * frac + r_base ) + 1.0) );
			g = (int)( g_mult * (cos( g_freq * frac + g_base ) + 1.0) );
			b = (int)( b_mult * (cos( b_freq * frac + b_base ) + 1.0) );
			a = (int)( a_mult * (cos( a_freq * frac + a_base ) + 1.0) );
			jePixelFormat_PutColor(PalFormat,&PalPtr,min(r,255),min(g,255),min(b,255),min(a,255));
		}
	}
	else
	{
		jeErrorLog_AddString(-1,"ProcEng_MakePalette : no palette type!",NULL);
	}

	PalData = NULL;

	if ( ! jeBitmap_Palette_UnLock(Pal) )
		return JE_FALSE;

	if ( pParams )
	{
		*pParams += (int)pstr - (int)ParamWork;
	}	

	return JE_TRUE;

fail:

	if ( PalData )
		jeBitmap_Palette_UnLock(Pal);

	return JE_FALSE;
}
