Vector4* findViewDirection(double xS, double yS, double zS){

	Vector4* V = new Vector4();
	V->SetVector4(eX-xS, eY-yS, eZ-zS,1.0);
	V->ConvertToUnit();
	return V;
}
Vector4* findNormalToSphere(double xS, double yS, double zS, Sphere& sphere){

	//Coordinates of the centre of the sphere.
	double x_c = sphere.position[0];
	double y_c = sphere.position[1];
	double z_c = sphere.position[2];

	//radius of the sphere.
	double S_r = sphere.radius;

	Vector4* normal = new Vector4();
	normal->SetVector4(xS-x_c, yS-y_c, zS-z_c, 1.0);
	normal->ConvertToUnit();
	return normal;

}
Vector4* findNormalToTriangle(double xS, double yS, double zS, Triangle& triangle){

	double x0 = triangle.v[0].position[0];
	double y0 = triangle.v[0].position[1];
	double z0 = triangle.v[0].position[2];

	double x1 = triangle.v[1].position[0];
	double y1 = triangle.v[1].position[1];
	double z1 = triangle.v[1].position[2];

	double x2 = triangle.v[2].position[0];
	double y2 = triangle.v[2].position[1];
	double z2 = triangle.v[2].position[2];

	//Calculate the vertices of the triangle.
	auto_ptr<Vector4> P0(new Vector4());
	P0->SetVector4(x0,y0,z0,1.0f);
	auto_ptr<Vector4> P1(new Vector4());
	P1->SetVector4((float)x1,(float)y1,(float)z1,1.0f);
	auto_ptr<Vector4> P2(new Vector4());
	P2->SetVector4((float)x2,(float)y2,(float)z2,1.0f);
	auto_ptr<Vector4> P(new Vector4());
	P->SetVector4((float)xS,(float)yS,(float)zS,1.0f);


	//Vector from one vertex to other vertex.
	auto_ptr<Vector4> Edge01(P0->Subtract(*P1, *P0));
	auto_ptr<Vector4> Edge12(P1->Subtract(*P2, *P1));
	auto_ptr<Vector4> Edge20(P2->Subtract(*P0, *P2));

	//Area of the complete triangle.
	double area_P0P1P2 = (0.5*Edge01->CrossProduct(*Edge01, *Edge20)->GetMagnitude());
	assert(area_P0P1P2 > 0);

	//Area of PP0P2
	auto_ptr<Vector4> EdgePP2(new Vector4());
	EdgePP2->SetVector4(xS-x2, yS-y2, zS-z2,1);
	double area_PP0P2 = (0.5*Edge20->CrossProduct(*Edge20, *EdgePP2)->GetMagnitude());
	assert(area_PP0P2 >= 0.0);

	//Area of PP1P2
	double area_PP1P2 = (0.5 * EdgePP2->CrossProduct(*EdgePP2, *Edge12)->GetMagnitude());
	assert(area_PP1P2 >= 0);

	//Area of PP0P1
	auto_ptr<Vector4> EdgePP0(new Vector4());
	EdgePP0->SetVector4(xS-x0, yS-y0, zS-z0,1);
	double area_PP0P1 = (0.5*Edge01->CrossProduct(*Edge01, *EdgePP0)->GetMagnitude());

	assert(area_PP0P1 >= 0);//I am here

	double alpha = area_PP1P2/area_P0P1P2;
	double beta = area_PP0P2/area_P0P1P2;
	double gamma = area_PP0P1/area_P0P1P2;


	double n0_x = triangle.v[0].normal[0];
	double n0_y = triangle.v[0].normal[1];
	double n0_z = triangle.v[0].normal[2];
	auto_ptr<Vector4> N0(new Vector4());
	N0->SetVector4(n0_x, n0_y, n0_z, 1);

	double n1_x = triangle.v[1].normal[0];
	double n1_y = triangle.v[1].normal[1];
	double n1_z = triangle.v[1].normal[2];
	auto_ptr<Vector4> N1(new Vector4());
	N1->SetVector4(n1_x, n1_y, n1_z, 1);

	double n2_x = triangle.v[2].normal[0];
	double n2_y = triangle.v[2].normal[1];
	double n2_z = triangle.v[2].normal[2];
	auto_ptr<Vector4> N2(new Vector4());
	N2->SetVector4(n2_x, n2_y, n2_z, 1);

	N0->Elongate(alpha);
	N1->Elongate(beta);
	N2->Elongate(gamma);

	Vector4* normalTemp = N0->Add(*N0, *N1);
	Vector4* normal = N0->Add(*normalTemp, *N2);

	delete normalTemp;
	normal->ConvertToUnit();
	return normal;
}
Color* getColor(Vector4& viewVector, double x, double y, double z, int depth){

	Color* color = new Color(0,0,0);
	int red = 0;
	int green = 0;
	int blue = 0;

	double ka_red = 0.0;
	double ka_green = 0.0;
	double ka_blue = 0.0;

	double kd_red = 0.0;
	double kd_green = 0.0;
	double kd_blue = 0.0;

	double ks_red = 0.0;
	double ks_green= 0.0;
	double ks_blue = 0.0;

	double shininess = 0.0;

	//The view vector from the point of intersection to where the user is standing.
	Vector4* V = findViewDirection(x,y,z);
	V->ConvertToUnit();

	//The normal vector to the surface obtained by interpolating the normals.
	Vector4* N = new Vector4();
	N->SetVector4(0,0,0,1);

	if(iType == SPHERE){
		N->GetCopyOf( *findNormalToSphere(x,y,z,spheres[index_sphere]) );
		N->ConvertToUnit();

		kd_red = spheres[index_sphere].color_diffuse[0];
		kd_green = spheres[index_sphere].color_diffuse[1];
		kd_blue = spheres[index_sphere].color_diffuse[2];

		ks_red = spheres[index_sphere].color_specular[0];
		ks_green = spheres[index_sphere].color_specular[1];
		ks_blue = spheres[index_sphere].color_specular[2];

		shininess = spheres[index_sphere].shininess;

	}
	if(iType == TRIANGLE){

		N->GetCopyOf( *findNormalToTriangle(x,y,z,triangles[index_triangle]) );
		N->ConvertToUnit();

		Vector4* Kd = interpolateKd(x,y,z, triangles[index_triangle]);
		Vector4* Ks = interpolateKs(x,y,z, triangles[index_triangle]);

		kd_red = Kd->getX();
		kd_green = Kd->getY();
		kd_blue = Kd->getZ();

		ks_red = Ks->getX();
		ks_green =  Ks->getY();
		ks_blue =  Ks->getZ();

		shininess = interpolateShininess(x,y,z, triangles[index_triangle]);

		delete Kd;
		delete Ks;
	}

	ka_red = kd_red;
	ka_green = kd_green;
	ka_blue = kd_blue;

	color->addMoreRed((int)getAmbientRed(ka_red));
	color->addMoreGreen((int)getAmbientGreen(ka_green));
	color->addMoreBlue((int)getAmbientBlue(ka_blue));

	int i =0;
	for(i = 0; i<num_lights; i++){
		//Light Vector (From the point of intersection to the light source)
		auto_ptr<Vector4> L(findLightDirection(x,y,z,lights[i]));
		L->ConvertToUnit();

		//Reflected Ray Vector
		auto_ptr<Vector4> R(findReflectedRayDirection(*N, *L));
		R->ConvertToUnit();

		double LN = L->DotProduct(*L, *N);
		double RV = R->DotProduct(*R, *V);

//		if(isShadowed(x,y,z,lights[i]) and LN>=0){
		if(isShadowed(x,y,z,lights[i])){
			red = 0;
			green = 0;
			blue = 0;

		}else{

			red = getRed(lights[i].color[0], ka_red, kd_red, ks_red, LN, RV, shininess);
			green = getGreen(lights[i].color[1], ka_green, kd_green, ks_green, LN, RV, shininess);
			blue = getBlue(lights[i].color[2], ka_blue, kd_blue, ks_green, LN, RV, shininess);

		}

//		cout << "more Red "<<red<<", ";/////////////////////////////////////////////////////////
//		cout << "more Green "<<green<<", ";
//		cout << "more Blue "<<blue<<endl;

		color->addMoreRed(red);
		color->addMoreGreen(green);
		color->addMoreBlue(blue);

//		if(depth < MAX_DEPTH){
//			auto_ptr<Ray> reflRay(new Ray(x,y,z,R->getX(), R->getY(), R->getZ()));
//			Color* newColor = traceRay(*reflRay, depth+1);
//
//			int newRed = (int)ks_red*newColor->getRed();
//			int newGreen = (int)ks_green*newColor->getGreen();
//			int newBlue = (int)ks_blue*newColor->getBlue();
//
//			color->addMoreRed(newRed);
//			color->addMoreGreen(newGreen);
//			color->addMoreBlue(newBlue);
//
//			delete newColor;
//		}
	}



	if(depth < MAX_DEPTH){
		auto_ptr<Vector4> reflVector(findReflectedRayDirection(*N, viewVector));
		reflVector->ConvertToUnit();

		auto_ptr<Ray> reflRay(new Ray(x,y,z,-1,-1,-1));
		reflRay->setXd(reflVector->getX());
		reflRay->setYd(reflVector->getY());
		reflRay->setZd(reflVector->getZ());

		double t_new = findIntersect(*reflRay);

		if(t_new != NO_INTERSECTION){
			double new_x_boom = getXIntersect(*reflRay, t_new);
			double new_y_boom = getYIntersect(*reflRay, t_new);
			double new_z_boom = getZIntersect(*reflRay, t_new);

			Color* newColor = getColor(*reflVector, new_x_boom, new_y_boom, new_z_boom, depth+1);
			int newRed = (int)(ks_red*newColor->getRed());
			int newGreen = (int)(ks_green*newColor->getGreen());
			int newBlue = (int)(ks_blue*newColor->getBlue());

			//cout<<"new colors"<<newRed<<", "<<newGreen<<", "<<newBlue<<endl;

			color->addMoreRed(newRed);
			color->addMoreGreen(newGreen);
			color->addMoreBlue(newBlue);

			delete newColor;
		}

	}




	delete N;
	iType = NONE;

	return color;
}