printAcm method

void printAcm ()

Prints the access control matrix in a human-understandable format.

┌──────────┬──────────┬──────────┬──────────┐
│   ACM    │  obj-1   │  Obj-2   │  obj-3   │
├──────────┼──────────┼──────────┼──────────┤
│  us-1, U │   -xw    │   r--    │   -xw    │
├──────────┼──────────┼──────────┼──────────┤
│  us-2, U │   rxw    │   --w    │   r--    │
├──────────┼──────────┼──────────┼──────────┤
│   o-1, O │   -x-    │   -xw    │   --w    │
├──────────┼──────────┼──────────┼──────────┤
│ Of-02, O │   r-w    │   rxw    │   rx-    │
├──────────┼──────────┼──────────┼──────────┤
│ admin, A │   r-w    │   --w    │   rxw    │
└──────────┴──────────┴──────────┴──────────┘

Implementation

void printAcm() {
  if (objects.isEmpty && subjects.isEmpty) {
    stdout.writeln('The matrix is empty');
  }

  var rows = subjects.length + 1;
  var cols = objects.length + 1;

  var matrix = List.generate(rows, (_) => List<String>(cols));

  var width = 3; // Starts with 3 since 'ACM' is "widest"

  // Iterate over rows
  for (var r = 0; r < rows; r++) {
    // Iterate over columns
    for (var c = 0; c < cols; c++) {
      // This is the first square
      if (r == 0 && c == 0) {
        matrix[0][0] = 'ACM';
      }

      // We know that r_0 is dealing with objects (top row)
      if (r == 0 && c > 0) {
        var o = objects[c - 1].shorthand();
        matrix[0][c] = o;
        if (o.length > width) width = o.length;
      }

      // We know that c_0 is dealing with subjects (left column)
      if (r > 0 && c == 0) {
        var s = subjects[r - 1].shorthand();
        matrix[r][0] = s;
        if (s.length > width) width = s.length;
      }

      if (r > 0 && c > 0) {
        // TODO: complete the cell data.
        // Currently generating random information in the cell
        var options = ['rxw', 'rx-', 'r-w', 'r--', '-xw', '-x-', '--w'];
        matrix[r][c] = options[Random().nextInt(options.length)];

        if (matrix[r][c].length > width) width = matrix[r][c].length;
      }
    }
  }

  // Handles actual printing

  width = width + 2; // addds padding
  var hline = (Runes.horizontalLine * width);

  for (var r = 0; r < rows; r++) {
    var line = '';
    var rowString = '';

    // TOP LINE
    if (r == 0) {
      line = Runes.cornerTopLeft +
          (hline + Runes.wallTop) * (objects.length) +
          hline +
          Runes.cornerTopRight;
      stdout.writeln(line);
    }

    for (var c = 0; c < cols; c++) {
      var pSize = width - (matrix[r][c] == null ? 0 : matrix[r][c].length);
      var lPad = (r > 0 && c == 0) ? pSize - 1 : (pSize ~/ 2);
      var rPad = pSize - lPad;

      rowString = rowString +
          Runes.verticalLine +
          (' ' * lPad) +
          (matrix[r][c] ?? '') +
          (' ' * rPad);
    }

    line = Runes.wallLeft +
        (hline + Runes.cross) * (cols - 1) +
        hline +
        Runes.wallRight;
    stdout.writeln(rowString + Runes.verticalLine);

    // BOTTOM LINE
    if (r == rows - 1) {
      line = Runes.cornerBotLeft +
          ((hline + Runes.wallBot) * (cols - 1)) +
          (hline + Runes.cornerBotRight);
      // break;
    }
    stdout.writeln(line);
  }
}