// ===================================================================
// $Id: samplinf.h,v 1.2 2003/11/04 15:27:18 havran Exp $
//
// samplinf.h
//     Header file for representation of sampling in organized way.
//
// Class: CSamplingInfo
//
// Licence and usage conditions in November 2003:
// This file can be used and modified only with written permission of
// Vlastimil Havran, Pohodli 27, 57001 Litomysl, the Czech Republic.
// This library is granted to be used by Polina Kondratieva within
// her MPI HIWI job working on BRDFLIB library. The usage condition
// may change in the next version of the library. At the moment,
// the library development is supported by Max-Planck-Institut for
// Informatik, Stuhlsatzenhausweg 85, 66123 Saarbruecken Germany
// See WWW: http://www.mpi-sb.mpg.de
// REPLACEMENT_STRING
//
// Initial coding by Vlastimil Havran, October 2003.
//
// Given to BRDFLIB project for the Polina Kondratieva's
// HIWI JOB assignment in November 2003.
// ===================================================================


#ifndef __SAMPLINF_H__
#define __SAMPLINF_H__

// BRDFLIB headers
#include "configh.h"
#include "basic.h"
#include "detrndba.h"
#include "rnd.h"
#include <iostream>


__BEGIN_BRDFLIB_HEADER

// ------------------------------------------------------------------------
// This class describes the distribution, random generator to be used,
// starting dimension for the random generator, the seed for random generator
// and other input parameters for stochastically sampling from the surface
// ------------------------------------------------------------------------
class CSamplingInfo
{
protected:
  unsigned long int savedSeed;
  // Some default must be used, my age at the moment of writing.
  enum EDUMMY { INITIAL_SEED = 31};
  // maximum number of samples to be taken
  int maxSamples;
  // random number generator to be used
  CMultDimRNDGen *randGenerator;
  // Starting dimension to be used for random generator
  // The first dimension is 0. If the dimension should not
  // be used, then it is -1.
  int initialDimension;
  // the seed to be used for the generator
  unsigned long int initialSeed;
  // whether to use seed here for the generation of this sample
  bool useSeed;
  // whether the random value has been saved from the previous
  // generation by function PushValue(float value)
  mutable bool valueWasPushed;
  // the saved random value
  mutable float pushedRNDvalue;
  
  // !!! DESIGN FEATURE
  // !!! Possibly some other information can be a Distribution
  // !!! of samples over the domain to be taken or some class to be used
  // !!! as the converter of random samples from uniform distribution.
  // !!! It might be also the part
  // !!! of random generator that contains another generator and
  // !!! converts the samples to match to required distribution.
  // CDistribution *distribution;
  // !!! THe other parameter can be the CDistParams - the object
  // !!! that contains parameters to be passed to CDistribution object
  // !!! for this particular case
  // CDistParams   *distParams;
public:
  // constructor
  CSamplingInfo():
    maxSamples(1), randGenerator(0),
    initialDimension(-1), initialSeed(INITIAL_SEED),
    useSeed(false) {
       valueWasPushed = false;
       pushedRNDvalue = 0;
    }

    // Generation sample interface

    // Generate random number whichever seed is used. The dimension is passed
    // to the generator.
    double Sample(int dimensionIncrement = 0) const {
    if (valueWasPushed) {
      valueWasPushed = false;
      return pushedRNDvalue;
    }
    
    if (randGenerator) {
      assert(initialDimension + dimensionIncrement <
	     randGenerator->MaxDimension());
      if (useSeed)
	randGenerator->SetSeed(initialSeed);
      return randGenerator->Rand01d(initialDimension + dimensionIncrement);
    }
    // use standard generator
    return RND::rand01d();
  }
  
  // Query and setting functions
  void SetSeed(unsigned long int newSeed) { initialSeed = newSeed;}
  unsigned long int GetSeed() const { return initialSeed;}
  void IncSeed() { initialSeed++;}
  void SetUseSeed(bool useSeedNew) {useSeed = useSeedNew;}

  void SetDimension(int newDim) { initialDimension = newDim;}  
  int  GetDimension() const { return initialDimension;}
  void IncDimension() { initialDimension++;}
  void IncDimension(int delta) { initialDimension += delta;}

  void SetMaxSamples(int newMaxSamples) { maxSamples = newMaxSamples;}
  int GetMaxSamples() const { return maxSamples;}
  
  // The concept of saving the seed for recovery
  void StoreSeed() { savedSeed = initialSeed;}
  void RecoverSeed() { initialSeed = savedSeed ;}  
  unsigned long GetSavedSeed() const {return savedSeed;}

  // Set a new random generator to be used
  void SetRandGenerator(CMultDimRNDGen *newRandGenerator) {
    delete randGenerator;
    randGenerator = newRandGenerator;
  }

  // push the random value that should be used for the next
  // generation of function Sample(in incdim). This can be used
  // when decreasing the number of dimensions used during selection
  // of distribution (for surface interaction and light source selection)
  void PushRandomValue(float rndvalue) {
    valueWasPushed = true;
    pushedRNDvalue = rndvalue;
  }
};


__END_BRDFLIB_HEADER

#endif // __SAMPLINF_H__

