/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Clock.cc: C++ Class provides timing and pseudo-random number generation services
//           based upon the system clock. 
//
// Copyright 2006 National Center for Ecological Analysis and Synthesis (NCEAS)
// Author: Rick Reeves, NCEAS Scientific Programmer
// 
// Please see the top of each class method for descriptions
//
// Note: the header file clock.h contains the formal class definition
//
/////////////////////////////////////////////////////////////////////////////////////////////////

//-----------------------------------
// Clock.cpp:  Clock class definition

//      Rick Reeves, August 2006
//-----------------------------------
           
#include "Clock.h"
#include <cstdlib>
#include <stdio.h>
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Clock class constructor
//
// Copyright 2006 National Center for Ecological Analysis and Synthesis (NCEAS)
// Author: Rick Reeves, NCEAS Scientific Programmer
// 
// initializes class member variables
//
/////////////////////////////////////////////////////////////////////////////////////////////////
Clock::Clock()
{ 
//----------------------------------------------------------
// Default constructor: 
// Set the base time with a call to the system time function
//----------------------------------------------------------
    time(&lCurrentTime);
    lBaseTime          = lCurrentTime;
    lStartingTime      = lBaseTime;
    ulElapsedTimeInSec = 0l;
//
// RR 12/6/06:
// for random number cache method
//
    lRandomCacheCount = 0l;
}
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Clock class default class destructor
//
// Copyright 2006 National Center for Ecological Analysis and Synthesis (NCEAS)
// Author: Rick Reeves, NCEAS Scientific Programmer
// 
// Called when class member goes out of scope. currently has no statements, but could later on....
//
/////////////////////////////////////////////////////////////////////////////////////////////////
Clock::~Clock()
{
//--------------------------------------------------
// Default destructor:
// Destroy all component objects, other housekeeping
//--------------------------------------------------
}
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Clock class method: GetNextTick()
//
// Copyright 2006 National Center for Ecological Analysis and Synthesis (NCEAS)
// Author: Rick Reeves, NCEAS Scientific Programmer
// 
// This method pauses for one clock second, then resets the base time and exits.
//
/////////////////////////////////////////////////////////////////////////////////////////////////
const unsigned long Clock::GetNextTick() 
{ 
   time_t lTimeDelta = (time_t) 0l;                                    
                                
// Method polls system time until one second has elapsed. 

   do
   {
       time(&lCurrentTime);               // Returns number of seconds since 1970
       lTimeDelta = lCurrentTime - lBaseTime;
   }  while (lTimeDelta == 0);            // Keep going until one second has elapsed 

//----------------
// Reset base time
//----------------
lBaseTime = lCurrentTime;
return (unsigned long) lCurrentTime;
}
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Clock class method: GetStartingTime()
//
// Copyright 2006 National Center for Ecological Analysis and Synthesis (NCEAS)
// Author: Rick Reeves, NCEAS Scientific Programmer
// 
// This method returns value of private class member lStartingTime.
//
/////////////////////////////////////////////////////////////////////////////////////////////////
   
const unsigned long Clock::GetStartingTime() 
{
   time(&lStartingTime);
   return lStartingTime;
}                                          
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Clock class method: GetCurrentTime()
//
// Copyright 2006 National Center for Ecological Analysis and Synthesis (NCEAS)
// Author: Rick Reeves, NCEAS Scientific Programmer
// 
// This method returns value of private class member lCurrentTime.
//
/////////////////////////////////////////////////////////////////////////////////////////////////
const unsigned long Clock::GetCurrentTime() 
{
   time(&lCurrentTime);
   return lCurrentTime;
}                                          
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Clock class method: GetElapsedTimeInSec()
//
// Copyright 2006 National Center for Ecological Analysis and Synthesis (NCEAS)
// Author: Rick Reeves, NCEAS Scientific Programmer
// 
// This method calculates the time in seconds elapsed since the last initialization of lStartingTime. .
//
/////////////////////////////////////////////////////////////////////////////////////////////////
const unsigned long Clock::GetElapsedTimeInSec()
{
   return lCurrentTime - lStartingTime;
}     
//
// RR 12/4/06: The following functions implement pseudo-random number generation functionality
//
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Clock class method: SetRandomSeed()
//
// Copyright 2006 National Center for Ecological Analysis and Synthesis (NCEAS)
// Author: Rick Reeves, NCEAS Scientific Programmer
// 
// This method sets the system-based pseudo-random number generator seed using the latest time
// (in 1/100 seconds since 1970) supplied by the system clock. This time is, of course, non-repeating 
// (at least for the forseeable future) and continually increasing at the rate of 1 second / second.
// So, it is the perfect place to get a unique seed for the pseudo random number generator.
//
/////////////////////////////////////////////////////////////////////////////////////////////////
void Clock::SetRandomSeed()
{
   time_t NextTick;
//
// (re)set random number seed from system clock
//
   NextTick = clock();             // Integer value of hundredth sec clock tick
   srand(NextTick);   
// 
// ok, the sytstem's random number generator is reset.
//
}
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Clock class method: FillRandomCache()
//
// Copyright 2006 National Center for Ecological Analysis and Synthesis (NCEAS)
// Author: Rick Reeves, NCEAS Scientific Programmer
// 
// This method generates a pseudo-random number series and stores it in the RandomCache vector.
// This vector will be periodically refilled with pseudo-random numbers whenever the calling 
// application exhausts the cache. 
//
/////////////////////////////////////////////////////////////////////////////////////////////////
unsigned long Clock::FillRandomCache()
{
    unsigned long lCtr = 0; 
//
// Generate and store a series of RANDOM_CACHE_SIZE pseudo-random numbers in the RandomCache buffer 
//
    SetRandomSeed();
//
// lets delay for half a second to possibly allow system clock to advance
// 
    this->DelayForCentiSec(50);
    for (lCtr = 0; lCtr < RANDOM_CACHE_SIZE; lCtr++)
    {
        RandomCache[lCtr] = rand();
    }
    lRandomCacheCount = RANDOM_CACHE_SIZE;
    lNextRandomVal = 0;
    return(lRandomCacheCount);
}
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Clock class method: GetNextRandValFromCache()
//
// Copyright 2006 National Center for Ecological Analysis and Synthesis (NCEAS)
// Author: Rick Reeves, NCEAS Scientific Programmer
// 
// This method retrieves a single pseudo-random value from the random cache. If the cache
// is empty, the cache will be refilled.
//
//
/////////////////////////////////////////////////////////////////////////////////////////////////
int Clock::GetNextRandValFromCache()
{
    int iRandVal = 0;
    unsigned long lCacheCount;

    if (lRandomCacheCount == 0)
    {
       lCacheCount = FillRandomCache();
    }
//
// now, get and return a random number
//
    iRandVal = RandomCache[lNextRandomVal];
    lNextRandomVal++;
    lRandomCacheCount--;      
//
    return(iRandVal);
}
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Clock class method: DelayForCentiSec()
//
// Copyright 2006 National Center for Ecological Analysis and Synthesis (NCEAS)
// Author: Rick Reeves, NCEAS Scientific Programmer
// 
// This method pauses the calling program by the user-specified number of 1/100 seconds.
//
/////////////////////////////////////////////////////////////////////////////////////////////////
void Clock::DelayForCentiSec(clock_t WaitTimeInCentiSec)
{
   clock_t Goal;
   clock_t NextTick;
   NextTick = clock();
   Goal = WaitTimeInCentiSec + NextTick;

   while (Goal > clock());  // Loop (this line only) iterates until clock reaches Goal
}

