#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "../common/objects.h"
#include "../common/vector.h"
#include "../render/intersect/intersect.h"
#include "../common/structs.h"
#include "../common/debug.h"
#include "./shaders.h"
#include "./lighting.h"

#include <pthread.h>
extern pthread_mutex_t mutexor;
extern scene_data* main_scene;


void ambient_light(color* c, intersect_data* id, int ln)
{
	double darkener = 1;
	vector uv;

	if(id->obj->obj_type == SPHERE)
	{
//		id->obj->inverse_map(&id->intersect, id->obj, &uv);
//		if((uv.x > 0.25 && uv.y > 0.25) || (uv.x < 0.25 && uv.y < 0.25))
//		if(uv.y > 0.5 )
//			darkener = 0.1;
	}
	
	c->r += (id->obj->amb.r * main_scene->lights[ln]->amb.r * darkener);
	c->g += (id->obj->amb.g * main_scene->lights[ln]->amb.g * darkener);
	c->b += (id->obj->amb.b * main_scene->lights[ln]->amb.b * darkener);
}


void diffuse_fast(color* c, intersect_data* id, vector *lightV, int ln)
{
	point *intersectP = &id->intersect;
	double dpLN;
	double atten;
	double distance;
	
	double darkener = 1;
	vector uv;
	
	dpLN = dot_product(lightV,normalize(&id->normal));
	
	// directly perpendicular/behind object
	if (dpLN <= 0)
		dpLN = 0;
	
	/* light distance */
	distance = distance_between(&main_scene->lights[ln]->pos,
								&id->intersect);
	
	//atten = 1/(50+2*distance+1.5*pow(distance,2))*80;
	//atten = 1/pow(distance,2)*80;
	//atten = 1/distance*20;
	atten = 15/distance;
	//atten = 1;

	/*
	if(id->obj->obj_type == SPHERE)
	{
		id->obj->inverse_map(&id->intersect, id->obj, &uv);
				if((uv.x > 0.25 && uv.y > 0.25) || (uv.x < 0.25 && uv.y < 0.25))
					darkener = 3.0;
	}*/
	
	c->r += (id->obj->diff.r * dpLN *
			 main_scene->lights[ln]->diff.r * atten * darkener);
	c->g += (id->obj->diff.g * dpLN *
			 main_scene->lights[ln]->diff.g * atten * darkener);
	c->b += (id->obj->diff.b * dpLN *
			 main_scene->lights[ln]->diff.b * atten * darkener);
}

void diffuse_light(color* c, intersect_data* id, int ln)
{
	vector lightV;  // vector to light from point q
	point *intersectP = &id->intersect;
	double dpLN;
	double atten;
	double distance;

	double darkener = 1;
	vector uv;

	/* light vector */
	lightV.x = main_scene->lights[ln]->pos.x - intersectP->x;
	lightV.y = main_scene->lights[ln]->pos.y - intersectP->y;
	lightV.z = main_scene->lights[ln]->pos.z - intersectP->z;
	normalize(&lightV);

	diffuse_fast(c, id, &lightV, ln);

}
// }}}

// {{{ specular light
void specular_light(color* c, intersect_data* id, int ln)
{
	vector lightV;  // vector to light from point q
	vector light_refl;
	double dpLN;
	double dpCR;
	double atten;
	double spec_gamma = id->obj->spec_alpha;
	double distance;

	lightV.x = main_scene->lights[ln]->pos.x - id->intersect.x;
	lightV.y = main_scene->lights[ln]->pos.y - id->intersect.y;
	lightV.z = main_scene->lights[ln]->pos.z - id->intersect.z;
	normalize(&lightV);
	dpLN = dot_product(&lightV,normalize(&id->normal));
	//invert_vector(&lightV);

	if (dpLN <= 0)
		dpLN = 0;
	// light distance
	distance = distance_between(&main_scene->lights[ln]->pos,
			&id->intersect);

	//atten = 1/(50+2*distance+1.5*pow(distance,2))*80;
	//atten = 1/pow(distance,2)*80;
	///atten = 1/distance*20;
	//atten = 5/distance;
	atten = 1;

	//light reflection vector
	light_refl = *reflect_vector(&lightV, &id->normal, &light_refl);

	normalize(&id->proj);
	dpCR = dot_product(&id->proj, &light_refl);
	if(dpCR < 0)
		dpCR = 0;

	c->r += (id->obj->spec.r * main_scene->lights[ln]->spec.r *
	 pow(dpCR,spec_gamma) * atten) * dpLN;
	c->g += (id->obj->spec.g * main_scene->lights[ln]->spec.g *
	 pow(dpCR,spec_gamma) * atten) * dpLN;
	c->b += (id->obj->spec.b * main_scene->lights[ln]->spec.b *
			pow(dpCR,spec_gamma) * atten) * dpLN;

}
// }}}



void phong(intersect_data *id, color *new_color)
{
	double shadow = 1;
	int i = 0;
	static color shaded_color;
	static vector lightV;
	
	clear_color(&shaded_color);
	for(i=0; main_scene->lights[i]!=NULL; i++)
	{
		
		ambient_light(&shaded_color, id, i);
		add_colors(new_color, &shaded_color);
		shadow = pointlight_fast(i, id, &lightV);

		if ( shadow > 0)
		{
			diffuse_fast(&shaded_color, id, &lightV, i);
			multiply_color(&shaded_color, shadow);
			add_colors(new_color, &shaded_color);
		}
		clear_color(&shaded_color);
		
	}
	
	multiply_color(new_color, 1.0/765.0);
	
	return;
}


//{{{ phong 
void phong_old(intersect_data *id, color *new_color)
{
	double shadow = 1;
	int i = 0;
	color shaded_color;

	//printd(DEBUG, "{phong\n");

	clear_color(&shaded_color);
	for(i=0; main_scene->lights[i]!=NULL; i++)
	{
	
		ambient_light(&shaded_color, id, i);
		add_colors(new_color, &shaded_color);
		clear_color(&shaded_color);

		/* if we are in a shadow, try the next light (ambient is the only
		 * lighting needed and it is already done */
		shadow = get_shadow(i, id);
		
		if ( shadow > 0)
		{
			diffuse_light(&shaded_color, id, i);
			specular_light(&shaded_color, id, i);

			multiply_color(&shaded_color, shadow);
			add_colors(new_color, &shaded_color);
		}
		clear_color(&shaded_color);
		
	}

	/* divide final value by the number of lighting calcs * max value
	 *     3 * 255 = 765   */   
	multiply_color(new_color, 1.0/765.0);

	return;
} //}}}


void fast_shade(intersect_data *id, color *new_color)
{
	double shadow = 1;
	int i = 0;
	color shaded_color;
	//point *intersectP = &id->intersect;
	double dpLN;
			
	printd(DEBUG, "{fast_shade\n");

	clear_color(&shaded_color);
	for(i=0; main_scene->lights[i]!=NULL; i++)
	{
		ambient_light(&shaded_color, id, i);
		add_colors(new_color, &shaded_color);
		clear_color(&shaded_color);

		shadow = get_shadow(i, id);
		if ( shadow > 0)
		{
			dpLN = dot_product(&main_scene->lights[i]->pos, normalize(&id->normal));

			// directly perpendicular/behind object
			if (dpLN <= 0)
				dpLN = 0;

			shaded_color.r += (id->obj->diff.r * dpLN * main_scene->lights[i]->diff.r);
			shaded_color.g += (id->obj->diff.g * dpLN * main_scene->lights[i]->diff.g);
			shaded_color.b += (id->obj->diff.b * dpLN * main_scene->lights[i]->diff.b);

			multiply_color(&shaded_color, shadow);
			add_colors(new_color, &shaded_color);
		}
		clear_color(&shaded_color);
	}

	new_color->r = new_color->r/765;
	new_color->g = new_color->g/765;
	new_color->b = new_color->b/765;
	printd(DEBUG, "}fast_shade\n");

	return;
}

