////////////////////////////////////////////////////////////////
//
// 
// Copyright (c) 2002 by Wesley H. Huang.  All rights reserved.
// 
////////////////////////////////////////////////////////////////
#include "utilities.h"
#include <string.h>
#include <iostream>

// Skip over any comments (lines which start with '#') and over any
// whitespace (spaces, tabs, and newlines).
//
void skipComments(std::ifstream& f)
{
  char c;
  while (!f.eof()) {
    f.get(c);
    if (c == '#') {
      // skip over a comment line
      while (c != '\n') {
	if (f.eof()) break;
	f.get(c);
      }
    }
    else if (c == '\n' || c == ' ' || c == '\t')
      // keep reading characters if it's whitespace
      continue;
    else {
      // if c is the next real character in the file, put it back!
      f.putback(c);
      break;
    }
  }
}


string getWord(char *parameter, char *description, std::ifstream &inpFile,
	       bool verbose)
{
  string tmp;

  if (verbose) cout << "Looking for " << description << " declaration..." 
		    << endl;
  skipComments(inpFile);
  inpFile >> tmp;
  if (tmp != parameter) {
    cerr << "Didn't find the " << description << " declaration;"  <<
      "Instead found \"" << tmp << "\"." << endl;
    exit(1);
  }
  inpFile >> tmp;
  if (verbose) cout << "The " << description << " is \"" << tmp
		    << "\"." << endl;
  return tmp;
}

double getNumber(char *parameter, char *description, std::ifstream &inpFile,
		 bool verbose)
{
  string tmp;
  double tmpval;
  
  if (verbose) cout << "Looking for " << description << " declaration..." 
		    << endl;
  skipComments(inpFile);
  inpFile >> tmp;
  if (tmp != parameter) {
    cerr << "Didn't find the " << description << " declaration;"  <<
      "Instead found \"" << tmp << "\"." << endl;
    exit(1);
  }
  inpFile >> tmpval;
  if (verbose) cout << "The " << description << " is \"" << tmpval
		    << "\"." << endl;
  return tmpval;
}
////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////
//
// Implementation of a random number generator that draws from a
// gaussian distribution.  The underlying (uniform deviate)
// pseudorandom number generator is the Park and Miller "Minimum
// standard" generator with Bayes-Durham shuffle
//
// Copyright (c) 2001 Wesley H. Huang.  All rights reserved.
//
#include <math.h>
//#include "rand.h"

long pmRand();
void pmRandSeed(long s);
long pmRand();
long pmRandShuffle();
float myRand();

//
// returns a number drawn from a gaussian distribution with the
// specified mean and standard deviation
// 
float gaussian(float mean, float stdev)
{
  static bool cached = false;
  static float extra;  	// the extra number from a 0 mean unit stdev gaussian

  if (cached) {
    cached = false;
    return extra*stdev + mean;
  }
  else {
    // pick a random point in the unit circle (excluding the origin)
    float a,b,c;
    do {
      a = 2*myRand()-1.0;
      b = 2*myRand()-1.0;
      c = a*a + b*b;
    }
    while (c >= 1.0 || c == 0.0);
    // transform it into two values drawn from a gaussian
    float t = sqrt(-2*log(c)/c);
    extra = t*a;
    cached = true;
    return t*b*stdev + mean;
  }
}

// default random generator seed (nothing special about this number
// except that it's not 0)
const long defaultSeed = 18846224; 
long pmRandGenSeed = defaultSeed;

// set the seed (optional)
void pmRandSeed(long s)
{
  if (s == 0) // can't use 0 as a seed
    pmRandGenSeed = defaultSeed;	// use the default
  else
    pmRandGenSeed = s;
}
 
// parameters for the random number generator
const long a = 16807;
const long m = 2147483647;
const long q = m/a;		// 127773
const long r = m % a;		// 2836
const long pmRandMax = m;

// Park and Miller's "Minimal Standard" generator using Schrage's
// method to do the computation in 32 bit arithmetic without overflow.
//
// This is a multiplicative congruential generator: I_{j+1} = a I_j mod m
// using the above constants (which are very carefully picked).
//
// The result is an integer between 1 and m-1 inclusive.
//
// Reference: Numerical Recipes in C, 2nd ed, pg 278.
long pmRand()
{

  long k = pmRandGenSeed/q;
  pmRandGenSeed = a*(pmRandGenSeed - k*q) - r*k;
  if (pmRandGenSeed < 0)
    pmRandGenSeed += m;
  return pmRandGenSeed;
}

// the Bayes-Durham shuffle
long pmRandShuffle()
{
  const int size = 32;
  const long div = 1 + (pmRandMax-1)/size;
  static bool initialized = false;
  static long rn[size];
  static long next;
  int index;

  if (!initialized) {
    for (int k= 0; k < size; k++) // warm up
      pmRand();
    for (int k= 0; k < size; k++) // fill table
      rn[k] =pmRand();
    next = pmRand();
    initialized = true;
  }
  index = next/div;		// find out which table entry to use next
  next = rn[index];		// that random nember determines the next index
  rn[index] = pmRand();		// refill the table slot
  return next;			// return the random number
}
  
// 
// This is a simple but pretty good random number generator.  I am
// providing it so that everyone will have the same sequence of
// pseudorandom numbers which will probably be useful for me for
// testing.
//
// Returns a floating point number in (0.0, 1.0)
float myRand()
{
  return pmRandShuffle()/(pmRandMax + 1.0);
}

void myRandSeed(long s)
{
  pmRandSeed(s);
}
