// Copyright (c) 2011, 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.

part of html_common;

/**
 * An indexable collection of a node's descendants in the document tree,
 * filtered so that only elements are in the collection.
 */
class FilteredElementList implements List {
  final Node _node;
  final List<Node> _childNodes;

  /**
   * Creates a collection of the elements that descend from a node.
   *
   * Example usage:
   *
   *     var filteredElements = new FilteredElementList(query("#container"));
   *     // filteredElements is [a, b, c].
   */
  FilteredElementList(Node node): _childNodes = node.nodes, _node = node;

  // We can't memoize this, since it's possible that children will be messed
  // with externally to this class.
  //
  // TODO(nweiz): we don't always need to create a new list. For example
  // forEach, every, any, ... could directly work on the _childNodes.
  List<Element> get _filtered =>
    new List<Element>.from(_childNodes.where((n) => n is Element));

  void forEach(void f(Element element)) {
    _filtered.forEach(f);
  }

  void operator []=(int index, Element value) {
    this[index].replaceWith(value);
  }

  void set length(int newLength) {
    final len = this.length;
    if (newLength >= len) {
      return;
    } else if (newLength < 0) {
      throw new ArgumentError("Invalid list length");
    }

    removeRange(newLength, len - newLength);
  }

  String join([String separator]) => _filtered.join(separator);

  void add(Element value) {
    _childNodes.add(value);
  }

  void addAll(Iterable<Element> iterable) {
    for (Element element in iterable) {
      add(element);
    }
  }

  void addLast(Element value) {
    add(value);
  }

  bool contains(Element element) {
    return element is Element && _childNodes.contains(element);
  }

  void sort([int compare(Element a, Element b)]) {
    throw new UnsupportedError('TODO(jacobr): should we impl?');
  }

  void setRange(int start, int rangeLength, List from, [int startFrom = 0]) {
    throw new UnimplementedError();
  }

  void removeRange(int start, int rangeLength) {
    _filtered.getRange(start, rangeLength).forEach((el) => el.remove());
  }

  void insertRange(int start, int rangeLength, [initialValue = null]) {
    throw new UnimplementedError();
  }

  void clear() {
    // Currently, ElementList#clear clears even non-element nodes, so we follow
    // that behavior.
    _childNodes.clear();
  }

  Element removeLast() {
    final result = this.last;
    if (result != null) {
      result.remove();
    }
    return result;
  }

  Iterable mappedBy(f(Element element)) => _filtered.mappedBy(f);
  Iterable<Element> where(bool f(Element element)) => _filtered.where(f);

  Element removeAt(int index) {
    final result = this[index];
    result.remove();
    return result;
  }

  void remove(Object element) {
    if (element is! Element) return;
    for (int i = 0; i < length; i++) {
      Element indexElement = this[i];
      if (identical(indexElement, element)) {
        indexElement.remove();
        return;
      }
    }
  }

  // Operations defined in terms of [Collections]' [remove].

  void removeAll(Iterable elements) {
    // This should be optimized to not use [remove] directly.
    Collections.removeAll(this, elements);
  }

  void retainAll(Iterable elements) {
    Collections.retainAll(this, elements);
  }

  void removeMatching(bool test(Element element)) {
    Collections.removeMatching(this, test);
  }

  void retainMatching(bool test(Element element)) {
    Collections.retainMatching(this, test);
  }

  dynamic reduce(dynamic initialValue,
      dynamic combine(dynamic previousValue, Element element)) {
    return IterableMixinWorkaround.reduce(this, initialValue, combine);
  }
  bool every(bool f(Element element)) => _filtered.every(f);
  bool any(bool f(Element element)) => _filtered.any(f);
  List<Element> toList() => new List<Element>.from(this);
  Set<Element> toSet() => new Set<Element>.from(this);
  Element firstMatching(bool test(Element value), {Element orElse()}) {
    return _filtered.firstMatching(test, orElse: orElse);
  }

  Element lastMatching(bool test(Element value), {Element orElse()}) {
    return _filtered.lastMatching(test, orElse: orElse);
  }

  Element singleMatching(bool test(Element value)) {
    return _filtered.singleMatching(test);
  }

  Element elementAt(int index) {
    return this[index];
  }

  bool get isEmpty => _filtered.isEmpty;
  int get length => _filtered.length;
  Element operator [](int index) => _filtered[index];
  Iterator<Element> get iterator => _filtered.iterator;
  List<Element> getRange(int start, int rangeLength) =>
    _filtered.getRange(start, rangeLength);
  int indexOf(Element element, [int start = 0]) =>
    _filtered.indexOf(element, start);

  int lastIndexOf(Element element, [int start = null]) {
    if (start == null) start = length - 1;
    return _filtered.lastIndexOf(element, start);
  }

  Iterable<Element> take(int n) {
    return new TakeIterable<Element>(this, n);
  }

  Iterable<Element> takeWhile(bool test(Element value)) {
    return new TakeWhileIterable<Element>(this, test);
  }

  Iterable<Element> skip(int n) {
    return new SkipIterable<Element>(this, n);
  }

  Iterable<Element> skipWhile(bool test(Element value)) {
    return new SkipWhileIterable<Element>(this, test);
  }

  Element get first => _filtered.first;

  Element get last => _filtered.last;

  Element get single => _filtered.single;

  Element min([int compare(Element a, Element b)]) => _filtered.min(compare);

  Element max([int compare(Element a, Element b)]) => _filtered.max(compare);
}
