#ifndef BMPHONGSHADER_HXX
#define BMPHONGSHADER_HXX

#include "Shader.hxx"
 
//#define AREALIGHT 
//#define NUM_AREA_SAMPLES 1000
#define dPdu Vec3f(1,0,0)
#define dPdv Vec3f(0,0,1)

class BumpMappedPhongShader : public Shader
{
public:
  Vec3f color; // base color
  float ka;    // ambient coefficient
  float kd;    // diffuse reflection coefficients
  float ks;    // specular refelection coefficients
  float ke;    // shininess exponent

  BumpMappedPhongShader(Scene *scene,
	      Vec3f color, float ka,float kd, float ks, float ke)
    : Shader(scene),color(color),ka(ka),kd(kd),ks(ks),ke(ke)
  {};

  virtual Vec3f Shade(Ray &ray)
  {
    /* get shading normal */

    Vec3f normal = ray.hit->GetNormal(ray);
    
    /* turn normal to front */
		Vec3f p = ray.org + ray.t * ray.dir;

		normal = normal
		  + 0.5 * cos( 3 * p.x * sin(p.z)) * dPdu
		  + 0.5 * sin(13 * p.z)            * dPdv;
		Normalize(normal);


    if (Dot(normal,ray.dir) > 0)
      normal = -normal;
    
    /* calculate reflection vector */

    Vec3f reflect = ray.dir - 2*Dot(normal,ray.dir)*normal;
    
    /* ambient term */

    Vec3f ambientIntensity(1,1,1);

    Vec3f ambientColor = ka * color;
    Vec3f result = Product(ambientColor, ambientIntensity);

    /* shadow ray (up to now only for the light direction) */
    
    Ray shadow;
    shadow.org = ray.org + ray.t * ray.dir;
    
    /* iterate over all light sources */

    for (unsigned int l=0; l<scene->lights.size(); l++) {
      
      /* get direction to light, and intensity */
      
      Vec3f lightIntensity;
      
#ifdef AREALIGHT
      for(unsigned int s = 0; s < NUM_AREA_SAMPLES; s++)
#endif
      if (scene->lights[l]->Illuminate(shadow, lightIntensity)) {
	
	/* diffuse term */
	
	float cosLightNormal = Dot(shadow.dir,normal);
	if (cosLightNormal > 0) {
	  if (scene->Occluded(shadow))
	    continue;
	  
	  Vec3f diffuseColor = kd * color;
	  result = result + Product(diffuseColor * cosLightNormal,
				    lightIntensity);
	}
	
	/* specular term */
	
	float cosLightReflect = Dot(shadow.dir,reflect);
	if (cosLightReflect > 0) {
	  Vec3f specularColor = ks * Vec3f(1,1,1); // white highlight;
	  result = result + Product(specularColor * powf(cosLightReflect,ke),
				    lightIntensity);
	}
      }

#ifdef AREALIGHT
      result = result / NUM_AREA_SAMPLES;
#endif
    }

    return result;
  };
};

#endif
