/****************************************************************************/
/* Copyright (c) 2015 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  :                                                               */
/* Filename : FastTime.cc                                                    */
/* Author   :                                                               */
/* Project  :                                                               */
/* Version  : 1.0                                                           */
/* Created  : 03/07/2015                                                    */
/* Modified :                                                               */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/****************************************************************************/

#include <time.h>
#include <stdlib.h>
#include "FastTime.h"

/*
CLASS 
FastTime

DESCRIPTION
Artificial time for use in simulation 

AUTHOR
Henthorn
*/

// FASTTIME defined in FastTime.h
//
#ifdef FASTTIME

static FastTime* FastTime::_instance = NULL;
static tri_state_t FastTime::_fastTimeState=UNITIALIZED;
static FastTime _myFastTime;

FastTime::FastTime()
{
}

FastTime::~FastTime()
{
    Boolean debug = False;
    dprintf("**** FastTime destructor ****\n");
}

static FastTime* FastTime::instance()
{
	if (!FastTime::_instance)
	{
        FastTime::_instance = &FastTime::_myFastTime;
	}
	return FastTime::_instance;
}

Boolean FastTime::fastTimeOn()
{
    Boolean debug=False;
    
    // set default return value
    Boolean fastTimeOn=FAST_TIME_DEFAULT;

    // check cached copy
    switch (_fastTimeState) {
        case ENABLED:
        case DISABLED:
            // value has been initialized,
            // return cached value
            fastTimeOn = (_fastTimeState==ENABLED?True:False);
            dprintf("**** FastTime using cached value ****\n");
            break;
        case UNITIALIZED:
        default:
            // local copy uninitialized,
            // read from shmem (must be set by supervisor)
            _time.read();
            switch (_time.data.fastTimeState) {
                case DISABLED:
                case ENABLED:
                    // cache local copy
                    _fastTimeState = _time.data.fastTimeState;
                    // set return value
                    fastTimeOn = (_fastTimeState==ENABLED?True:False);
                    dprintf("**** FastTime using/assigning cacched value ****\n");

                    break;
                default:
                    // undefined, use default
                    // and don't set cached value
                    dprintf("**** FastTime using default ****\n");
                    break;
            }
            break;
    }
    
    return fastTimeOn;
    
}

// Only called when fastsim option is used in a simulation
//
void FastTime::initialize(TimeIF::TimeSpec *ts)
{
  // If no time is passed in, use the current system time
  //
  if (!ts)
  {
    struct timespec timeNow;
    clock_gettime(CLOCK_REALTIME, &timeNow);
    ts = (TimeIF::TimeSpec*)&timeNow;
  }

  _time.data.fastTimeState = ENABLED;
  _time.data.ts.seconds     = ts->seconds;
  _time.data.ts.nanoSeconds = ts->nanoSeconds;

  _time.write();
  printf("\n\n\t\t\t\tFastTime inititalized to epoch %ld.%ld\n\n",
    _time.data.ts.seconds, _time.data.ts.nanoSeconds);
}

void FastTime::getFastTime(struct timespec *ts)
{
	_time.read();
	ts->tv_sec  = _time.data.ts.seconds;
	ts->tv_nsec = _time.data.ts.nanoSeconds;
}

void FastTime::getFastTime(TimeIF::TimeSpec *ts)
{
	_time.read();
	ts->seconds     = _time.data.ts.seconds;
	ts->nanoSeconds = _time.data.ts.nanoSeconds;
}

void FastTime::incrFastTime(int milliseconds)
{
  long GIGASECS = 1000000000L;

  // Increment the artificial clock
  //
  _time.read();
  long ns = _time.data.ts.nanoSeconds + milliseconds*1000000L;
  _time.data.ts.seconds += ns/GIGASECS;
  _time.data.ts.nanoSeconds = ns % GIGASECS;

  _time.write();
}

#endif
