//
//    FILE: UUID.cpp
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.5
//    DATE: 2022-06-14
// PURPOSE: Arduino Library for generating UUID's
//     URL: https://github.com/RobTillaart/UUID
//          https://en.wikipedia.org/wiki/Universally_unique_identifier


#include "Uuid.h"


UUID::UUID()
{
  seed(1, 2);
  setVariant4Mode();
  generate();
}


void UUID::seed(uint32_t s1, uint32_t s2)
{
  //  set Marsaglia constants, prevent 0 as value
  if (s1 == 0) s1 = 1;
  if (s2 == 0) s2 = 2;
  _m_w = s1;
  _m_z = s2;
}


//  check version 0.1.1 for more readable code
void UUID::generate()
{
  uint32_t ar[4];
  for (uint8_t i = 0; i < 4; i++)
  {
    ar[i] = _random();
    //  store binary version globally ?
    //  _ar[i] = ar[i];
  }
  //  Conforming to RFC 4122 Specification
  //  - byte 7: four most significant bits ==> 0100  --> always 4
  //  - byte 9: two  most significant bits ==> 10    --> always {8, 9, A, B}.
  //
  //  patch bits for version 1 and variant 4 here
  if (_mode == UUID_MODE_VARIANT4)
  {
    ar[1] &= 0xFFF0FFFF;   //  remove 4 bits.
    ar[1] |= 0x00040000;   //  variant 4
    ar[2] &= 0xFFFFFFF3;   //  remove 2 bits
    ar[2] |= 0x00000008;   //  version 1
  }

  //  process 16 bytes build up the char array.
  for (uint8_t i = 0, j = 0; i < 16; i++)
  {
    //  multiples of 4 between 8 and 20 get a -.
    //  note we are processing 2 digits in one loop.
    if ((i & 0x1) == 0)
    {
      if ((4 <= i) && (i <= 10)) 
      {
        _buffer[j++] = '-';
      }
    }

    //  process one byte at the time instead of a nibble
    uint8_t nr   = i / 4;
    uint8_t xx   = ar[nr];
    uint8_t ch   = xx & 0x0F;
    _buffer[j++] = (ch < 10) ? '0' + ch : ('a' - 10) + ch;

    ch = (xx >> 4) & 0x0F;
    ar[nr] >>= 8;
    _buffer[j++] = (ch < 10) ? '0' + ch : ('a' - 10) + ch;
  }

  //  if (_upperCase)
  //  {
  //    for (int i = 0; i < 37; i++)
  //    {
  //      _buffer[i] = toUpper(_buffer[i]);
  //    }
  //  }
  _buffer[36] = 0;
}


char * UUID::toCharArray()
{
  //  if (_upperCase)
  //  {
  //    for (int i = 0; i < 37; i++)
  //    {
  //      _buffer[i] = toLower(_buffer[i]);
  //    }
  //  }
  //  else
  //  {
  //    for (int i = 0; i < 37; i++)
  //    {
  //      _buffer[i] = toLower(_buffer[i]);
  //    }
  //  }
  return _buffer;
}


//////////////////////////////////////////////////
//
//  MODE
//
void UUID::setVariant4Mode()
{
  _mode = UUID_MODE_VARIANT4;
}


void UUID::setRandomMode()
{
  _mode = UUID_MODE_RANDOM;
}


uint8_t UUID::getMode()
{
  return _mode;
}


//////////////////////////////////////////////////
//
//  PRINTING
//
size_t UUID::printTo(Print& p) const
{
  return p.print(_buffer);
}


//////////////////////////////////////////////////
//
//  CASE
//
//  void UUID::setLowerCase()
//  {
//    _upperCase = false;
//  }
//
//
//  void UUID::setUpperCase()
//  {
//    _upperCase = true;
//  }


//////////////////////////////////////////////////
//
//  PRIVATE
//



//////////////////////////////////////////////////
//
//  RANDOM GENERATOR MARSAGLIA
//
//  An example of a simple pseudo-random number generator is the
//  Multiply-with-carry method invented by George Marsaglia.
//  two initializers (not null)
uint32_t UUID::_random()
{
  _m_z = 36969L * (_m_z & 65535L) + (_m_z >> 16);
  _m_w = 18000L * (_m_w & 65535L) + (_m_w >> 16);
  return (_m_z << 16) + _m_w;  //   32-bit result
}


//  -- END OF FILE --
