#ifndef RIRANDOM_H
#define RIRANDOM_H
/*
 * RiRandom.H
 * 
 */

#ifndef RIMATH_H
#include <RiMath.H>
#endif

#define RI_RANDOM_ARRAY_SIZE 120

/***************************************************************
CLASS
    RiRandomStrategy
    The strategy for creating a set of random numbers.  

DESCRIPTION
    Generates pseudo-random numbers for use by RiRandom.  This class
    allows RiRandom to amortize the function calls and any extra overhead
    of generating random numbers over many individual numbers.

IMPLEMENTATION
    Must have a constructor that takes an int seed value.
    
PATTERN
    Prototype
    Strategy
****************************************************************/

class RiRandomStrategy {
  public:
    // GROUP: Constructors and assignment
    virtual ~RiRandomStrategy() {}
				//// Clone me, returning a RNG with the same state.
    virtual  RiRandomStrategy  *Clone() = 0;
    // GROUP: Members
				//// Seed the Strategy
    virtual void SetSeed(long seed = 0)=0;
				//// Fill an array with RI_RANDOM_ARRAY_SIZE random numbers
    virtual void Generate(RiReal *data, int num = RI_RANDOM_ARRAY_SIZE)=0;
};




/***************************************************************
CLASS
    RiRandom
     Encapsulates Random Numbers

DESCRIPTION

METHOD
METHOD: DRand48
     Drand48 is a Wrapper around drand48.  Keeps state so each RiRandom is an independent stream.
METHOD: NonRandom
     NonRandom returns .5 always.  Good for testing, makes the sampling code orthogonal
     to the random number code.
WARNING
     Passing by value creates a copy which forks off the random stream,
     Repeated copies from the same base will give the same sequence. Passing
     by reference is much more efficient, and will keep things random.

****************************************************************/

class RiRandom {
  public:
    enum Method {DRand48, NonRandom, Shuffle};
    // GROUP: Constructors and assignment
    //// Default Constructor
    RiRandom(long seed = 0, Method meth = DRand48);
    ////Copy Constructor
    RiRandom(const RiRandom &);
    //// Assignment 
    const RiRandom &operator=(const RiRandom &);
    //// Destructor
    ~RiRandom();
    // GROUP: Accessors
    //// Set the seed in the generator 
    void   SetSeed(int seed = 0);
    //// Return a random number in [0,1)
    RiReal operator()();
    //// Return a random number in [min,max)
    RiReal operator()(RiReal min, RiReal max);
  private:
    RiReal	generated[RI_RANDOM_ARRAY_SIZE];
    int		cur;
    RiRandomStrategy  *generator;
};


inline RiReal RiRandom::operator()()
{
    if(cur >= RI_RANDOM_ARRAY_SIZE) {
	generator->Generate(generated);
	cur = 0;
    }
    return generated[cur++];
}

inline RiReal RiRandom::operator()(RiReal min, RiReal max)
{
    if(cur >= RI_RANDOM_ARRAY_SIZE) {
	generator->Generate(generated);
	cur = 0;
    }
    return min + (max - min) * generated[cur++];
}


#endif /* RIRANDOM_H */











