// 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.

/// Dart test verifying that the parser can handle type parameterization of
/// method declarations and method invocations. Slightly adjusted version of
/// code from DEP #22.

library generic_methods_test;

import "package:expect/expect.dart";

class BinaryTreeNode<K extends Comparable<K>, V> {
  final K _key;
  final V _value;
  final BinaryTreeNode<K, V>? _left;
  final BinaryTreeNode<K, V>? _right;

  BinaryTreeNode(this._key, this._value,
      {BinaryTreeNode<K, V>? left = null, BinaryTreeNode<K, V>? right = null})
      : _left = left,
        _right = right;

  // Use fresh type variables.
  static BinaryTreeNode<K2, V2> insertOpt<K2 extends Comparable<K2>, V2>(
      BinaryTreeNode<K2, V2>? t, K2 key, V2 value) {
    return (t == null) ? new BinaryTreeNode(key, value) : t.insert(key, value);
  }

  BinaryTreeNode<K, V> insert(K key, V value) {
    int c = key.compareTo(_key);
    if (c == 0) return this;
    var _insert = (BinaryTreeNode<K, V>? node, K key, V value) =>
        insertOpt<K, V>(node, key, value);
    BinaryTreeNode<K, V>? left = _left;
    BinaryTreeNode<K, V>? right = _right;
    if (c < 0) {
      left = _insert(_left, key, value);
    } else {
      right = _insert(_right, key, value);
    }
    return new BinaryTreeNode<K, V>(_key, _value, left: left, right: right);
  }

  // Reuse type variables [K], [V] to test shadowing.
  static BinaryTreeNode<K, U>? mapOpt<K extends Comparable<K>, V, U>(
      BinaryTreeNode<K, V>? t, U f(V x)) {
    return (t == null) ? null : t.map<U>(f);
  }

  BinaryTreeNode<K, U> map<U>(U f(V x)) {
    var _map = (BinaryTreeNode<K, V>? t, U f(V x)) => mapOpt<K, V, U>(t, f);
    return new BinaryTreeNode<K, U>(_key, f(_value),
        left: _map(_left, f), right: _map(_right, f));
  }

  // Use fresh [K2], shadowing [V].
  static S foldPreOpt<K2 extends Comparable<K2>, V, S>(
      BinaryTreeNode<K2, V>? t, S init, S f(V t, S s)) {
    return (t == null) ? init : t.foldPre<S>(init, f);
  }

  S foldPre<S>(S init, S f(V t, S s)) {
    var _fold = (BinaryTreeNode<K, V>? t, S s, S f(V t, S s)) =>
        foldPreOpt<K, V, S>(t, s, f);
    S s = init;
    s = f(_value, s);
    s = _fold(_left, s, f);
    s = _fold(_right, s, f);
    return s;
  }
}

class BinaryTree<K extends Comparable<K>, V> {
  final BinaryTreeNode<K, V>? _root;

  BinaryTree._internal(this._root);
  BinaryTree.empty() : this._internal(null);

  BinaryTree<K, V> insert(K key, V value) {
    BinaryTreeNode<K, V> root =
        BinaryTreeNode.insertOpt<K, V>(_root, key, value);
    return new BinaryTree<K, V>._internal(root);
  }

  BinaryTree<K, U> map<U>(U f(V x)) {
    BinaryTreeNode<K, U>? root = BinaryTreeNode.mapOpt<K, V, U>(_root, f);
    return new BinaryTree<K, U>._internal(root);
  }

  S foldPre<S>(S init, S f(V t, S s)) {
    return BinaryTreeNode.foldPreOpt<K, V, S>(_root, init, f);
  }
}

main() {
  BinaryTree<num, String> sT = new BinaryTree<num, String>.empty();

  sT = sT.insert(0, "");
  sT = sT.insert(1, " ");
  sT = sT.insert(2, "  ");
  sT = sT.insert(3, "   ");

  BinaryTree<num, num> iT = sT.map<num>((String s) => s.length);

  Expect.equals(iT.foldPre<num>(0, (num i, num s) => i + s), 6);
}
