/**
 * This class represents a packet containing a header, payload and checksum.
 */
class Packet {
  /**
   * The header is a nibble that contains the length of the payload in
   * bytes.
   *
   * @type {Number[]}
   */
  #header = [];

  /**
   * The payload of the packet. This can be up to 16 bytes in length.
   *
   * @type {Number[]}
   */
  #payload = [];

  /**
   * The checksum of the payload.
   *
   * @type {Number[]}
   */
  #checksum = [];

  /**
   * Creates a new packet with the given text as the payload.
   *
   * @param {String} payloadText
   */
  constructor(payloadText) {
    this.#header = this.#numberToBitArray(payloadText.length, 4);
    this.#payload = this.#textToBitArray(payloadText);
    this.#checksum = this.#calculateChecksum(this.#textToCodePoints(payloadText));
  }

  /**
   * This methods turns a number into an array of bits of the size
   * denoted by length.
   *
   * @param {Number} number
   * @param {Number} length
   * @return {Number[]}
   */
  #numberToBitArray(number, length) {
    const bitArray = [];
    for (var i = length - 1; i >= 0; i--) {
      let bit = number & (1 << i);
      bit = bit ? 1 : 0;
      bitArray.push(bit);
    }
    return bitArray;
  }

  /**
   * Turns a string into an array of ASCII code points.
   *
   * @param {String} text
   * @return {Number[]}
   */
  #textToCodePoints(text) {
    const codePoints = [];
    for (let i = 0; i < text.length; i++) {
      codePoints.push(text.charCodeAt(i));
    }
    return codePoints;
  }

  /**
   * Turns a string into a bit array.
   *
   * @param {String} text
   * @return {Number[]}
   */
  #textToBitArray(text) {
    const codePoints = this.#textToCodePoints(text);
    let bitArray = [];
    for (const codePoint of codePoints) {
      bitArray = bitArray.concat(this.#numberToBitArray(codePoint, 8));
    }
    return bitArray;
  }

  /**
   * Calculates the checksum of the given array of bytes and return it
   * as a bit array.
   *
   * @param {Number[]} bytes
   * @return {Number[]}
   */
  #calculateChecksum(bytes) {
    const checksum = Utility.crc8Autosar(bytes);
    return this.#numberToBitArray(checksum, 8);
  }

  /**
   * Returns all data of the packet as a bit array.
   *
   * @return {Number[]}
   */
  getData() {
    return [...this.#header, ...this.#payload, ...this.#checksum];
  }
}
