/**********************************************************************
 * Copyright (c) 2005, 2006 Scapa Technologies Limited and others
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * $Id: clock.c,v 1.2 2006/10/26 22:40:21 kcallaghan Exp $
 * 
 * Contributors: 
 * Scapa Technologies Limited - Initial API and implementation
 **********************************************************************/

/***********************************************************************
 *
 * File: Event.c
 * Overview: The following code provides a simple clock interface,
 *                               refer to Clock.h for definitions of Clock struct and return
 *                               types. Note that the Clock struct is explicitly allocated
 *                               by user.
 *
 ***********************************************************************/

#include "system.h"

/***********************************************************************
 * Function: ClockMillis
 * Purpose: return milliseconds since arbitrary start point
 * Parameters: 
 * Returns:
 ***********************************************************************/

static int ClockMillis(XINT64 *d)
{
#ifdef WIN32

  GetSystemTimeAsFileTime((LPFILETIME)d);

  (*d) = (((*d) + 5000) / 10000);
#endif
#if defined(SOLARIS) || defined(LINUX) || defined(AIX) || defined(USS) || defined(HPUX) || defined(LINUX_S390) || defined(SOLARIS_I386) 
  struct timeval tv;

  if (gettimeofday(&tv, NULL) < 0)
  {
    return XCLOCK_ERROR_UNKNOWN;
  }

  *d = (tv.tv_sec * 1000) + ((tv.tv_usec + 500) / 1000);
//  (*d) = ((((XINT64)(tv.tv_sec) * 1000) + (((XINT64)(tv.tv_usec) + 500) / 1000)));
  
#endif

  return SUCCESS;
}

int XClockMillis(XINT64 *d) {

#ifdef WIN32
  LARGE_INTEGER time;
  FILETIME ftime;
  LPFILETIME fileTime = &ftime;

  GetSystemTimeAsFileTime(fileTime);

//  (*d) = (((*d) + 5000) / 10000);

  time.LowPart = fileTime->dwLowDateTime; time.HighPart = fileTime->dwHighDateTime;
  *d = (time.QuadPart / 10000L) - 11644473600000L;

#else

  struct timeb t;
  ftime(&t);
  *d = ((XINT64)(t.time))*1000 + t.millitm;

#endif

  return SUCCESS;
}
/***********************************************************************
 * Function: SC_ClockCreate
 * Purpose: Initialises Clock struct with the time of the call. This
 *                               is when the clock was created.
 * Parameters: Clock *, a pointer to a Clock struct.
 * Returns: int, CLOCK_SUCCESS as the routine cannot fail.
 ***********************************************************************/

int XClockCreate(XClock *clock)
{
  int okay;

  if ((okay = ClockMillis(&clock->initial)) != SUCCESS)
  {
    return okay;
  }

  return SUCCESS;
}

/***********************************************************************
 * Function: XClockDelete
 * Purpose: Invalidates the clock struct.
 * Parameters: Clock *, a pointer to a Clock struct.
 * Returns: int, CLOCK_SUCCESS as the routine cannot fail.
 ***********************************************************************/

int XClockDelete(XClock *clock)
{
  return SUCCESS;
}

/***********************************************************************
 * Function: ClockAdjust
 * Purpose: Adjusts clock initial
 * Parameters: Clock *, a pointer to a Clock struct.
 * Returns: int, CLOCK_SUCCESS as the routine cannot fail.
 ***********************************************************************/

int XClockAdjust(XClock *clock, XINT64 adj)
{
  clock->initial = clock->initial + adj;

  return SUCCESS;
}

/***********************************************************************
 * Function: ClockRead
 * Purpose: Returns the number of clock ticks in ticks that have 
 *          passed since creation (modulo adjustment).
 * Parameters: Clock *, a pointer to a Clock struct.
 * Returns: int, CLOCK_SUCCESS, function cannot fail.
 ***********************************************************************/

int XClockRead(XClock *clock, XINT64 *ticks)
{
  int okay;
  XINT64 current;

  if ((okay = ClockMillis(&current)) != SUCCESS)
  {
    return okay;
  }

  *ticks = current - clock->initial;
  
  return SUCCESS;
}

/***********************************************************************
 * Function: XClockWait
 * Purpose: suspend calling thread until (at least) until on the clock
 * Parameters: Clock *, a pointer to a Clock struct.
 * Returns: int, CLOCK_SUCCESS, function cannot fail.
 ***********************************************************************/

int XClockWait(XClock *clock, XINT64 until)
{
  int okay;
  XINT64 current;

  if ((okay = ClockMillis(&current)) != SUCCESS)
  {
    return okay;
  }

  current = current - clock->initial;

  if (until > current)
  {
      long period = (long) (until - current);

#ifdef XCLOCK_PRECISION
      long doirep = period % (XCLOCK_PRECISION);

      period = period - doirep;

      if ((long)(XRandomUniform() * (XCLOCK_PRECISION)) < doirep)
      {
          period = period + (XCLOCK_PRECISION);
      }
#endif

#ifdef WIN32
    (void)Sleep(period * 1);
#endif
#if defined(SOLARIS) || defined(LINUX) || defined(AIX) || defined(USS) || defined(HPUX) || defined(LINUX_S390) || defined(SOLARIS_I386)
    (void)usleep(period * 1000);
#endif
  }

  return SUCCESS;
}

/***********************************************************************
 * EOF
 ***********************************************************************/
