Source: machine/connectionsTable/connectionsTable.js

const assert = require('../../tools/assert');

const NB_INST_SERIES_3 = require("../constants").NB_INST_SERIES_3;
const NB_HEX_VALUES_PER_INST = require("../constants").NB_HEX_VALUES_PER_INST;
const NB_HEX_VALUES = 16;

/**
 * A connection table was used to define the code in series 3 using voltages and wires
 */
class ConnectionsTable {

  /**
   * Constructs a new instance of ConnectionsTable
   * @param bullGamma the machine to which this drum is attached
   */
  constructor(bullGamma) {
    assert(bullGamma, "bullGamma must not be null or undefined");
    this.bullGamma = bullGamma;
    this.instructions = new Array(NB_INST_SERIES_3);
    this.reset();
  }

  reset() {
    for (let instIndex = 0; instIndex < NB_INST_SERIES_3; ++instIndex) {
      this.instructions[instIndex] = new Array(NB_HEX_VALUES_PER_INST);
      for (var hexIndex = 0; hexIndex < NB_HEX_VALUES_PER_INST; hexIndex++) {
        this.instructions[instIndex][hexIndex] = 0;
      }
    }
  }

  /**
   * Set the Series3's content with hex values
   * @param hexCode a String that represents the new hex values of the array
   */
  setInstructions(hexCode) {
    this.reset();
    let instructions = this.bullGamma.parser.parseInstructions(hexCode);
    if (instructions.length > NB_INST_SERIES_3) {
      throw Error("Instructions number should not be greater than " + NB_INST_SERIES_3);
    }
    for (let instIndex = 0; instIndex < instructions.length; ++instIndex) {
      this.instructions[instIndex] = new Array(NB_HEX_VALUES_PER_INST);
      // NB: .toString() is prefered to .TO/.AD/.OD/.OF so that A100 does not become A10C
      var hex = instructions[instIndex].toString();
      this.instructions[instIndex][3] = parseInt(hex[0], 16);
      this.instructions[instIndex][2] = parseInt(hex[1], 16);
      this.instructions[instIndex][1] = parseInt(hex[2], 16);
      this.instructions[instIndex][0] = parseInt(hex[3], 16);
    }
  }

  /**
   * Sets a value for the given instruction digit
   * @param instIndex The instruction index in the Series3
   * @param hexIndex The index of the hex digit in the instruction (0: OF, 1: OD, 2: AD, 3: TO)
   * @param hexValue The value of the hex digit in base 10 (from 0 to 15)
   */
  setHexValue(instIndex, hexIndex, hexValue) {
    assert(instIndex >= 0, "Instruction index must be >= 0");
    assert(hexIndex >= 0, "Hex digit index must be >= 0");
    assert(hexValue >= 0, "Hex digit must be >= 0");
    assert(instIndex < NB_INST_SERIES_3, "Instruction index " + instIndex + " does not exist (<" + NB_INST_SERIES_3 + ")");
    assert(hexIndex < NB_HEX_VALUES_PER_INST, "Hex digit index " + hexIndex + " does not exist (0: OF, 1: OD, 2: AD, 3: TO)");
    assert(hexValue < NB_HEX_VALUES, "Hex value must be strictly lower that " + NB_HEX_VALUES);
    this.instructions[instIndex][hexIndex] = hexValue;
  }

  /**
   * Returns the instructions digits that by value and ordered by instruction index and hex digit index.
   * The parameters give the instructions to be considered
   * @param startIndex The index of the first instruction
   * @param stopIndex The index of the last instruction (excluded)
   * @param step The step to skip some indices
   */
  _getConnections(startIndex, stopIndex, step) {
    assert(startIndex >= 0, "Incorrect index");
    assert(stopIndex <= NB_INST_SERIES_3, "Incorrect index")
    var connections = new Array(NB_HEX_VALUES);
    for (var hexValue = 0; hexValue < NB_HEX_VALUES; hexValue++) {
      connections[hexValue] = new Array();
    }
    for (var instIndex = startIndex; instIndex < stopIndex; instIndex+=step) {
      for (var hexIndex = 0; hexIndex < NB_HEX_VALUES_PER_INST; hexIndex++) {
        var hexValue = this.instructions[instIndex][hexIndex];
        connections[hexValue].push([instIndex, hexIndex]);
      }
    }
    return connections;
  }

  /**
   * Returns the instructions digits that by value and ordered by instruction index and hex digit index.
   * The instructions considered are only the ones on the top left of the table
   * @returns An array of arrays
   */
  getConnectionsTopLeft() {
    return this._getConnections(0, 16, 1)
  }

  /**
   * Returns the instructions digits that by value and ordered by instruction index and hex digit index.
   * The instructions considered are only the ones on the bottom left of the table
   * @returns An array of arrays
   */
  getConnectionsBottomLeft() {
    return this._getConnections(16, 32, 1)
  }

  /**
   * Returns the instructions digits that by value and ordered by instruction index and hex digit index.
   * The instructions considered are only the ones on the top right of the table
   * @returns An array of arrays
   */
  getConnectionsTopRight() {
    return this._getConnections(32, 48, 1)
  }

  /**
   * Returns the instructions digits that by value and ordered by instruction index and hex digit index.
   * The instructions considered are only the ones on the bottom right of the table
   * @returns An array of arrays
   */
  getConnectionsBottomRight() {
    return this._getConnections(48, 64, 1)
  }

  getInstructionCode(instIndex) {
    return new Instruction(
      this.instructions[instIndex][3],
      this.instructions[instIndex][2],
      this.instructions[instIndex][1],
      this.instructions[instIndex][0],
      this.bullGamma
    ).toString();
  }

  getHexCode() {
    var code = "-- Code généré par le tableau de connexions\n";
    for (var instIndex = 0; instIndex < NB_INST_SERIES_3; instIndex++) {
      code += this.getInstructionCode(instIndex) + "\n";
      // for (var hexIndex = 0; hexIndex < NB_HEX_VALUES_PER_INST; hexIndex++) {
      //   hexValue = this.instructions[instIndex][hexIndex];
      //   code += Number(hexValue).toString(16).toUpperCase();
      // }
      // code += "\n";
    }
    return code;
  }

  toString() {
    return this.getHexCode();
  }

  loadInstructions() {
    this.bullGamma.getSerie(3).setInstructions(this.getHexCode());
  }
}

module.exports.ConnectionsTable = ConnectionsTable;