// 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));

  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));

  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;

  E get single => _base.single as E;

  E singleWhere(bool test(E element)) =>
    _base.singleWhere(_validate(test)) 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)));

  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;
  }

  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());

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

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

  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);

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

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

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

  void 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));
  }

  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);
  }

  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<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);
  }

  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));
  }

  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 clear() {
    _base.clear();
  }

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

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

  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;

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

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

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

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