#ifndef _timestamp_h__
#define _timestamp_h__

/** timestamp **
 * 
 * Useful macros and functions to handle timestamps expressed as microseconds since Epoch.
 * 
 */

#include <stdint.h>
#include <time.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifdef _WIN32
#include <windows.h>

#  define CLOCK_REALTIME 0
#  define CLOCK_PROCESS_CPUTIME_ID 0
#  define BILLION (1E9)

struct timezone {
    int tz_minuteswest;
    int tz_dsttime;
};

int clock_gettime(int dummy, struct timespec *ct);
int gettimeofday(struct timeval* tv, struct timezone* tz);
#else
#include <sys/time.h>
#endif

/**
 * One second, i.e. one million microseconds.
 */
#define TIMESTAMP_ONE_SECOND 1000000

/**
 * Return the current system time as a timestamp. Involves a system call.
 */
int64_t timestamp_now();

/**
 * Convert a struct timespec to a timestamp. Loss of precision may occur.
 */
int64_t timestamp_from_timespec(const struct timespec *tp);

/**
 * Convert a timestamp to a struct timespec.
 */
#define timestamp_to_timespec(t, tp) { \
    (tp)->tv_sec = (t) / TIMESTAMP_ONE_SECOND; \
    (tp)->tv_nsec = ((t) % TIMESTAMP_ONE_SECOND) * 1000; \
}

/**
 * Convert a struct timeval to a timestamp.
 */
#define timestamp_from_timeval(tv) \
    ( (int64_t) ( (((int64_t)((tv)->tv_sec)) * TIMESTAMP_ONE_SECOND) + tv->tv_usec ) )

/**
 * Convert a timestamp to a struct timeval.
 */
#define timestamp_to_timeval(t, tv) { \
    (tv)->tv_sec = (t) / TIMESTAMP_ONE_SECOND; \
    (tv)->tv_usec = ((t) % TIMESTAMP_ONE_SECOND); \
}

/**
 * Convert seconds (expressed as a double) to microseconds. Loss of precision may occur.
 */
int64_t timestamp_from_double(double d);

/**
 * Convert microseconds to seconds (expressed as a double).
 */
double timestamp_to_double(int64_t t);

/**
 * Convert microseconds to milliseconds. Loss of precision may occur.
 */
#define timestamp_to_ms(t)  ( ((t) / 1000) + (((t) % 1000) / 500) )


#ifdef __cplusplus
}
#endif

#endif
