
#ifndef EMISSION_STRATEGY_H
#define EMISSION_STRATEGY_H

#include "edf.h"
#include "ray.h"
#include "spherical.h"

#include "Hemicube.h"
#include "PatchProbabilityAssigner.h"


// Emission flags
const int DE_UNIFORM_EMISSION          =  1;
const int DE_COSTHETA_EMISSION         =  2;
const int DE_AREA_EMISSION             =  4;
const int DE_DIRECT_POTENTIAL_EMISSION =  8;
const int DE_EQUI_WIN_EMISSION         = 16;


// EmissionStrategy.
// This abstract class define generic methods to send particles through a scene.
class EmissionStrategy
{
public:
  // EmissionStrategy factory.
  // Construct a EmissionStrategy combining emission strategies (Emission flags OR'ed) and
  // an HemicubeType.
  // IN:  ef : emission flags OR'ed.
  //      ht : hemicube type to combine probabilities.
  // OUT: An emission strategy combining strategies from ef and modulating probabilities according to ht.
  //      NULL if memory allocation failed.
  static EmissionStrategy* newEmissionStrategy(int ef,HemicubeType ht);
  static EmissionStrategy* newSingleEmissionStrategy(int em,HemicubeType ht);

  // Destructor.
  // POST: All ressources are freed.
  virtual ~EmissionStrategy();


  // Get the emission flags corresponding to this strategy.
  // OUT: The emission flags corresponding to this strategy OR'ed.
  // virtual int GetEmissionFlags();


  // Get the hemicube type associated with this strategy.
  // OUT: The hemicube associated with this strategy
  // virtual HemicubeType GetHemicubeType();


  // Reset the emission strategy (recompute pdf according to current state).
  // IN:    p  : patch from where we will send the particles.
  // POST:  The probability density function this class use to send particle has been updated
  //        according to strategies, hemicube type, current state and patch we are sending
  //        particles from.
  virtual void Update(PATCH *p);


  // Send a ray from a patch.
  // IN:  The patch we are sending the ray from.
  // OUT: The choosen ray.
  //      The hit record corresponding to this ray.
  //      The probability of selection of this ray according to the sampling strategy.
  virtual double SendRay(PATCH *patch,RAY &rout,HITREC &hout) = 0;


  // Evaluate the probability of a ray.
  virtual double EvalRay(PATCH *patch,RAY &rout,HITREC &hout) =0;
};


class CombineEmissionStrategy : public EmissionStrategy
{
private:
  int               nm;   // Number of emission strategies to combine.
  EmissionStrategy  **es; // Array of emission strategies pointers.
  float             *p;   // Array of probability for each emission strategy.

public:
  CombineEmissionStrategy(int n);
  ~CombineEmissionStrategy();

  // Set the Nth technique.
  void setEmissionStrategy(int i,float p,EmissionStrategy *nes);

  // Virtual functions from EmissionStrategy
  void Update(PATCH *);
  double SendRay(PATCH *patch,RAY &rout,HITREC &hout);
  double EvalRay(PATCH *patch,RAY &rout,HITREC &hout);
};


class UniformEmissionStrategy : public EmissionStrategy
{
  double SendRay(PATCH *patch,RAY &rout,HITREC &hout);
  double EvalRay(PATCH *patch,RAY &rout,HITREC &hout);
};


class CosThetaEmissionStrategy : public EmissionStrategy
{
  double SendRay(PATCH *patch,RAY &rout,HITREC &hout);
  double EvalRay(PATCH *patch,RAY &rout,HITREC &hout);
};


class PatchEmissionStrategy : public EmissionStrategy 
{
private:
  PatchProbabilityAssigner *ppa;

public:
  PatchEmissionStrategy(PatchProbabilityAssigner *nppa);
  ~PatchEmissionStrategy();

  void Update(PATCH *p);
  double SendRay(PATCH *p,RAY &rout,HITREC &hout);
  double EvalRay(PATCH *patch,RAY &rout,HITREC &hout);
};


#endif




