/**
 * @file provsql_utils_cpp.cpp
 * @brief C++ UUID utility function implementations.
 *
 * Implements the C++ helper functions declared in @c provsql_utils_cpp.h:
 * - @c uuid2string(): format a @c pg_uuid_t as a 36-char hyphenated hex string.
 * - @c string2uuid(): parse a UUID string into a @c pg_uuid_t.
 * - @c UUIDDatum2string(): extract and format a UUID from a PostgreSQL @c Datum.
 * - @c hash_value(): Boost-compatible hash for @c pg_uuid_t.
 * - @c operator==(): byte-level equality for @c pg_uuid_t.
 *
 * The @c uuid2string and @c string2uuid functions are adapted from
 * PostgreSQL's own @c uuid.c, which is not exposed as a public API.
 */
extern "C" {
#include "postgres.h"
#include "utils/uuid.h"

#include "provsql_utils.h"
}

#include "provsql_utils_cpp.h"
#include <cassert>
#include "Circuit.h"

using namespace std;

string uuid2string(pg_uuid_t uuid) {
/* copied with small changes from uuid.c */
  static const char hex_chars[] = "0123456789abcdef";
  string result;

  for (int i = 0; i < UUID_LEN; i++)
  {
    if (i == 4 || i == 6 || i == 8 || i == 10)
      result += '-';

    int hi = uuid.data[i] >> 4;
    int lo = uuid.data[i] & 0x0F;

    result+=hex_chars[hi];
    result+=hex_chars[lo];
  }

  return result;
}

/**
 * @brief Parse a UUID string into a @c pg_uuid_t.
 * @param source  UUID string in standard hyphenated hex format.
 * @return        The parsed @c pg_uuid_t value.
 */
pg_uuid_t string2uuid(const string &source)
/* copied with small changes from uuid.c */
{
  const char *src = source.c_str();
  pg_uuid_t uuid;
  bool braces = false;
  int i;

  if (src[0] == '{')
  {
    src++;
    braces = true;
  }

  for (i = 0; i < UUID_LEN; i++)
  {
    char str_buf[3];

    if (src[0] == '\0' || src[1] == '\0')
      goto syntax_error;
    memcpy(str_buf, src, 2);
    if (!isxdigit((unsigned char) str_buf[0]) ||
        !isxdigit((unsigned char) str_buf[1]))
      goto syntax_error;

    str_buf[2] = '\0';
    uuid.data[i] = (unsigned char) strtoul(str_buf, NULL, 16);
    src += 2;
    if (src[0] == '-' && (i % 2) == 1 && i < UUID_LEN - 1)
      src++;
  }

  if (braces)
  {
    if (*src != '}')
      goto syntax_error;
    src++;
  }

  if (*src != '\0')
    goto syntax_error;

  return uuid;

syntax_error:
  ereport(ERROR,
          (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
           errmsg("invalid input syntax for type %s: \"%s\"",
                  "uuid", src)));
}

string UUIDDatum2string(Datum token)
{
  pg_uuid_t *uuid = DatumGetUUIDP(token);
  return uuid2string(*uuid);
}

std::size_t hash_value(const pg_uuid_t &u)
{
  return *reinterpret_cast<const std::size_t*>(&u);
}

bool operator==(const pg_uuid_t &u, const pg_uuid_t &v)
{
  for(int i=0; i<UUID_LEN; ++i)
    if(u.data[i]!=v.data[i])
      return false;

  return true;
}
