package jetbrains.mps.closures.test;

/*Generated by MPS */

import org.junit.jupiter.api.Test;
import org.junit.Assert;
import jetbrains.mps.internal.collections.runtime.ISelector;
import jetbrains.mps.baseLanguage.closures.runtime._FunctionTypes;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import java.util.stream.Stream;
import jetbrains.mps.internal.collections.runtime.Sequence;

public class InferredParameter_Test {
  @Test
  public void test_returnContext() throws Exception {
    Assert.assertEquals(returnContext().invoke(3), "3");

    SelectorProvider provider = () -> {
      return new ISelector<Integer, String>() {
        public String select(Integer obj) {
          return String.valueOf(obj);
        }
      };
    };
    Assert.assertEquals(provider.get().invoke(4), "4");

    // The following case would not be generated correctly because the current preparation scripts cannot do magic for now
  }
  @Test
  public void test_functionType() throws Exception {
    _FunctionTypes._void_P4_E0<? super Integer, ? super Double, ? super String, ? super ArrayList<Integer>> method = (intVar, doubleVar, strVar, list) -> {
      Integer.bitCount(intVar);
      Double.isFinite(doubleVar);
      strVar.substring(intVar);
      list.clear();
    };

    Assert.assertNotNull(method);
  }
  @Test
  public void test_genericType() throws Exception {
    IGeneric<Integer> method = (val, count, computer) -> {
      ArrayList<Integer> list = new ArrayList<Integer>();
      for (int i = 0; i < count; i++) {
        list.add(i);
      }
      return computer.convert(val, list);
    };

    AbstractGeneric<IGeneric<Double>> nested = new AbstractGeneric<IGeneric<Double>>() {
      public IGeneric<Double> convert(IGeneric<Double> item, List<IGeneric<Double>> list) {
        list.forEach((it) -> {
          it.resultOf(3.0, 2, new AbstractGeneric<Double>() {
            public Double convert(Double doublValue, List<Double> nestedList) {
              return doublValue + nestedList.size();
            }
          });
        });
        return item;
      }
    };

    Assert.assertNotNull(method);
    Assert.assertNotNull(nested);
  }
  @Test
  public void test_castContext() throws Exception {
    double perform = ((ISimple) (input) -> input * 2.0).perform(3);

    Assert.assertNotNull(perform);
  }
  @Test
  public void test_callContext() throws Exception {
    ArrayList<Integer> integers = new ArrayList();
    integers.forEach((input) -> input.bitCount(2));
  }
  @Test
  public void test_assignContext() throws Exception {
    ISimple value = (input) -> 3 * input;
    value.perform(5);

    value = (input2) -> input2 + 3;
    value.perform(3);

    AbstractGeneric<String> generic;
    generic = new AbstractGeneric<String>() {
      public String convert(String input, List<String> list) {
        input.charAt(3);
        return "";
      }
    };
    Assert.assertNotNull(generic);
  }
  @Test
  public void test_varAssignment() throws Exception {
    ISimple value = (ISimple) (input) -> 1;

    Assert.assertNotNull(value);
  }
  @Test
  public void test_methodParamInferrence() throws Exception {
    String[] content = new String[]{"A", "D", "C", "B"};
    Arrays.sort(content, (_this_0, str) -> _this_0.compareToIgnoreCase(str));
    Assert.assertEquals(content[1], "B");
  }
  @Test
  public void test_testChainedCallsJavaType() throws Exception {
    List<StringBuilder> builders = ListSequence.fromListAndArray(new ArrayList<StringBuilder>(), new StringBuilder("Hello"), new StringBuilder("World"));

    // Chained calls with inferred type from "builders", using stream API
    Stream<String> map = builders.stream().map((content) -> ItemContainer.init(content)).map((_this_0) -> _this_0.get()).map((_this_0) -> _this_0.toString());
    Assert.assertEquals(map.findFirst().get(), "Hello");
  }
  @Test
  public void test_testChainedCallsJavaFunctionType() throws Exception {
    List<StringBuilder> builders = ListSequence.fromListAndArray(new ArrayList<StringBuilder>(), new StringBuilder("Hello"), new StringBuilder("World"));

    // Chained calls with inferred type from "builders", using java implementation of sequences
    Iterable<String> strings = ListSequence.fromList(builders).select((content) -> ItemContainer.init(content)).select((_this_0) -> _this_0.get()).select((_this_0) -> _this_0.toString());
    Assert.assertEquals(Sequence.fromIterable(strings).first(), "Hello");
  }
  @Test
  public void test_testChainedCallsFunctionType() throws Exception {
    Iterable<StringBuilder> builders = ListSequence.fromListAndArray(new ArrayList<StringBuilder>(), new StringBuilder("Hello"), new StringBuilder("World"));

    // Chained calls with inferred type from "builders", using sequences
    Iterable<String> strings = Sequence.fromIterable(builders).select((content) -> ItemContainer.init(content)).select((_this_0) -> _this_0.get()).select((_this_0) -> _this_0.toString());
    Assert.assertEquals(Sequence.fromIterable(strings).first(), "Hello");
  }
  public interface IGeneric<K> {
    int resultOf(K value, int count, InferredParameter_Test.AbstractGeneric<K> computator);
  }

  public abstract class AbstractGeneric<T> {
    public abstract T convert(T input, List<T> parentList);
  }

  public interface IEmpty {
  }
  public interface ISimple extends IEmpty {
    double perform(int occurences);
  }
  /*package*/ static class ItemContainer<E> {
    private E item;
    /*package*/ ItemContainer(E item) {
      this.item = item;
    }
    /*package*/ static <W> ItemContainer<W> init(W content) {
      return new ItemContainer(content);
    }
    /*package*/ E get() {
      return item;
    }
  }
  /*package*/ ISelector<Integer, String> returnContext() {
    return new ISelector<Integer, String>() {
      public String select(Integer obj) {
        return String.valueOf(obj);
      }
    };
  }
  /*package*/ interface SelectorProvider {
    ISelector<Integer, String> get();
  }


}
