#include <math.h>
#include <time.h>
#include "../common/vector.h"
#include "shaders.h"
#include "phong.h"
#include "../render/tracer.h"
#include "../common/structs.h"
#include "../common/colors.h"
#include "../common/debug.h"
#include "../common/misc.h"
#include "../render/intersect/intersect.h"

#include <stdio.h>

#include <pthread.h>
extern pthread_mutex_t mutexor;
//pthread_mutex_lock (&mutexor);
//pthread_mutex_unlock (&mutexor);

extern scene_data* main_scene;
extern clock_t current_time;
int skip_object;

// general_shader {{{
void general_shader(intersect_data *i_data, color* final_color)
{
	color new_color;


	printd(DEBUG, "{general_shader\n");

	new_color.r = 0;
	new_color.g = 0;
	new_color.b = 0;

	CHECK_STEPS(i_data->step, main_scene->max_recurs);
	
	skip_object = i_data->obj_num;


	// create the intersection data structure 
//pthread_mutex_lock (&mutexor);
	get_normal(&i_data->intersect, i_data->obj, &i_data->normal);

//	reflect_vector(&i_data->proj, &i_data->normal, &i_data->reflect);
//pthread_mutex_unlock (&mutexor);
	normalize(&i_data->reflect);

//	print_idata(INSANE, "gshader recieved:", i_data);

	// adjust for rays falling inside the object
//	i_data->intersect.x += i_data->normal.x*0.1;
//	i_data->intersect.y += i_data->normal.y*0.1;
//	i_data->intersect.z += i_data->normal.z*0.1;

	// phong 
//pthread_mutex_lock (&mutexor);
	phong(i_data, &new_color);
//pthread_mutex_unlock (&mutexor);
	add_colors(final_color, &new_color);

//	clear_color(&new_color);

	// reflection 
	//reflect_color(i_data, &new_color);

	reflect_color(i_data, &new_color);
	multiply_color(final_color, (1 - i_data->obj->reflect));
	multiply_color(&new_color, i_data->obj->reflect);
	add_colors(final_color, &new_color);
	clear_color(&new_color);
	i_data->step--;

	// move the intersection for internal object calculations 
	i_data->intersect.x -= i_data->normal.x*0.05;
	i_data->intersect.y -= i_data->normal.y*0.05;
	i_data->intersect.z -= i_data->normal.z*0.05;

	// transparency
	trans_color(i_data, &new_color);
	multiply_color(final_color, (1 - i_data->obj->trans));
	multiply_color(&new_color, i_data->obj->trans);
	add_colors(final_color, &new_color);
	clear_color(&new_color);
	i_data->step--;

	/*
	// refraction 
	printd(CRAZY, " refraction\n");
	refract_color(i_data, &new_color);
	add_colors(final_color, &new_color);
	clear_color(&new_color);
	i_data->step--;
*/
//	print_color(INSANE, "color:", final_color);
//	printd(DEBUG, "}general_shader\n");
	
	skip_object = -1;

	return;
 } // }}}

// wave_shader {{{
void wave_shader(intersect_data *i_data, color* final_color)
{
	color new_color;
	double dist = 0.0;
	vector bend;

	printd(DEBUG, "{wave_shader\n");

	new_color.r = 0;
	new_color.g = 0;
	new_color.b = 0;

	CHECK_STEPS(i_data->step, main_scene->max_recurs);
	i_data->step++;
//	if(i_data->step > main_scene->max_recurs)
//	{
//		printd(DEBUG, "}__FUNCTION__: max recurs\n");
//		return;
//	}

	// create the intersection data structure 
	get_normal(&i_data->intersect, i_data->obj, &i_data->normal);
	reflect_vector(&i_data->normal, &i_data->proj, &i_data->reflect);
	normalize(&i_data->reflect);

	//setup the bumpy surface
	//copy_vector(&id->intersect, &new_id.start);
	//copy_vector(&id->proj, &new_id.proj);
	dist = distance_between(&i_data->intersect, &i_data->obj->pos);
	make_vector(&i_data->intersect, &i_data->obj->pos, &bend); 

	multiply_vector(&bend, &bend, sin(dist+current_time/TIME_SCALE));
	multiply_vector(&bend, &bend, 0.7);
	add_vectors(&bend, &i_data->normal, &bend);
	

	
	print_idata(INSANE, "wave shader recieved:", i_data);

	// adjust for rays falling inside the object 
	i_data->intersect.x += i_data->normal.x*0.01;
	i_data->intersect.y += i_data->normal.y*0.01;
	i_data->intersect.z += i_data->normal.z*0.01;

	// phong 
	phong(i_data, &new_color);
	add_colors(final_color, &new_color);

	// reflection 
	reflect_color(i_data, &new_color);
	multiply_color(final_color, (1 - i_data->obj->reflect));
	multiply_color(&new_color, i_data->obj->reflect);
	add_colors(final_color, &new_color);

	// move the intersection for internal object calculations 
	i_data->intersect.x -= i_data->normal.x*0.05;
	i_data->intersect.y -= i_data->normal.y*0.05;
	i_data->intersect.z -= i_data->normal.z*0.05;

	// sintransparency 
	add_vectors(&bend, &i_data->proj, &bend);
	trans_color(i_data, &new_color);
	//sin_filter(i_data, &new_color);
	multiply_color(final_color, (1 - i_data->obj->trans));
	multiply_color(&new_color, i_data->obj->trans);
	add_colors(final_color, &new_color);

	print_color(INSANE, "color:", final_color);
	printd(DEBUG, "}wave_shader\n");
	return;
} // }}}


void distance_shader(intersect_data *i_data, color* final_color)
{
	double dis = main_scene->intrsct.distance;
	//dis = i_data->distance;
	printd(DEBUG, "{ distance shader");

	final_color->r = 10;
	final_color->g = 10;
	final_color->b = 10;

	if(dis < 20)
		final_color->r = (char)(dis/20*256);
	if(dis > 19 && dis < 200)
		final_color->g = (char)(dis/200*256);
	if(dis > 199 && dis < 2000)
		final_color->b = (char)(dis/2000*256);
	//fprintf(stdout, "%i\n", (char)(main_scene->intrsct.distance*300));
	print_color(INSANE, "color:", final_color);
	printd(DEBUG, "}\n");
}

	// obj hack 
void object_shader(intersect_data *i_data, color* final_color)
{
	printd(DEBUG, "{ object shader");
	color_from_number(final_color, i_data->obj_num);
	print_color(INSANE, "color:", final_color);
	printd(DEBUG, "}\n");
}

void normal_shader(intersect_data *i_data, color* final_color)
{
	printd(DEBUG, "{ normal shader");
	//FIXME:normal also is calced in ray_common, kill one
	get_normal(&i_data->intersect, i_data->obj, &i_data->normal);
	normalize(&i_data->normal);

	final_color->r = (i_data->normal.x*128+128);
	final_color->g = (i_data->normal.y*128+128);
	final_color->b = (i_data->normal.z*128+128);
	print_vector(INSANE, "norm:", &i_data->normal);
	print_color(INSANE, "color:", final_color);
	printd(DEBUG, "}\n");
}

