//
// Copyright 2014 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
//

part of charted.charts;

/// Transforms the ChartData based on the specified dimension columns and facts
/// columns indices. The values in the facts columns will be aggregated by the
/// tree hierarchy generated by the dimension columns.  Expand and Collapse
/// methods may be called to display different levels of aggregation.
///
/// The output ChartData produced by transform() will contain only columns in the
/// original ChartData that were specified in dimensions or facts column indices.
/// The output column will be re-ordered first by the indices specified in the
/// dimension column indices then by the facts column indices.  The data in the
/// cells of each row will also follow this rule.
class AggregationTransformer extends Observable
    implements ChartDataTransform, ChartData {
  static const String AGGREGATION_TYPE_SUM = 'sum';
  static const String AGGREGATION_TYPE_MIN = 'min';
  static const String AGGREGATION_TYPE_MAX = 'max';
  static const String AGGREGATION_TYPE_VALID = 'valid';
  final SubscriptionsDisposer _dataSubscriptions = new SubscriptionsDisposer();
  final Set<List> _expandedSet = new Set();
  List<ChartColumnSpec> columns;
  ObservableList<List> rows = new ObservableList<List>();
  List<int> _dimensionColumnIndices;
  List<int> _factsColumnIndices;
  String _aggregationType;
  AggregationModel _model;
  bool _expandAllDimension = false;
  List<int> _selectedColumns = [];
  FieldAccessor _indexFieldAccessor =
      (row, index) => (row as List)[index as int];
  ChartData _data;

  AggregationTransformer(this._dimensionColumnIndices, this._factsColumnIndices,
      [String aggregationType = AGGREGATION_TYPE_SUM]) {
    _aggregationType = aggregationType;
  }

  /// Transforms the ChartData base on the specified dimension columns and facts
  /// columns, aggregation type and currently expanded dimensions.
  ChartData transform(ChartData data) {
    assert(data.columns.length > max(_dimensionColumnIndices));
    assert(data.columns.length > max(_factsColumnIndices));
    _data = data;
    _registerListeners();
    _transform();
    return this;
  }

  /// Registers listeners if data.rows or data.columns are Observable.
  _registerListeners() {
    _dataSubscriptions.dispose();

    if (_data is Observable) {
      var observable = (_data as Observable);
      _dataSubscriptions.add(observable.changes.listen((records) {
        _transform();

        // NOTE: Currently we're only passing the first change because the chart
        // area just draw with the updated data.  When we add partial update
        // to chart area, we'll need to handle this better.
        notifyChange(records.first);
      }));
    }
  }

  /// Performs the filter transform with _data.  This is called on transform and
  /// onChange if the input ChartData is Observable.
  _transform() {
    _model = new AggregationModel(
        _data.rows, _dimensionColumnIndices, _factsColumnIndices,
        aggregationTypes: [_aggregationType],
        dimensionAccessor: _indexFieldAccessor,
        factsAccessor: _indexFieldAccessor);
    _model.compute();

    // If user called expandAll prior to model initiation, do it now.
    if (_expandAllDimension) {
      expandAll();
    }

    _selectedColumns.clear();
    _selectedColumns.addAll(_dimensionColumnIndices);
    _selectedColumns.addAll(_factsColumnIndices);

    // Process rows.
    rows.clear();
    var transformedRows = <List>[];
    for (String value
        in _model.valuesForDimension(_dimensionColumnIndices[0])) {
      _generateAggregatedRow(transformedRows, [value]);
    }
    rows.addAll(transformedRows);

    // Process columns.
    columns = new List<ChartColumnSpec>.generate(_selectedColumns.length,
        (int index) => _data.columns.elementAt(_selectedColumns[index]));
  }

  /// Fills the aggregatedRows List with data base on the set of expanded values
  /// recursively.  Currently when a dimension is expanded, rows are
  /// generated for its children but not for itself.  If we want to change the
  /// logic to include itself, just move the expand check around the else clause
  /// and always write a row of data whether it's expanded or not.
  _generateAggregatedRow(
      List<List> aggregatedRows, List<String> dimensionValues) {
    var entity = _model.facts(dimensionValues);
    var dimensionLevel = dimensionValues.length - 1;

    // Dimension is not expanded at this level.  Generate data rows and fill int
    // value base on whether the column is dimension column or facts column.
    if (!_isExpanded(dimensionValues) ||
        dimensionValues.length == _dimensionColumnIndices.length) {
      aggregatedRows.add(new List.generate(_selectedColumns.length, (index) {
        // Dimension column.
        if (index < _dimensionColumnIndices.length) {
          if (index < dimensionLevel) {
            // If column index is in a higher level, write parent value.
            return dimensionValues[0];
          } else if (index == dimensionLevel) {
            // If column index is at current level, write value.
            return dimensionValues.last;
          } else {
            // If column Index is in a lower level, write empty string.
            return '';
          }
        } else {
          // Write aggregated value for facts column.
          return entity['${_aggregationType}(${_selectedColumns[index]})'];
        }
      }));
    } else {
      // Dimension is expanded, process each child dimension in the expanded
      // dimension.
      for (AggregationItem childAggregation in entity.lowerAggregations()) {
        _generateAggregatedRow(aggregatedRows, childAggregation.dimensions);
      }
    }
  }

  /// Expands a specific dimension and optionally expands all of its parent
  /// dimensions.
  void expand(List dimension, [bool expandParent = true]) {
    _expandAllDimension = false;
    _expandedSet.add(dimension);
    if (expandParent && dimension.length > 1) {
      var eq = const ListEquality().equals;
      var dim = dimension.take(dimension.length - 1).toList();
      if (!_expandedSet.any((e) => eq(e, dim))) {
        expand(dim);
      }
    }
  }

  /// Collapses a specific dimension and optionally collapse all of its
  /// Children dimensions.
  void collapse(List dimension, [bool collapseChildren = true]) {
    _expandAllDimension = false;
    if (collapseChildren) {
      var eq = const ListEquality().equals;
      // Doing this because _expandedSet.where doesn't work.
      var collapseList = [];
      for (List dim in _expandedSet) {
        if (eq(dim.take(dimension.length).toList(), dimension)) {
          collapseList.add(dim);
        }
      }
      _expandedSet.removeAll(collapseList);
    } else {
      _expandedSet.remove(dimension);
    }
  }

  /// Expands all dimensions.
  void expandAll() {
    if (_model != null) {
      for (String value
          in _model.valuesForDimension(_dimensionColumnIndices[0])) {
        _expandAll([value]);
      }
      _expandAllDimension = false;
    } else {
      _expandAllDimension = true;
    }
  }

  void _expandAll(List<String> value) {
    var entity = _model.facts(value);
    _expandedSet.add(value);
    for (AggregationItem childAggregation in entity.lowerAggregations()) {
      _expandAll(childAggregation.dimensions);
    }
  }

  /// Collapses all dimensions.
  void collapseAll() {
    _expandAllDimension = false;
    _expandedSet.clear();
  }

  /// Tests if specific dimension is expanded.
  bool _isExpanded(List dimension) {
    var eq = const ListEquality().equals;
    return _expandedSet.any((e) => eq(e, dimension));
  }
}
