#include <v_lib.h>
#include "framebuf.h"
#include "cspace.h"
#include "eval.h"

/*
random_seed 3

matrix ref_matrix
{
	state custom_width 256
	state custom_height 256
	# row
	constant 0.5
}

vector ref_vector
{
	state custom_size 256 # sets custom_width
	linear 0 1
}

matrix image1_temp # name - any string
{
	# state parameter; reset after evaluation
	state	custom_width		256
	state	custom_height		256
	# state custom_width width_of ref_matrix
	# state custom_width size_of ref_vector
	# state input_power2 true # false
	# state input_square true # false
	input	img1.bmp channel red # green,blue,alpha,hue,saturation,value,cieX,cieY,cieZ
	# constant 0.5
	# random 0.1 0.3
	# state stack empty, result: framebuffer in cache, red channel extracted to matrix
	fourier_forward

    TODO 
	zero_rows		1 2
	zero_rows		16 255
	zero_cols		1 2
	zero_cols		16 255
	# band_pass		3 15 # equivalent to prev four commands
	zero_rows		3 15
	zero_cols		3 15
	# band_reject	3 15 # equivalent to prev two commands

	# scale 0.35
	# offset 0.1
	# scale_offset 0.35 0.1 # equivalent to prev two commands
	# mat_scale matrix1 # by-element multiplication
	# mat_offset matrix2 # by-element addition
	fourier_inverse
	maximize_contrast
}

matrix matrix1
{
	image1_temp # evaluated prev. matrix
	gamma_correction vector2 # see below for vector2
}

vector vector2
{
	historgam	image1_temp
	save img1_red.txt # optional
	integrate
}

output out.tga
{
	source_space RGB	# or HSV or CIE
	red 	matrix1
	green	matrix2
	blue	matrix3
	alpha	matrix_05	# allowed for any colorspace
}

*/

#if 0

/* ==================================================================== */

void zero_freq(vec_t *afreq,s32_t lo_pass,s32_t hi_pass)
{
	u32_t hlen;
	/*
	 * Discard frequencies below 'lo_pass'
	 */
	if(lo_pass)
		memZero(afreq,lo_pass * 2 * sizeof(vec_t));
	/*
	 * Discard frequencies above 'hi_pass'
	 */
	hi_pass <<= 1;
	hlen = SCAN_WIDTH - hi_pass;
	if(hlen)
		memZero(afreq + hi_pass,hlen * sizeof(vec_t));
}

void zero2d(matrix_t *m,s32_t lo_pass,s32_t hi_pass)
{
	u32_t i;
	matrix_t *m2 = matAlloc(m->rows,m->cols);
	for(i=0;i<m->rows;i++)
		zero_freq(m->cell[i],lo_pass,hi_pass);
	matTranspose(m2,m);
	for(i=0;i<m->rows;i++)
		zero_freq(m2->cell[i],lo_pass,hi_pass);
	matTranspose(m,m2);
	memFree(m2);
}

vhandle_t fft_context = LIBV_INVALID_HANDLE;

void band_pass(u8_p pixels,s32_t lo_pass,s32_t hi_pass)
{
	u32_t channel;
	for(channel=0;channel<3;channel++)
	{
		scanlines_to_array(pixels,channel);
		fftForward2D(fft_context,&pixmat);
		zero2d(&pixmat,lo_pass,hi_pass);
		fftInverse2D(fft_context,&pixmat);
		array_to_scanlines(pixels,channel);
	}
}

void masked_zero(matrix_t *m,matrix_t *mask)
{
	u32_t i,j;
	for(i=0;i<m->rows;i++)
		for(j=0;j<m->cols;j++)
			m->cell[i][j] *= mask->cell[i][j];
}

void mask_pass(u8_p pixels,matrix_t *mask)
{
	u32_t channel;
	for(channel=0;channel<3;channel++)
	{
		scanlines_to_array(pixels,channel);
		fftForward2D(fft_context,&pixmat);
		masked_zero(&pixmat,mask);
		fftInverse2D(fft_context,&pixmat);
		array_to_scanlines(pixels,channel);
	}
}

/* ==================================================================== */

u32_t log_two(u32_t val)
{
	u32_t count = 0;
	while((1 << count) < val)
		count++;
	return count;
}
	framebuf_p fb;
	matrix_p c1=NULL,c2=NULL,c3=NULL;
	logStartConsoleLog();
	logUpperLevel(LOG_TRACE);
	fb = fbLoadEx("30.jpg",true,true,true);
	fft_context = fftCreateContext(log_two(fb->width),true);
	ctransFill3Matrices(fb,CSPACE_HSV,&c1,&c2,&c3);

	fftForward2D(fft_context,c1);

	matZeroRows(c1,128,fb->height-1);
	matZeroCols(c1,128,fb->width-1);

	/*
	matZeroRows(c1,0,10);
	matZeroCols(c1,0,10);
	*/
	fftInverse2D(fft_context,c1);

	/* cspaceMaximizeContrast(c1,c1); */
	ctransStore3Matrices(fb,CSPACE_HSV,c1,c2,c3);
	fbSaveEx(fb,"out.bmp",true);

	memFree(fb);
	memFree(c1);
	memFree(c2);
	memFree(c3);
	
	fftDestroyContext(fft_context);


#endif

void usage(char *name)
{
	puts("Image processing language interpreter.\n"
		"Version 0.49 by Vladimir A. Smirnov.");
	printf("Usage: %s <scriptfile>\n",name);
	printf("For language description, type %s --help-ipl.\n",name);
}

u32_t random_seed = 1;

vhandle_t random_gen = LIBV_INVALID_HANDLE;

void
evalGlobals(vhandle_t script)
{
	if(tokSkipToEx(script,"random_seed",STR_COMP))
	{
		if(!tokNextInteger(script,(s32_p)&random_seed))
		{
			conlPuts(LOG_WARNING,"evalGlobals(): error "
				"getting random_seed, using default value '1'.\n");
			random_seed = 1;
		}
	}
	tokRestart(script);
}

int main(int argc,char *argv[])
{
	vhandle_t script;
	vboolean result;
	u32_t nbytes, nblocks, nhandles;
	u32_t nbytes_out, nblocks_out, nhandles_out;
	logStartConsoleLog();
	logUpperLevel(LOG_TRACE);
	if(argc != 2)
	{
		usage(argv[0]);
		return -1;
	}
	if(STR_EQ(argv[1],"--help"))
	{
		usage(argv[0]);
		return 0;
	}
	if(STR_EQ(argv[1],"--help-ipl"))
	{
		evalHelp();
		return 0;
	}
	if(STR_EQ(argv[1],"--help-state"))
	{
		stateHelp();
		return 0;
	}
	script = tokParseFile(argv[1],"{}");
	if(script == LIBV_INVALID_HANDLE)
	{
		conlPrintf(LOG_ERROR,"main(): unable to parse '%s'\n",argv[1]);
		return -1;
	}
	evalGlobals(script);
	random_gen = urnCreateGenerator(random_seed);
	V_ASSERT(random_gen);
	result = evalAll(script);
	memStats(&nbytes,&nblocks,&nhandles);
	urnDestroyGenerator(random_gen);
	inputCollectGarbage();
	evalFreeAllArgs();
	evalDestroyAllFourierTransformers();
	memStats(&nbytes_out,&nblocks_out,&nhandles_out);
	printf("%s run completed: %s. "
		"(%u bytes in %u blocks and %u handles allocated, %u bytes leak)\n",
		result ? "success" : "error(s)",nbytes,nblocks,nhandles,nbytes_out);
	return 0;
}
