
#ifndef PATCHPROBABILITYASSIGNER_H
#define PATCHPROBABILITYASSIGNER_H

#include "patch.h"

// PatchProbabilityAssigner :: ABSTRACT CLASS
// Derived classes associate a probability to patches.
// All you have to do to implement derived classes is to provide a 'recomputeProbabilities' method.
// See the specification of this method for more info. 
class PatchProbabilityAssigner
{
public:

  // Constructor.
  // POST: A patch probability assigner is created.
  // NOTE: You can't directly create a PatchProbabilityAssigner since this class is abstract.
  PatchProbabilityAssigner();


  // Destructor.
  // POST: All memory is given back to the system.
  virtual ~PatchProbabilityAssigner();
  

  // Assign probabilities to patches.
  // IN:   A patch pointer to the current emitting patch 
  //       for probability assignment strategies dependant of this information.
  // OUT:  An integer indicating if the probability assignment was succesful.
  // POST: You can use the next public methods if return values was different from 0;
  int assignProbabilities(PATCH *);


  // Get the probability assigned to a patch.
  // PRE: assignProbabilities must have been called.
  // IN:  pid : A valid patch id (0 < pid <= # of patches in the scene).
  // OUT: the probability assigned to the patch.
  double getProbability(const int pid);


  // Get the probability assigned to a patch.
  // PRE: assignProbabilities must have been called.
  // IN:  patch : A valid pointer to a patch in the scene.
  // OUT: the probability assigned to the patch.
  double getProbability(const PATCH *patch);


  // Choose randomly a patch according to assigned probabilities.
  // PRE: assignProbabilities must have been called.
  // OUT:  A valid patch pointer. (if the scene contains no patches, returns NULL)
  // POST: The patch is choosen according to assigned probabilities 
  //       and the random number generator.
  PATCH *choosePatch();


  // Choose randomly a patch according to assigned probabilities.
  // PRE: assignProbabilities must have been called.
  // OUT:  A valid patch id. (if the scene contains no patches, returns 0)
  // POST: The patch is choosen according to assigned probabilities 
  //       and the random number generator.
  int choosePatchId();


protected:

  // Recompute probabilities.
  // All derived classes have to implement this method.
  // PRE:  numpatches contains the number of patches+1.
  //       pa[i]      contains a pointer to patch i.
  //       pb[i]      contains garbage.
  //       sum        contains garbage.
  // IN:   A pointer to the currently emmitting patch.
  // POST: numpatches and pa are unchanged
  //       pb[i]      contains a positive number for each i.
  //       sum        contains the sum of pb[i] for i=1 to i=numpatches.
  virtual void recomputeProbabilities(PATCH *) = 0;

  // Assign a probability of zero to all patches.
  // POST: pb[i] = 0.0 for all 0 <= i < numpatches
  void clearProbabilities();

  int            numpatches;
  PATCH          **pa;
  double         *pb;
  double         sum;

private:

  // Alloc arrays to hold patches pointers and probabilities.
  int allocProbabilities();

  // Free arrays used to hold patches pointers and probabilities.
  void freeProbabilities();


  // Normalize probabilities
  void normalizeProbabilities();
};


class AreaPatchProbabilityAssigner : public PatchProbabilityAssigner
{
protected:
  void recomputeProbabilities(PATCH*);
};


class DirectPotentialPatchProbabilityAssigner : public PatchProbabilityAssigner
{
protected:
  void recomputeProbabilities(PATCH*);
};


class EquiWinPatchProbabilityAssigner : public PatchProbabilityAssigner
{
protected:
  void recomputeProbabilities(PATCH*);
};


class CombinePatchProbabilityAssigner : public PatchProbabilityAssigner
{
private:
  PatchProbabilityAssigner *ppa1,*ppa2;

protected:
  void recomputeProbabilities(PATCH*);

public:
  // Constructor
  CombinePatchProbabilityAssigner(PatchProbabilityAssigner *nppa1,PatchProbabilityAssigner *nppa2);
  ~CombinePatchProbabilityAssigner();
};

#endif
