#include <math.h>
#include "EmissionStrategy.h"
#include "Hemicube.h"
#include "Common.h"

EmissionStrategy* EmissionStrategy::newEmissionStrategy(int ef,HemicubeType ht)
{
  CombineEmissionStrategy *es;
  int                     cb,i;
  float                   fp;

  cb = countBits(ef);
  
  // Combine
  if (cb>1)
    {
      fp = 1.0f / (float)cb;
      i = 1 ;
      es = new CombineEmissionStrategy(cb);
      while (cb > 0)
	{
	  if ((ef & i)!=0)
	    {
	      cb--;
	      es->setEmissionStrategy(cb,fp,newSingleEmissionStrategy(ef & i,ht));
	    }
	  i <<= 1;
	}
      return es;
    }

  // Single
  if (cb==1)
    return newSingleEmissionStrategy(ef,ht);

  // Error
  return NULL;
}


EmissionStrategy* EmissionStrategy::newSingleEmissionStrategy(int em,HemicubeType ht)
{
  // Deal with non-patch sampling strategies..

  if (em==DE_UNIFORM_EMISSION)
    return new UniformEmissionStrategy();

  if (em==DE_COSTHETA_EMISSION)
    return new CosThetaEmissionStrategy();


  // Deal with patch sampling strategies˛
  if (ht==HEMICUBE_NONE)
    {
      switch(em)
	{
	case DE_AREA_EMISSION:
	  return new PatchEmissionStrategy(new AreaPatchProbabilityAssigner());

	case DE_DIRECT_POTENTIAL_EMISSION:
	  return new PatchEmissionStrategy(new DirectPotentialPatchProbabilityAssigner());

	case DE_EQUI_WIN_EMISSION:
	  return new PatchEmissionStrategy(new EquiWinPatchProbabilityAssigner());

	default:
	  break;
	}
    }
  else
    {
      switch(em)
	{
	case DE_AREA_EMISSION:
	  return new PatchEmissionStrategy(new CombinePatchProbabilityAssigner(new AreaPatchProbabilityAssigner(),new Hemicube(ht)));

	case DE_DIRECT_POTENTIAL_EMISSION:
	  return new PatchEmissionStrategy(new CombinePatchProbabilityAssigner(new DirectPotentialPatchProbabilityAssigner(),new Hemicube(ht)));

	case DE_EQUI_WIN_EMISSION:
	  return new PatchEmissionStrategy(new CombinePatchProbabilityAssigner(new EquiWinPatchProbabilityAssigner(),new Hemicube(ht)));

	default:
	  break;
	}
    }

  fprintf(stderr,"SOULD NEVER APPEND");

  return NULL;
}


EmissionStrategy::~EmissionStrategy()
{
}

void EmissionStrategy::Update(PATCH *)
{
}
