// ==============================================================
//	This file is part of Glest Shared Library (www.glest.org)
//
//	Copyright (C) 2005 Matthias Braun <matze@braunis.de>
//
//	You can redistribute this code and/or modify it under
//	the terms of the GNU General Public License as published
//	by the Free Software Foundation; either version 2 of the
//	License, or (at your option) any later version
// ==============================================================
/* what follows is a somewhat stripped-down version of the sample
   implementation of UUID generation from RFC 4122.  */

/*
** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
** Digital Equipment Corporation, Maynard, Mass.
** Copyright (c) 1998 Microsoft.
** To anyone who acknowledges that this file is provided "AS IS"
** without any express or implied warranty: permission to use, copy,
** modify, and distribute this file for any purpose is hereby
** granted without fee, provided that the above copyright notices and
** this notice appears in all source code copies, and that none of
** the names of Open Software Foundation, Inc., Hewlett-Packard
** Company, Microsoft, or Digital Equipment Corporation be used in
** advertising or publicity pertaining to distribution of the software
** without specific, written prior permission. Neither Open Software
** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
** Equipment Corporation makes any representations about the
** suitability of this software for any purpose.
*/

#ifndef _SHARED_PLATFORM_UUID_H_
#define _SHARED_PLATFORM_UUID_H_

//#ifdef HAVE_CONFIG_H
//#include "config.h"
//#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

namespace Shared { namespace Util {

//#if defined(HAVE_INTTYPES_H)
//#include <inttypes.h>
//#endif

/* set the following to the number of 100ns ticks of the actual
   resolution of your system's clock */
#define UUIDS_PER_TICK 1024

//#ifdef WIN32
//#include <windows.h>
//#include "missing\stdint.h"
//#define snprintf _snprintf
//#else
//
//#if HAVE_SYS_TYPES_H
//#include <sys/types.h>
//#else
//# if HAVE_STDINT_H
//#  include <stdint.h>
//# endif
//#endif
//
//#if HAVE_SYS_TIME_H
//#include <sys/time.h>
//#endif
//
//#if HAVE_SYS_SYSINFO_H
//#include <sys/sysinfo.h>
//#endif
//
//#endif

/* system dependent call to get the current system time. Returned as
   100ns ticks since UUID epoch, but resolution may be less than
   100ns. */

#ifdef WIN32
#define I64(C) C
#else
#define I64(C) C##LL
#endif

typedef uint64_t uuid_time_t;

typedef struct {
  char nodeID[6];
} uuid_node_t;

#undef uuid_t
typedef struct {
  uint32_t  time_low;
  uint16_t  time_mid;
  uint16_t  time_hi_and_version;
  uint8_t   clock_seq_hi_and_reserved;
  uint8_t   clock_seq_low;
  uint8_t   node[6];
} uuid_t;

/* some forward declarations.  kind of wimpy to do that but heck, we
   are all friends here right?  raj 20081024 */
inline static uint16_t true_random(void);

#ifdef WIN32

inline static void get_system_time(uuid_time_t *uuid_time) {
  ULARGE_INTEGER time;

  /* NT keeps time in FILETIME format which is 100ns ticks since
     Jan 1, 1601. UUIDs use time in 100ns ticks since Oct 15, 1582.
     The difference is 17 Days in Oct + 30 (Nov) + 31 (Dec)
     + 18 years and 5 leap days. */
  GetSystemTimeAsFileTime((FILETIME *)&time);
  time.QuadPart +=

    (unsigned __int64) (1000*1000*10)       // seconds
    * (unsigned __int64) (60 * 60 * 24)       // days
    * (unsigned __int64) (17+30+31+365*18+5); // # of days
  *uuid_time = time.QuadPart;
}

/* Sample code, not for use in production; see RFC 1750 */
inline static void get_random_info(char seed[16]) {
  uint16_t myrand;
  int i;

  i = 0;
  do {
    myrand = true_random();
    seed[i++] = myrand & 0xff;
    seed[i++] = myrand >> 8;
  } while (i < 14);
}

#else

inline static void get_system_time(uuid_time_t *uuid_time) {
  struct timeval tp;
  gettimeofday(&tp, (struct timezone *)0);

  /* Offset between UUID formatted times and Unix formatted times.
     UUID UTC base time is October 15, 1582.
     Unix base time is January 1, 1970.*/
  *uuid_time = ((uint64_t)tp.tv_sec * 10000000)
    + ((uint64_t)tp.tv_usec * 10)
    + I64(0x01B21DD213814000);
}

/* Sample code, not for use in production; see RFC 1750 */
inline static void get_random_info(char seed[16]) {
  FILE *fp;
  uint16_t myrand;
  int i;

  /* we aren't all that picky, and we would rather not block so we
     will use urandom */
  fp = fopen("/dev/urandom","rb");

  if (NULL != fp) {
    size_t bytes = fread(seed,sizeof(char),16,fp);
    if(bytes <= 0) { }
    fclose(fp);
    return;
  }

  /* ok, now what? */

  i = 0;
  do {
    myrand = true_random();
    seed[i++] = myrand & 0xff;
    seed[i++] = myrand >> 8;
  } while (i < 14);
}

#endif

/* true_random -- generate a crypto-quality random number.
**This sample doesn't do that.** */
inline static uint16_t true_random(void) {
  static int inited = 0;
  uuid_time_t time_now;

  if (!inited) {
    get_system_time(&time_now);
    time_now = time_now / UUIDS_PER_TICK;
    srand((unsigned int) (((time_now >> 32) ^ time_now) & 0xffffffff));
    inited = 1;
  }

  return (uint16_t)rand();
}

/* puid -- print a UUID */
inline void puid(uuid_t u) {
  int i;

  printf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", u.time_low, u.time_mid,
	 u.time_hi_and_version, u.clock_seq_hi_and_reserved,
	 u.clock_seq_low);
  for (i = 0; i < 6; i++)
    printf("%2.2x", u.node[i]);
  printf("\n");
}

/* snpuid -- print a UUID in the supplied buffer */
inline void snpuid(char *str, size_t size, uuid_t u) {
  int i;
  char *tmp = str;

  if (size < 38) {
    snprintf(tmp,size,"%s","uuid string too small");
    return;
  }

  /* perhaps this is a trifle optimistic but what the heck */
  sprintf(tmp,
	  "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-",
	  u.time_low,
	  u.time_mid,
	  u.time_hi_and_version,
	  u.clock_seq_hi_and_reserved,
	  u.clock_seq_low);
  tmp += 24;
  for (i = 0; i < 6; i++) {
    sprintf(tmp,"%2.2x", u.node[i]);
    tmp += 2;
  }
  *tmp = 0;
}

/* get-current_time -- get time as 60-bit 100ns ticks since UUID epoch.
   Compensate for the fact that real clock resolution is
   less than 100ns. */
inline static void get_current_time(uuid_time_t *timestamp) {
  static int inited = 0;
  static uuid_time_t time_last;
  static uint16_t uuids_this_tick;
  uuid_time_t time_now;

  if (!inited) {
    get_system_time(&time_now);
    uuids_this_tick = UUIDS_PER_TICK;
    inited = 1;
  }

  for ( ; ; ) {
    get_system_time(&time_now);

    /* if clock reading changed since last UUID generated, */
    if (time_last != time_now) {
      /* reset count of uuids gen'd with this clock reading */
      uuids_this_tick = 0;
      time_last = time_now;
      break;
    }
    if (uuids_this_tick < UUIDS_PER_TICK) {
      uuids_this_tick++;
      break;
    }
    /* going too fast for our clock; spin */
  }
  /* add the count of uuids to low order bits of the clock reading */
  *timestamp = time_now + uuids_this_tick;
}


/* system dependent call to get IEEE node ID.
   This sample implementation generates a random node ID. */
/* netperf mod - don't bother trying to read or write the nodeid */
inline static void get_ieee_node_identifier(uuid_node_t *node) {
  static int inited = 0;
  static uuid_node_t saved_node;
  char seed[16];

  if (!inited) {
    get_random_info(seed);
    seed[0] |= 0x01;
    memcpy(&saved_node, seed, sizeof saved_node);
  }
  inited = 1;

  *node = saved_node;
}

/* format_uuid_v1 -- make a UUID from the timestamp, clockseq,
   and node ID */
inline static void format_uuid_v1(uuid_t* uuid, uint16_t clock_seq,
                    uuid_time_t timestamp, uuid_node_t node) {
  /* Construct a version 1 uuid with the information we've gathered
     plus a few constants. */
  uuid->time_low = (unsigned long)(timestamp & 0xFFFFFFFF);
  uuid->time_mid = (unsigned short)((timestamp >> 32) & 0xFFFF);
  uuid->time_hi_and_version =
    (unsigned short)((timestamp >> 48) & 0x0FFF);
  uuid->time_hi_and_version |= (1 << 12);
  uuid->clock_seq_low = clock_seq & 0xFF;
  uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8;
  uuid->clock_seq_hi_and_reserved |= 0x80;
  memcpy(&uuid->node, &node, sizeof uuid->node);
}

/* uuid_create -- generator a UUID */
inline int uuid_create(uuid_t *uuid) {
  uuid_time_t timestamp;
  uint16_t clockseq;
  uuid_node_t node;

  /* get time, node ID, saved state from non-volatile storage */
  get_current_time(&timestamp);
  get_ieee_node_identifier(&node);

  /* for us clockseq is always to be random as we have no state */
  clockseq = true_random();

  /* stuff fields into the UUID */
  format_uuid_v1(uuid, clockseq, timestamp, node);
  return 1;
}

inline void get_uuid_string(char *uuid_str, size_t size) {
  uuid_t u;

  uuid_create(&u);
  snpuid(uuid_str,size,u);

  return;
}

inline string getUUIDAsString() {
	char  uuid_str[38];
	get_uuid_string(uuid_str,sizeof(uuid_str));
	return uuid_str;
}

//#ifdef NETPERF_STANDALONE_DEBUG
//
//int
//main(int argc, char *argv[])
//{
//  uuid_t u;
//  char  uuid_str[38];
//#if 0
//  uuid_create(&u);
//  printf("uuid_create(): "); puid(u);
//  snpuid(uuid_str,sizeof(uuid_str),u);
//  printf("\nas a string %s\n",uuid_str);
//#endif
//  get_uuid_string(uuid_str,sizeof(uuid_str));
//  printf("uuid_str is %s\n",uuid_str);
//  return 0;
//}
//
//#endif

}};

#endif
