// Copyright (c) 2013, 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 dart.dom.html;

/**
 * A list which just wraps another list, for either intercepting list calls or
 * retyping the list (for example, from List<A> to List<B> where B extends A).
 */
class _WrappedList<E> implements List<E> {
  final List _list;

  _WrappedList(this._list);

  // Iterable APIs

  Iterator<E> get iterator => new _WrappedIterator(_list.iterator);

  Iterable map(f(E element)) => _list.map(f);

  Iterable<E> where(bool f(E element)) => _list.where(f);

  Iterable expand(Iterable f(E element)) => _list.expand(f);

  bool contains(E element) => _list.contains(element);

  void forEach(void f(E element)) { _list.forEach(f); }

  dynamic reduce(initialValue, combine(previousValue, E element)) =>
      _list.reduce(initialValue, combine);

  bool every(bool f(E element)) => _list.every(f);

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

  bool any(bool f(E element)) => _list.any(f);

  List<E> toList({ bool growable: true }) =>
      new List.from(_list, growable: growable);

  Set<E> toSet() => _list.toSet();

  int get length => _list.length;

  E min([int compare(E a, E b)]) => _list.min(compare);

  E max([int compare(E a, E b)]) => _list.max(compare);

  bool get isEmpty => _list.isEmpty;

  Iterable<E> take(int n) => _list.take(n);

  Iterable<E> takeWhile(bool test(E value)) => _list.takeWhile(test);

  Iterable<E> skip(int n) => _list.skip(n);

  Iterable<E> skipWhile(bool test(E value)) => _list.skipWhile(test);

  E get first => _list.first;

  E get last => _list.last;

  E get single => _list.single;

  E firstWhere(bool test(E value), { E orElse() }) =>
      _list.firstWhere(test, orElse: orElse);

  E lastWhere(bool test(E value), {E orElse()}) =>
      _list.lastWhere(test, orElse: orElse);

  E singleWhere(bool test(E value)) => _list.singleWhere(test);

  E elementAt(int index) => _list.elementAt(index);

  // Collection APIs

  void add(E element) { _list.add(element); }

  void addAll(Iterable<E> elements) { _list.addAll(elements); }

  void remove(Object element) { _list.remove(element); }

  void removeAll(Iterable elements) { _list.removeAll(elements); }

  void retainAll(Iterable elements) { _list.retainAll(elements); }

  void removeWhere(bool test(E element)) { _list.removeWhere(test); }

  void retainWhere(bool test(E element)) { _list.retainWhere(test); }

  void clear() { _list.clear(); }

  // List APIs

  E operator [](int index) => _list[index];

  void operator []=(int index, E value) { _list[index] = value; }

  void set length(int newLength) { _list.length = newLength; }

  void addLast(E value) { _list.add(value); }

  Iterable<E> get reversed => _list.reversed;

  void sort([int compare(E a, E b)]) { _list.sort(compare); }

  int indexOf(E element, [int start = 0]) => _list.indexOf(element, start);

  int lastIndexOf(E element, [int start]) => _list.lastIndexOf(element, start);

  void insert(int index, E element) => _list.insert(index, element);

  E removeAt(int index) => _list.removeAt(index);

  E removeLast() => _list.removeLast();

  List<E> sublist(int start, [int end]) => _list.sublist(start, end);

  List<E> getRange(int start, int length) => sublist(start, start + length);

  void setRange(int start, int length, List<E> from, [int startFrom]) {
    _list.setRange(start, length, from, startFrom);
  }

  void removeRange(int start, int length) { _list.removeRange(start, length); }

  void insertRange(int start, int length, [E fill]) {
    _list.insertRange(start, length, fill);
  }

  Map<int, E> asMap() => IterableMixinWorkaround.asMapList(_list);
}

/**
 * Iterator wrapper for _WrappedList.
 */
class _WrappedIterator<E> implements Iterator<E> {
  Iterator _iterator;

  _WrappedIterator(this._iterator);

  bool moveNext() {
    return _iterator.moveNext();
  }

  E get current => _iterator.current;
}
