// Random Number Generator
//
// For ECS 110 - UC Davis - Coverted to C++ by Ted Krovetz
//
// Implementation based on block cipher RC5 which is copywritten.
// RC5REF.C -- Reference implementation of RC5-32/12/16 in C.
// Copyright (C) 1995 RSA Data Security, Inc. Patent Pending.
//
// Version 1.0  - Initial implementation
//         1.01 - Made data static
//         1.02 - Added get_rand_bit()

#ifndef RANDOM_H
#define RANDOM_H

#include <limits.h>

#if UINT_MAX == 0xffffffffu
  typedef unsigned int WORD;    // Should be 32-bit = 4 bytes
#elif ULONG_MAX == 0xffffffffu
  typedef unsigned long WORD;   // Should be 32-bit = 4 bytes
#elif USHRT_MAX == 0xffffffffu
  typedef unsigned short WORD;  // Should be 32-bit = 4 bytes
#else
  !! Error -- This computer does not support 32-bit words
#endif


// ----------------------------------------------------------------------

class Random {
public:
  Random(void);                    // Automatic Weak Constructor
  Random(WORD seed);               // Weak Constructor, 4 bytes
  Random(unsigned char seed[]);    // Strong Constructor, 16 bytes 
  WORD get_rand(WORD min_val, WORD max_val); // Returns random min..max
  int get_rand_bit(void);          // Returns random 0 or 1
  WORD get_next_WORD(void);        // Returns random unsigned 32-bits

private:
  static int one_is_saved;
  static WORD saved;
  static WORD counter[2];
  static WORD *S;      // key table

  void aux_init(unsigned char K[]);
};

// ----------------------------------------------------------------------

// Random is a C++ class which produces pseudo random numbers. Seeding
// the generator is done automatically in the constructor. The type
// of the output is 'WORD' which is always 32-bits and unsigned. Standard
// C++ conversions will be applied if the output is assigned to a
// smaller or larger type.
//
// For debugging purposes, you may want to seed the generator
// with a known value. To do so, pass the constructor a value.
//
// get_rand(WORD min_val, WORD max_val) returns an integer at
// least min_val and at most max_val.
//
// int get_rand_bit(void) efficiently returns random 0 or 1
//
// get_next_WORD(void) returns a random unsigned 32-bit quantity
//
// NOTES: The class data is static and initialized only once per program
//        execution. The data is initialized by the first (temporal) call to
//        any of the constructors. Subsequent invocations of the no-argument
//        constructor are bypassed. Invocations of the constructors with 
//        arguments modify the class data to reflect the invocation. The
//        benefit of this arrangement is to allow local Random objects
//        without incurring reconstruction each time.
//
// EXAMPLE: Output 100 numbers from 1 to 10
//
// #include "Random.h"
//
// Random r;
//
// void main(void)
// {
//   for (int i = 0; i < 100; i++)
//     cout << r.get_rand(1,10) << endl;
// }

#endif