#ifndef TOOLS
#define TOOLS
#include "MyTools.h"

// BATTERY MEASUREMENT
#define VOLTAGE_MAX 2800   // raw ADC at full charge (~4.2V), calibrated from real devices
#define VOLTAGE_MIN 2000   // raw ADC at empty battery (below BATTERY_TRIGGER=2300)

MyTools::MyTools(){

};

String MyTools::byteToHex(byte inp)
{
  char hi, lo;
  byte b_hi, b_lo;
  b_hi = inp >> 4;
  b_lo = inp & 0x0F;
  // chars[0] = (inp >> 4) + 0x30;
  // chars[1] = (inp & 0x0F) + 0x30;
  if (b_hi > 9)
  {
    hi = (char)(0x37 + b_hi);
  }
  else
  {
    hi = (char)(0x30 + b_hi);
  }

  if (b_lo > 9)
  {
    lo = (char)(0x37 + b_lo);
  }
  else
  {
    lo = (char)(0x30 + b_lo);
  }
  // Serial.println(hi);
  // Serial.println(lo);
  String ret = "";
  ret += hi;
  ret += lo;

  // Serial.println(ret);
  return ret;
}

/**
 * CONVERT HEX TO BINARY
 */
uint8_t MyTools::hex2bin(char ch)
{
  if (ch > 0x60)
  {
    ch -= 0x20;
  }
  return ch < 0x41 ? ch - 0x30 : ch - 0x37;
}

/**
 * @brief Convert one char to decimal digit
 *
 * @param ch
 * @return uint8_t
 */
uint8_t MyTools::dec2bin(char ch)
{
  uint8_t ret = ch - 0x30;
  if (ret < 0 || ret > 9)
  {
    return 0;
  }
  return ret;
}

/**
 * @brief Convert string to uint64_t
 *
 * @param str
 * @return uint64_t
 */
uint64_t MyTools::StringTo64(String str)
{
  uint64_t num = 0;
  for (size_t i = 0; i < str.length(); i++)
  {
    if (str.charAt(i) >= 0x30 && str.charAt(i) <= 0x39)
    {
      num *= 10;
      num += dec2bin(str.charAt(i));
    }
  }
  return num;
}

/**
 * Helper routine to dump a byte array as hex values to Serial.
 */
void MyTools::printHex(byte *buffer, byte bufferSize)
{
  for (byte i = 0; i < bufferSize; i++)
  {
    Serial.print(buffer[i] < 0x10 ? " 0" : " ");
    Serial.print(buffer[i], HEX);
  }
}

/**
 * Helper routine to dump a byte array as dec values to Serial.
 */
void MyTools::printDec(byte *buffer, byte bufferSize)
{
  for (byte i = 0; i < bufferSize; i++)
  {
    Serial.print(buffer[i] < 0x10 ? " 0" : " ");
    Serial.print(buffer[i], DEC);
  }
}

/**
 * @brief BCD to BIN
 *
 * @param bcd
 * @return uint8_t
 */
uint8_t MyTools::bcd2bin(uint8_t bcd)
{
  uint8_t bin = bcd & 0xf0;
  bin >>= 4;
  bin *= 10;
  bin += bcd & 0x0f;
  return bin;
}

/**
 * Helper routine to dump a byte array as hex values to Serial.
 */
void MyTools::dump_byte_array(uint8_t *buffer, uint16_t bufferSize)
{
  for (uint16_t i = 0; i < bufferSize; i++)
  {
    Serial.print(buffer[i] < 0x10 ? " 0" : " ");
    Serial.print(buffer[i], HEX);
  }
  Serial.println();
}
/*
// convert
  char buf[8 * sizeof(num) + 1]; // Assumes 8-bit chars plus zero byte.
  char *str = &buf[sizeof(buf) - 1];
  *str = '\0';
  uint8_t base = 10;
  do
  {
    auto m = num;
    num /= base;
    char c = m - base * num;
    *--str = c < 10 ? c + '0' : c + 'A' - 10;
  } while (num);
  */

void MyTools::convertHexStringToByteArray(uint8_t *buffer, uint64_t len, String cmd)
{
  // uint64_t hexStringLength = cmd.length();
  // for (uint64_t i = 0; i < hexStringLength; i += 2)
  // {
  //   buffer[i / 2] = hex2bin(cmd.charAt(i)) * 16 + hex2bin(cmd.charAt(i + 1));
  // }
  for (uint64_t i = 0; i < len; i++)
  {
    buffer[i] = hex2bin(cmd.charAt(i * 2)) * 16 + hex2bin(cmd.charAt(i * 2 + 1));
  }
}

/**
 * @brief Calculates checksum from string
 *
 * @param cmd
 * @return uint16_t
 */
uint16_t MyTools::calculateCKS(String cmd)
{
  uint16_t ret = 0;
  int hexStringLength = cmd.length();
  for (int i = 0; i < hexStringLength; i += 2)
  {
    ret += hex2bin(cmd.charAt(i)) * 16 + hex2bin(cmd.charAt(i + 1));
  }
  return ret;
}

uint16_t MyTools::calc_battery_percentage(uint16_t adc)
{
  int battery = 100 * (adc - VOLTAGE_MIN) / (VOLTAGE_MAX - VOLTAGE_MIN);
  if (battery < 0)
    battery = 0;
  if (battery > 100)
    battery = 100;
  return battery;
}

/**
 * @brief Parsing payload
 *
 * @param array
 * @param payload
 * @return uint8_t size of elements
 */
uint8_t MyTools::parseMessage(String *array, String payload)
{
  uint32_t p_size = payload.length() + 1;
  char input[p_size];
  payload.toCharArray(input, p_size);
  uint8_t j = 0;
  for (uint32_t ii = 0; ii < p_size; ii++)
  {
    // ii=1 skip first character '/'
    if (input[ii] == '/')
    {
      j++;
      if (j >= 7)
        break;
      array[j] = "";
    }
    else
    {
      array[j] += input[ii];
    }
  }
  return j;
}

/**
 * @brief Compare arrays. Limited to 256 elements
 *
 * @param size
 * @param arr1
 * @param arr2
 * @return true
 * @return false
 */
bool MyTools::compareByteArrays(size_t size, uint8_t *card_code, char *pass)
{
  for (size_t i = 0; i < size; i++)
  {
    // Serial << "i: "<<i<<" upcard " << card_code[i] << " pass " << pass[i] << endl;
    if (card_code[i] != (uint8_t)pass[i])
    {
      return false;
    }
  }
  return true;
}

bool MyTools::isTimeValid(uint8_t *buffer)
{
  // check year 20 22 03 28 18 55 20 22 03 20 14 30 00 00 00 17
  // Serial << "year1 " << buffer[0] << endl;
  if (buffer[0] < 0x20) // after 2000
    return false;
  // Serial << "year2 " << buffer[0] << endl;
  if (buffer[0] > 0x30) // before 3000
    return false;
  // Serial << "year3 " << buffer[1] << endl;
  if (buffer[1] > 0x99)
    return false;
  // Serial << "mont " << buffer[2] << endl;
  if (buffer[2] > 0x12) // validate month
    return false;
  // Serial << "day " << buffer[3] << endl;
  if (buffer[3] > 0x31) // validate day
    return false;
  // Serial << "hour " << buffer[4] << endl;
  if (buffer[4] > 0x24) // validate hour
    return false;
  //  Serial << "minutes " << buffer[5] << endl;
  if (buffer[5] > 0x59) // validate minutes
    return false;

  return true;
}
#endif