#include "CountdownTimer.h"

#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>

#else // assume POSIX
#  include <stdlib.h>
#  include <sys/resource.h>
// #  include <sys/select.h>
#  include <sys/time.h>
#  include <sys/types.h>
#  include <unistd.h>
#endif

#include "YBWCManager.h"

CountdownTimer* CountdownTimer_Construct(CountdownTimer* pThis, unsigned int nCountdownTime)
{
  pThis->dStartTime     = CountdownTimer_GetTickCount(pThis);
  pThis->nCountdownTime = nCountdownTime;
  pThis->bRunning       = TRUE;
  pThis->bAutoRestart   = FALSE;

  return pThis;
}

void CountdownTimer_Destruct(CountdownTimer* pThis)
{
  if(pThis)
  {
    free(pThis);
  }
}

double CountdownTimer_GetTickCount(CountdownTimer* pThis)
{
  double dResult;

#if defined(_WIN32) || defined(_WIN64)

   dResult = GetTickCount() / 1000.0;

#else // assume POSIX

  struct timeval tv[1];
  struct timezone tz[1];

  tz->tz_minuteswest  = 0;
  tz->tz_dsttime      = 0; // DST_NONE not declared in linux

  if(gettimeofday(tv, tz) == -1) // tz needed at all?
  {
//  my_fatal("now_real(): gettimeofday(): %s\n", strerror(errno));
  }

  dResult = double(tv->tv_sec) + double(tv->tv_usec) * 1E-6;

#endif

  return dResult;
}

void CountdownTimer_Sleep(CountdownTimer* pThis, unsigned int nMilliSeconds)
{
//YBWCManager_Printf(YBWCManager_Instance(), "CountdownTimer_Wait(\n");
#if defined(_WIN32) || defined(_WIN64)

  Sleep(nMilliSeconds);

#else // assume POSIX

  usleep((unsigned long)nMilliSeconds * (unsigned long)1000);

#endif
}

void CountdownTimer_Wait(CountdownTimer* pThis)
{
  double       dActualTime;
  unsigned int nElapsedTime;
  unsigned int nSleepTime;

//YBWCManager_Printf(YBWCManager_Instance(), "CountdownTimer_Wait(\n");

  dActualTime      = CountdownTimer_GetTickCount(pThis);
  nElapsedTime     = (int)((dActualTime - pThis->dStartTime) * 1000.0);
  if(pThis->nCountdownTime <= nElapsedTime)
  {

// kh 04.07.04 (handles also overflow of 4 byte for tick count (in milliseconds) since system startup)
    nSleepTime = 0;
  }
  else
  {
    nSleepTime = pThis->nCountdownTime - nElapsedTime;
    CountdownTimer_Sleep(pThis, nSleepTime);
  }
}

void CountdownTimer_Restart(CountdownTimer* pThis)
{
  pThis->dStartTime = CountdownTimer_GetTickCount(pThis);
  pThis->bRunning   = TRUE;
}

void CountdownTimer_WaitAndRestart(CountdownTimer* pThis)
{
  CountdownTimer_Wait(pThis);
  CountdownTimer_Restart(pThis);
}

void CountdownTimer_StopRunning(CountdownTimer* pThis)
{
  pThis->bRunning = FALSE;
}

void CountdownTimer_SetAutoRestart(CountdownTimer* pThis, BOOL bAutoRestart)
{
  pThis->bAutoRestart = bAutoRestart;
}

BOOL CountdownTimer_IsRunning(CountdownTimer* pThis)
{
  BOOL         bResult;

  double       dActualTime;
  unsigned int nElapsedTime;

  dActualTime      = CountdownTimer_GetTickCount(pThis);
  nElapsedTime     = (int)((dActualTime - pThis->dStartTime) * 1000.0);
  if(    (pThis->nCountdownTime <= nElapsedTime)
      || !pThis->bRunning)
  {
    bResult = FALSE;
    if(pThis->bAutoRestart)
    {
      CountdownTimer_Restart(pThis);
    }
  }
  else
  {
    bResult = TRUE;
  }

  return bResult;
}
