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

import "dart:collection";
import "dart:math" as math;

import "wrappers.dart";

typedef F _UnaryFunction<E, F>(E argument);

/// The base class for delegating, type-asserting iterables.
///
/// Subclasses can provide a [_base] that should be delegated to. Unlike
/// [TypeSafeIterable], this allows the base to be created on demand.
abstract class _TypeSafeIterableBase<E> implements Iterable<E> {
  /// The base iterable to which operations are delegated.
  Iterable get _base;

  _TypeSafeIterableBase();

  bool any(bool test(E element)) => _base.any(_validate(test));

  Iterable<T> cast<T>() => new TypeSafeIterable<T>(_base.cast<T>());

  bool contains(Object element) => _base.contains(element);

  E elementAt(int index) => _base.elementAt(index) as E;

  bool every(bool test(E element)) => _base.every(_validate(test));

  Iterable<T> expand<T>(Iterable<T> f(E element)) => _base.expand(_validate(f));

  E get first => _base.first as E;

  E firstWhere(bool test(E element), {E orElse()}) =>
      _base.firstWhere(_validate(test), orElse: orElse) as E;

  T fold<T>(T initialValue, T combine(T previousValue, E element)) =>
      _base.fold(initialValue,
          (previousValue, element) => combine(previousValue, element as E));

  Iterable<E> followedBy(Iterable<E> other) =>
      new TypeSafeIterable<E>(_base.followedBy(other));

  void forEach(void f(E element)) => _base.forEach(_validate(f));

  bool get isEmpty => _base.isEmpty;

  bool get isNotEmpty => _base.isNotEmpty;

  Iterator<E> get iterator => _base.map((element) => element as E).iterator;

  String join([String separator = ""]) => _base.join(separator);

  E get last => _base.last as E;

  E lastWhere(bool test(E element), {E orElse()}) =>
      _base.lastWhere(_validate(test), orElse: orElse) as E;

  int get length => _base.length;

  Iterable<T> map<T>(T f(E element)) => _base.map(_validate(f));

  E reduce(E combine(E value, E element)) =>
      _base.reduce((value, element) => combine(value as E, element as E)) as E;

  Iterable<T> retype<T>() => new TypeSafeIterable<T>(_base.retype<T>());

  E get single => _base.single as E;

  E singleWhere(bool test(E element), {E orElse()}) {
    return _base.singleWhere(_validate(test), orElse: orElse) as E;
  }

  Iterable<E> skip(int n) => new TypeSafeIterable<E>(_base.skip(n));

  Iterable<E> skipWhile(bool test(E value)) =>
      new TypeSafeIterable<E>(_base.skipWhile(_validate(test)));

  Iterable<E> take(int n) => new TypeSafeIterable<E>(_base.take(n));

  Iterable<E> takeWhile(bool test(E value)) =>
      new TypeSafeIterable<E>(_base.takeWhile(_validate(test)));

  List<E> toList({bool growable: true}) =>
      new TypeSafeList<E>(_base.toList(growable: growable));

  Set<E> toSet() => new TypeSafeSet<E>(_base.toSet());

  Iterable<E> where(bool test(E element)) =>
      new TypeSafeIterable<E>(_base.where(_validate(test)));

  Iterable<T> whereType<T>() => _base.whereType<T>();

  String toString() => _base.toString();

  /// Returns a version of [function] that asserts that its argument is an
  /// instance of `E`.
  _UnaryFunction<dynamic, F> _validate<F>(F function(E value)) =>
      (value) => function(value as E);
}

/// An [Iterable] that asserts the types of values in a base iterable.
///
/// This is instantiated using [DelegatingIterable.typed].
class TypeSafeIterable<E> extends _TypeSafeIterableBase<E>
    implements DelegatingIterable<E> {
  final Iterable _base;

  TypeSafeIterable(Iterable base) : _base = base;
}

/// A [List] that asserts the types of values in a base list.
///
/// This is instantiated using [DelegatingList.typed].
class TypeSafeList<E> extends TypeSafeIterable<E> implements DelegatingList<E> {
  TypeSafeList(List base) : super(base);

  /// A [List]-typed getter for [_base].
  List get _listBase => _base;

  E operator [](int index) => _listBase[index] as E;

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

  List<E> operator +(List<E> other) => new TypeSafeList<E>(_listBase + other);

  void add(E value) {
    _listBase.add(value);
  }

  void addAll(Iterable<E> iterable) {
    _listBase.addAll(iterable);
  }

  Map<int, E> asMap() => new TypeSafeMap<int, E>(_listBase.asMap());

  List<T> cast<T>() => new TypeSafeList<T>(_listBase.cast<T>());

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

  void fillRange(int start, int end, [E fillValue]) {
    _listBase.fillRange(start, end, fillValue);
  }

  set first(E value) {
    if (this.isEmpty) throw new RangeError.index(0, this);
    this[0] = value;
  }

  Iterable<E> getRange(int start, int end) =>
      new TypeSafeIterable<E>(_listBase.getRange(start, end));

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

  int indexWhere(bool test(E element), [int start = 0]) =>
      _listBase.indexWhere((e) => test(e as E), start);

  void insert(int index, E element) {
    _listBase.insert(index, element);
  }

  void insertAll(int index, Iterable<E> iterable) {
    _listBase.insertAll(index, iterable);
  }

  set last(E value) {
    if (this.isEmpty) throw new RangeError.index(0, this);
    this[this.length - 1] = value;
  }

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

  int lastIndexWhere(bool test(E element), [int start]) =>
      _listBase.lastIndexWhere((e) => test(e as E), start);

  set length(int newLength) {
    _listBase.length = newLength;
  }

  bool remove(Object value) => _listBase.remove(value);

  E removeAt(int index) => _listBase.removeAt(index) as E;

  E removeLast() => _listBase.removeLast() as E;

  void removeRange(int start, int end) {
    _listBase.removeRange(start, end);
  }

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

  void replaceRange(int start, int end, Iterable<E> iterable) {
    _listBase.replaceRange(start, end, iterable);
  }

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

  List<T> retype<T>() => new TypeSafeList<T>(_listBase.retype<T>());

  Iterable<E> get reversed => new TypeSafeIterable<E>(_listBase.reversed);

  void setAll(int index, Iterable<E> iterable) {
    _listBase.setAll(index, iterable);
  }

  void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
    _listBase.setRange(start, end, iterable, skipCount);
  }

  void shuffle([math.Random random]) {
    _listBase.shuffle(random);
  }

  void sort([int compare(E a, E b)]) {
    if (compare == null) {
      _listBase.sort();
    } else {
      _listBase.sort((a, b) => compare(a as E, b as E));
    }
  }

  List<E> sublist(int start, [int end]) =>
      new TypeSafeList<E>(_listBase.sublist(start, end));
}

/// A [Set] that asserts the types of values in a base set.
///
/// This is instantiated using [DelegatingSet.typed].
class TypeSafeSet<E> extends TypeSafeIterable<E> implements DelegatingSet<E> {
  TypeSafeSet(Set base) : super(base);

  /// A [Set]-typed getter for [_base].
  Set get _setBase => _base;

  bool add(E value) => _setBase.add(value);

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

  Set<T> cast<T>() => new TypeSafeSet<T>(_setBase.cast<T>());

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

  bool containsAll(Iterable<Object> other) => _setBase.containsAll(other);

  Set<E> difference(Set<Object> other) =>
      new TypeSafeSet<E>(_setBase.difference(other));

  Set<E> intersection(Set<Object> other) =>
      new TypeSafeSet<E>(_setBase.intersection(other));

  E lookup(Object element) => _setBase.lookup(element) as E;

  bool remove(Object value) => _setBase.remove(value);

  void removeAll(Iterable<Object> elements) {
    _setBase.removeAll(elements);
  }

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

  void retainAll(Iterable<Object> elements) {
    _setBase.retainAll(elements);
  }

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

  Set<T> retype<T>() => new TypeSafeSet<T>(_setBase.retype<T>());

  Set<E> union(Set<E> other) => new TypeSafeSet<E>(_setBase.union(other));
}

/// A [Queue] that asserts the types of values in a base queue.
///
/// This is instantiated using [DelegatingQueue.typed].
class TypeSafeQueue<E> extends TypeSafeIterable<E>
    implements DelegatingQueue<E> {
  TypeSafeQueue(Queue queue) : super(queue);

  /// A [Queue]-typed getter for [_base].
  Queue get _baseQueue => _base;

  void add(E value) {
    _baseQueue.add(value);
  }

  void addAll(Iterable<E> iterable) {
    _baseQueue.addAll(iterable);
  }

  void addFirst(E value) {
    _baseQueue.addFirst(value);
  }

  void addLast(E value) {
    _baseQueue.addLast(value);
  }

  Queue<T> cast<T>() => new TypeSafeQueue<T>(_baseQueue.cast<T>());

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

  bool remove(Object object) => _baseQueue.remove(object);

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

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

  Queue<T> retype<T>() => new TypeSafeQueue<T>(_baseQueue.retype<T>());

  E removeFirst() => _baseQueue.removeFirst() as E;

  E removeLast() => _baseQueue.removeLast() as E;
}

/// A [Map] that asserts the types of keys and values in a base map.
///
/// This is instantiated using [DelegatingMap.typed].
class TypeSafeMap<K, V> implements DelegatingMap<K, V> {
  /// The base map to which operations are delegated.
  final Map _base;

  TypeSafeMap(Map base) : _base = base;

  V operator [](Object key) => _base[key] as V;

  void operator []=(K key, V value) {
    _base[key] = value;
  }

  void addAll(Map<K, V> other) {
    _base.addAll(other);
  }

  void addEntries(Iterable<MapEntry<K, V>> entries) {
    _base.addEntries(entries);
  }

  Map<K2, V2> cast<K2, V2>() => new TypeSafeMap<K2, V2>(_base.cast<K2, V2>());

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

  bool containsKey(Object key) => _base.containsKey(key);

  bool containsValue(Object value) => _base.containsValue(value);

  Iterable<MapEntry<K, V>> get entries => _base.entries;

  void forEach(void f(K key, V value)) {
    _base.forEach((key, value) => f(key as K, value as V));
  }

  bool get isEmpty => _base.isEmpty;

  bool get isNotEmpty => _base.isNotEmpty;

  Iterable<K> get keys => new TypeSafeIterable<K>(_base.keys);

  int get length => _base.length;

  Map<K2, V2> map<K2, V2>(dynamic transform(K key, V value)) {
    return _base as dynamic;
  }

  V putIfAbsent(K key, V ifAbsent()) => _base.putIfAbsent(key, ifAbsent) as V;

  V remove(Object key) => _base.remove(key) as V;

  void removeWhere(bool test(K key, V value)) =>
      _base.removeWhere((k, v) => test(k as K, v as V));

  Map<K2, V2> retype<K2, V2>() =>
      new TypeSafeMap<K2, V2>(_base.retype<K2, V2>());

  Iterable<V> get values => new TypeSafeIterable<V>(_base.values);

  String toString() => _base.toString();

  V update(K key, V update(V value), {V ifAbsent()}) =>
      _base.update(key, (v) => update(v as V), ifAbsent: ifAbsent);

  void updateAll(V update(K key, V value)) =>
      _base.updateAll((k, v) => update(k, v));
}
