// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

library vm_snapshot_analysis.ascii_table;

import 'dart:math' as math;

/// A row in the [AsciiTable].
abstract class Row {
  String render(List<int> widths, List<AlignmentDirection> alignments);

  /// Compute the total width of the row given [widths] of individual
  /// columns.
  ///
  /// Note: there is a border on the left and right of each column
  /// plus whitespace around it.
  static int totalWidth(List<int> widths) =>
      widths.fold(0, (sum, width) => sum + width + 3) + 1;
}

enum Separator {
  /// Line separator looks like this: `+-------+------+`
  Line,

  /// Wave separator looks like this: `~~~~~~~~~~~~~~~~`.
  Wave,
}

/// A separator row in the [AsciiTable].
class SeparatorRow extends Row {
  final Separator filler;
  SeparatorRow(this.filler);

  @override
  String render(List<int> widths, List<AlignmentDirection> alignments) {
    final sb = StringBuffer();
    switch (filler) {
      case Separator.Line:
        sb.write('+');
        for (var i = 0; i < widths.length; i++) {
          sb.write('-' * (widths[i] + 2));
          sb.write('+');
        }
        break;

      case Separator.Wave:
        sb.write('~' * Row.totalWidth(widths));
        break;
    }
    return sb.toString();
  }
}

/// A separator row in the [AsciiTable].
class TextSeparatorRow extends Row {
  final Text text;
  TextSeparatorRow(String text)
      : text = Text(value: text, direction: AlignmentDirection.Center);

  @override
  String render(List<int> widths, List<AlignmentDirection> alignments) {
    return text.render(Row.totalWidth(widths));
  }
}

class NormalRow extends Row {
  final List<dynamic> columns;
  NormalRow(this.columns);

  @override
  String render(List<int> widths, List<AlignmentDirection> alignments) {
    final sb = StringBuffer();
    sb.write('|');
    for (var i = 0; i < widths.length; i++) {
      sb.write(' ');
      final text = columns[i] is Text
          ? columns[i]
          : Text(value: columns[i], direction: alignments[i]);
      sb.write(text.render(widths[i]));
      sb.write(' |');
    }
    return sb.toString();
  }
}

enum AlignmentDirection { Left, Right, Center }

/// A chunk of text aligned in the given direction within a cell.
class Text {
  final String value;
  final AlignmentDirection direction;

  Text({this.value, this.direction});
  Text.left(String value)
      : this(value: value, direction: AlignmentDirection.Left);
  Text.right(String value)
      : this(value: value, direction: AlignmentDirection.Right);
  Text.center(String value)
      : this(value: value, direction: AlignmentDirection.Center);

  String render(int width) {
    if (value.length > width) {
      // Narrowed column.
      return value.substring(0, width - 2) + '..';
    }
    switch (direction) {
      case AlignmentDirection.Left:
        return value.padRight(width);
      case AlignmentDirection.Right:
        return value.padLeft(width);
      case AlignmentDirection.Center:
        final diff = width - value.length;
        return ' ' * (diff ~/ 2) + value + (' ' * (diff - diff ~/ 2));
    }
    return null; // Make analyzer happy.
  }

  int get length => value.length;
}

class AsciiTable {
  static const int unlimitedWidth = 0;

  final int maxWidth;

  final List<Row> rows = <Row>[];

  AsciiTable({List<dynamic> header, this.maxWidth = unlimitedWidth}) {
    if (header != null) {
      addSeparator();
      addRow(header);
      addSeparator();
    }
  }

  void addRow(List<dynamic> columns) => rows.add(NormalRow(columns));

  void addSeparator([Separator filler = Separator.Line]) =>
      rows.add(SeparatorRow(filler));

  void addTextSeparator(String text) => rows.add(TextSeparatorRow(text));

  void render() {
    // We assume that the first row gives us alignment directions that
    // subsequent rows would follow.
    List<AlignmentDirection> alignments = rows
        .whereType<NormalRow>()
        .first
        .columns
        .map((v) => v is Text ? v.direction : AlignmentDirection.Left)
        .toList();
    List<int> widths =
        List<int>.filled(rows.whereType<NormalRow>().first.columns.length, 0);

    // Compute max width for each column in the table.
    for (var row in rows.whereType<NormalRow>()) {
      assert(row.columns.length == widths.length);
      for (var i = 0; i < widths.length; i++) {
        widths[i] = math.max(row.columns[i].length, widths[i]);
      }
    }

    if (maxWidth > 0) {
      for (var i = 0; i < widths.length; i++) {
        widths[i] = math.min(widths[i], maxWidth);
      }
    }

    for (var row in rows) {
      print(row.render(widths, alignments));
    }
  }
}
