// Released under the MIT License. See LICENSE for details.

#ifndef BALLISTICA_GENERIC_HUFFMAN_H_
#define BALLISTICA_GENERIC_HUFFMAN_H_

#include <vector>

#include "ballistica/core/object.h"

namespace ballistica {

class Huffman {
 public:
  Huffman();
  ~Huffman();

#if HUFFMAN_TRAINING_MODE
  void train(const char* buffer, int len);
#endif

  void build();

  // NOTE: this assumes the topmost bit of the first byte is unused
  // (see details in implementation).
  auto compress(const std::vector<uint8_t>& src) -> std::vector<uint8_t>;
  auto decompress(const std::vector<uint8_t>& src) -> std::vector<uint8_t>;
  auto get_built() const -> bool { return built; }

 private:
  bool built;
#if HUFFMAN_TRAINING_MODE
  uint32_t test_bytes = 0;
  uint32_t test_bits_compressed = 0;
  int total_count = 0;
  int total_length = 0;
#endif

  class Node {
   public:
    Node() = default;

    // Left child index in node array (-1 for none).
    int16_t left_child = -1;

    // Right child index in node array (-1 for none).
    int16_t right_child = -1;

    // Parent index in node array (0 for none - add 255 to this to get actual
    // index).
    uint8_t parent = 0;
    uint8_t bits = 0;
    uint16_t val = 0;
    int frequency = 0;
  };

  Node nodes_[511];
};

}  // namespace ballistica

#endif  // BALLISTICA_GENERIC_HUFFMAN_H_
