// Copyright (c) 2015, 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 protoc.benchmark.dashboard_model;

import 'generated/benchmark.pb.dart' as pb;

import 'benchmark.dart' show Benchmark;
import 'benchmarks/index.dart' show createBenchmark;

/// Contains the viewable state of the dashboard. (Immutable.)
class DashboardModel {
  final Map<String, pb.Report> savedReports;
  final Table table;
  final pb.Report latest;

  DashboardModel(this.savedReports, this.table, this.latest);

  DashboardModel withBaseline(String name) {
    var nextTable = table.withBaseline(name, savedReports[name]);
    return new DashboardModel(savedReports, nextTable, latest);
  }

  DashboardModel withReport(pb.Report right) =>
      new DashboardModel(savedReports, table, right);

  DashboardModel withTable(Table table) =>
      new DashboardModel(savedReports, table, latest);

  /// Returns true if the Run button should be enabled.
  bool get canRun => !latest.hasStatus() || latest.status != pb.Status.RUNNING;
}

/// The parts of the benchmark results table that don't change often.
class Table {
  final pb.Suite suite;
  final String baseline;
  final pb.Report report;
  final Set<pb.Request> selections;
  final rows = <Row>[];

  factory Table(pb.Suite suite) => new Table._raw(
      suite, null, null, new Set<pb.Request>.from(suite.requests));

  Table._raw(this.suite, this.baseline, this.report, this.selections) {
    Iterator it = report == null ? [].iterator : report.responses.iterator;
    for (var r in suite.requests) {
      var b = createBenchmark(r);
      pb.Sample baseline;
      if (it.moveNext()) {
        b.checkRequest(it.current.request);
        baseline = b.medianSample(it.current);
      }
      rows.add(new Row(r, b, baseline, selected: this.selections.contains(r)));
    }
  }

  Table withBaseline(String baseline, pb.Report report) =>
      new Table._raw(suite, baseline, report, selections);

  Table withAllSelected() {
    return new Table._raw(
        suite, baseline, report, new Set<pb.Request>.from(suite.requests));
  }

  Table withNoneSelected() {
    return new Table._raw(suite, baseline, report, new Set<pb.Request>());
  }

  Table withSelection(pb.Request request, bool selected) {
    var s = new Set<pb.Request>.from(selections);
    if (selected) {
      s.add(request);
    } else {
      s.remove(request);
    }
    return new Table._raw(suite, baseline, report, s);
  }
}

/// The parts of a row in the benchmark results table that don't change often.
class Row {
  final pb.Request request;
  final Benchmark benchmark;
  final pb.Sample baseline;
  final bool selected;
  Row(this.request, this.benchmark, this.baseline, {this.selected = true});

  /// Returns the response that should be displayed in this row.
  pb.Response findResponse(pb.Report r) {
    for (var candidate in r.responses) {
      if (candidate.request == request) return candidate;
    }
    return null;
  }
}

// Indicates that the given item was added or removed from a selection.
class SelectEvent<T> {
  final bool selected;
  final T item;
  SelectEvent(this.selected, [this.item]);
  toString() => "SelectEvent($selected, $item)";
}
