#include "header.h"

namespace sframe {

static size_t
uint_size(uint64_t val)
{
  if (val < 0x08) {
    // Fits in the config byte
    return 0;
  }

  for (unsigned int i = 0; i < 8; i += 1) {
    if ((val >> (8 * i)) == 0) {
      return i;
    }
  }

  return 8;
}

void
encode_uint(uint64_t val, output_bytes buffer)
{
  size_t size = buffer.size();
  for (size_t i = 0; i < size && i < 8; i++) {
    buffer[size - i - 1] = uint8_t(val >> (8 * i));
  }
}

static uint64_t
decode_uint(input_bytes data)
{
  if (!data.empty() && data[0] == 0) {
    throw invalid_parameter_error("Integer is not minimally encoded");
  }

  uint64_t val = 0;
  for (size_t i = 0; i < data.size(); i++) {
    val = (val << 8) + static_cast<uint64_t>(data[i]);
  }
  return val;
}

struct ValueOrLength
{
  bool is_length = false;
  uint8_t value_or_length = 0;

  static ValueOrLength for_u64(uint64_t value)
  {
    if (value >= 0x08) {
      return { true, static_cast<uint8_t>(uint_size(value) - 1) };
    } else {
      return { false, static_cast<uint8_t>(value) };
    }
  }

  static ValueOrLength decode(uint8_t encoded)
  {
    const auto is_length = (encoded & 0x08) != 0;
    const auto value_or_length = (encoded & 0x07);
    return { is_length, static_cast<uint8_t>(value_or_length) };
  }

  uint8_t encode() const
  {
    return (((is_length) ? 1 : 0) << 3) | (value_or_length & 0x07);
  }

  size_t value_size() const
  {
    if (!is_length) {
      return 0;
    }

    return value_or_length + 1;
  }

  std::tuple<uint64_t, input_bytes> read(input_bytes data) const
  {
    if (!is_length) {
      // Nothing to read; value is already in config byte
      return { value_or_length, data };
    }

    const auto size = value_size();
    const auto value = decode_uint(data.subspan(0, size));
    const auto remaining = data.subspan(size);
    return { value, remaining };
  }

private:
  ValueOrLength(bool is_length_in, uint8_t value_or_length_in)
    : is_length(is_length_in)
    , value_or_length(value_or_length_in)
  {
  }
};

struct ConfigByte
{
  ValueOrLength kid;
  ValueOrLength ctr;

  ConfigByte(uint64_t kid_in, uint64_t ctr_in)
    : kid(ValueOrLength::for_u64(kid_in))
    , ctr(ValueOrLength::for_u64(ctr_in))
  {
  }

  explicit ConfigByte(uint8_t encoded)
    : kid(ValueOrLength::decode(encoded >> 4))
    , ctr(ValueOrLength::decode(encoded & 0x0f))
  {
  }

  size_t encoded_size() const
  {
    return 1 + kid.value_size() + ctr.value_size();
  }

  uint8_t encode() const { return (kid.encode() << 4) | ctr.encode(); }
};

Header::Header(KeyID key_id_in, Counter counter_in)
  : key_id(key_id_in)
  , counter(counter_in)
{
  const auto cfg = ConfigByte{ key_id, counter };

  _encoded[0] = cfg.encode();
  _encoded.resize(cfg.encoded_size());

  const auto encoded = output_bytes(_encoded);
  const auto after_cfg = encoded.subspan(1);
  encode_uint(key_id, after_cfg.subspan(0, cfg.kid.value_size()));

  const auto after_kid = after_cfg.subspan(cfg.kid.value_size());
  encode_uint(counter, after_kid.subspan(0, cfg.ctr.value_size()));
}

Header
Header::parse(input_bytes buffer)
{
  if (buffer.size() < Header::min_size) {
    throw buffer_too_small_error("Ciphertext too small to decode header");
  }

  const auto cfg = ConfigByte{ buffer[0] };
  const auto after_cfg = buffer.subspan(1);
  const auto [key_id, after_kid] = cfg.kid.read(after_cfg);
  const auto [counter, _] = cfg.ctr.read(after_kid);
  const auto encoded = buffer.subspan(0, cfg.encoded_size());

  return Header(key_id, counter, encoded);
}

Header::Header(KeyID key_id_in, Counter counter_in, input_bytes encoded_in)
  : key_id(key_id_in)
  , counter(counter_in)
  , _encoded(encoded_in)
{
}

#if 0
std::tuple<Header, input_bytes>
decode(input_bytes buffer)
{
  if (buffer.size() < Header::min_size) {
    throw buffer_too_small_error("Ciphertext too small to decode header");
  }

  const auto cfg = ConfigByte{ buffer[0] };
  const auto after_cfg = buffer.subspan(1);
  const auto [kid, after_kid] = cfg.kid.read(after_cfg);
  const auto [ctr, after_ctr] = cfg.ctr.read(after_kid);
  const auto header = Header{ KeyID(kid), Counter(ctr) };

  return { header, after_ctr };
}

size_t
Header::encode(output_bytes buffer) const
{
  if (buffer.size() < size()) {
    throw buffer_too_small_error("Buffer too small to encode header");
  }

  const auto cfg = ConfigByte{ key_id, counter };
  buffer[0] = cfg.encode();

  const auto after_cfg = buffer.subspan(1);
  encode_uint(key_id, after_cfg.subspan(0, cfg.kid.size()));

  const auto after_kid = after_cfg.subspan(cfg.kid.size());
  encode_uint(counter, after_kid.subspan(0, cfg.ctr.size()));

  return size();
}
#endif

} // namespace sframe
