/*
 * Copyright 2013 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.dev.jjs.test;

import com.google.gwt.dev.jjs.test.overrides.package1.Caller;
import com.google.gwt.dev.jjs.test.overrides.package1.ClassExposingM;
import com.google.gwt.dev.jjs.test.overrides.package1.SomeParent;
import com.google.gwt.dev.jjs.test.overrides.package1.SomeParentParent;
import com.google.gwt.dev.jjs.test.overrides.package1.SomeParentParentParent;
import com.google.gwt.dev.jjs.test.overrides.package1.SubClassExposingM;
import com.google.gwt.dev.jjs.test.overrides.package2.SomeSubClassInAnotherPackage;
import com.google.gwt.dev.jjs.test.overrides.package2.SomeSubSubClassInAnotherPackage;
import com.google.gwt.dev.jjs.test.overrides.package3.SomeInterface;
import com.google.gwt.dev.jjs.test.overrides.package3.SomePackageConfusedParent;
import com.google.gwt.junit.DoNotRunWith;
import com.google.gwt.junit.Platform;
import com.google.gwt.junit.client.GWTTestCase;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javaemul.internal.annotations.DoNotInline;
import jsinterop.annotations.JsMethod;
import jsinterop.annotations.JsOverlay;
import jsinterop.annotations.JsPackage;
import jsinterop.annotations.JsProperty;
import jsinterop.annotations.JsType;

/**
 * Tests Miscelaneous fixes.
 */
public class CompilerMiscRegressionTest extends GWTTestCase {

  @Override
  public String getModuleName() {
    return "com.google.gwt.dev.jjs.CompilerSuite";
  }

  native double toNumber(String value) /*-{
    return +value;
  }-*/;

  native double addAndConvert(double v1, String v2) /*-{
    return v1 + +v2;
  }-*/;

  native double minusAndDecrement(double val) /*-{
    var lhs = val;
    return - --lhs;
  }-*/;

  /**
   * The array {@code map.get("one")[0]} gets normalized (by {@link ImplementCastsAndTypeChecks}) to
   * {@code Cast.dynamicCast(map.get("one"), ...)[0]}. The expression resulting from dynamiCast
   * would have type Object and that would not be a valid type for an array access operation.
   */
  public void testOverridingReturnType() {
    Map<String, String[]> map = new HashMap();
    map.put("one", new String[10]);

    map.get("one")[0] = "one";
    assertEquals("one", map.get("one")[0]);
  }

  /**
   * Test for issues 6373 and 3942.
   */
  public void testUnaryPlus() {
    // With the unary + operator stripped the first assertion only fails in
    // dev mode, in web mode the  comparison made by assertEquals masks
    // the error; whereas the second fails in both dev and web modes.
    assertEquals(11.0, toNumber("11"));
    assertEquals(12.0, toNumber("10") + toNumber("2"));
    assertEquals(12.0, addAndConvert(10, "2"));
    assertEquals(-10.0, minusAndDecrement(11));
  }
  private static float[] copy(float[] src, float[] dest) {
    System.arraycopy(src, 0, dest, 0, Math.min(src.length, dest.length));
    return dest;
  }

  private void throwE(String message) {
    throw new RuntimeException(message);
  }

  /**
   * Test for issue 8243.
   */
  public void testAddAllLargeNumberOfElements() {

    int dstLength = 10;
    // Some browser have a limit on the number of parameters a function can have and 130000 barely
    // exceeds Chrome limit (as of V34).
    // This limit also applies when functions are called through apply().
    int srcLength =  130000;
    List<String> original = new ArrayList<String>();
    for (int i = 0; i < dstLength; i++) {
      original.add("foo");
    }
    List<String> src = new ArrayList<String>();
    for (int i = 0; i < srcLength; i++) {
      src.add("bar");
    }

    original.addAll(src);
    final int totalLength = srcLength + dstLength;
    assertEquals(totalLength, original.size());

    // Check the result sampling as iterating through large arrays seems costly in IE.
    for (int i = 0; i < totalLength; i += 1000) {
      if (i < dstLength) {
        assertEquals("foo", original.get(i));
      } else {
        assertEquals("bar", original.get(i));
      }
    }
  }

  /**
   * Test for issue 7253.
   */
  public void testNestedTryFollowedByTry() {
    try {
      throwE("1");
      fail("Should have thrown RuntimeException");
    } catch (RuntimeException e) {
      assertEquals("1", e.getMessage());
      try {
        throwE("2");
        fail("Should have thrown RuntimeException");
      } catch (RuntimeException e2) {
        assertEquals("2", e2.getMessage());
      }
    }
    try {
      throwE("3");
      fail("Should have thrown RuntimeException");
    } catch (RuntimeException e) {
      assertEquals("3", e.getMessage());
    }
  }

  /**
   * Test for issue 6638.
   */
  public void testNewArrayInlining() {
    float[] src = new float[]{1,1,1};
    float[] dest = copy(src, new float[3]);

    assertEqualContents(src, dest);
  }

  /**
   * Tests complex overriding patterns involving package private methods.
   * <p>
   * Test for issue 8654.
   */
  public void testOverride() {
    Caller aCaller = new Caller();
    assertEquals("SomeParentParent", aCaller.callPackagePrivatem(new SomeParentParent()));
    assertEquals("SomeParent", aCaller.callPackagePrivatem(new SomeParent()));
    assertEquals("SomeParent", aCaller.callPackagePrivatem(
        new SomeSubClassInAnotherPackage()));

    assertEquals("SomeSubClassInAnotherPackage",
        SomeSubClassInAnotherPackage.pleaseCallm(new SomeSubClassInAnotherPackage()));
    assertEquals("SomeSubSubClassInAnotherPackage",
        SomeSubClassInAnotherPackage.pleaseCallm(new SomeSubSubClassInAnotherPackage()));

    assertEquals("ClassExposingM",
        aCaller.callPackagePrivatem(new ClassExposingM()));

    SomeInterface i = new ClassExposingM();
    assertEquals("ClassExposingM", i.m());
    assertEquals("live at ClassExposingM", new ClassExposingM().f());

    // Confirm that both calling m through SomeInterface and through SomeParentParentParent
    // dispatch to the right implementation.
    SomeInterface i1 = new SubClassExposingM();
    assertEquals("SubClassExposingM", i1.m());

    assertEquals("SubClassExposingM",
        SomeParentParentParent.callSomeParentParentParentM(new SubClassExposingM()));

    assertEquals("SomeParentParentParent",
        SomeParentParentParent.callSomeParentParentParentM(new SomeParentParentParent()));
    assertEquals("SomeParentParentParent",
        SomeParentParentParent.callSomeParentParentParentM(new SomePackageConfusedParent()));
    assertEquals("SomeParentParent",
        SomeParentParentParent.callSomeParentParentParentM(new SomeParentParent()));
    assertEquals("SomeParent",
        SomeParentParentParent.callSomeParentParentParentM(new SomeParent()));
    assertEquals("SomeParent",
        SomeParentParentParent.callSomeParentParentParentM(new SomeSubClassInAnotherPackage()));
    assertEquals("SomeParent",
        SomeParentParentParent.callSomeParentParentParentM(new SomeSubSubClassInAnotherPackage()));
  }

  enum MyEnum {
    A,
    B,
    C;

    public final static MyEnum[] VALUES = values();

    public int getPriority() {
      return VALUES.length - ordinal();
    }
  }

  /**
   * Tests that enum ordinalizer does not incorrectly optimize {@code MyEnum}.
   * <p>
   * Test for issue 8846.
   */
  public void testMyEnum() {
    assertEquals(2, MyEnum.B.getPriority());
  }

  enum OrderingProblem {
    A,
    B;

    public static OrderingProblem getPriority1() {
      if (new Integer(1).toString().isEmpty()) {
        return B;
      }
      return A;
    }
  }

  /**
   * Test for regression introduced in patch https://gwt-review.googlesource.com/#/c/9083; where
   * depending on the order in which references to the enum class were encountered, some instances
   * were not correctly replaced .
   */
  public void testOrderingProblem() {
    assertEquals(OrderingProblem.A.ordinal(), OrderingProblem.getPriority1().ordinal());
  }

  /**
   * Tests that regexes are not incorrectly internalized.
   *
   * Test for issue 8865.
   */
  public native void testJavaScriptRegExps() /*-{
    // Make regexes large enough so that the will be interned (if regex interning was enabled).
    var regExp1 = /this is a string where the search/g;
    var regExp2 = /this is a string where the search/g;
    var str = "this is a string where the search occurs";
    @junit.framework.Assert::assertEquals(ZZ)(
       regExp1.test(str), regExp2.test(str));
  }-*/;

  private static final double MINUTES_IN_DAY = 24 * 60;

  @DoNotInline
  public void assertStaticEvaluationRegression(int hour, int minute) {
    // Do not inline this method so that the problematic expression reaches JsStaticEval.
    double expected = hour * 60 + minute;
    expected /= MINUTES_IN_DAY;
    expected *= 100;
    assertEquals(expected , (hour * 60 + minute) / MINUTES_IN_DAY * 100);
  }

  /**
   * Test for issue 8934.
   */
  public void testStaticEvaluationRegression() {
    // Perform two calls with different constant values to make sure the assertStaticEvaluation does
    // not get the constant parameters propagated and statically evaluated in the Java AST.
    assertStaticEvaluationRegression(10, 20);
    assertStaticEvaluationRegression(20, 10);
  }

  /**
   * Test for issue 8909.
   * <p>
   * DevMode does not conform to JS arithmetic semantics and this method tests exactly that.
   */
  @DoNotRunWith(Platform.Devel)
  public void testStaticEvaluationSematics() {
    float num = getRoundedValue(1.005f);
    assertEquals(1.00, num, 0.001);
  }

  private float getRoundedValue(float parameter) {
    float local = parameter;
    local = local * 100f;
    return Math.round(local) / 100f;
  }

  /**
   * Test for issue 9043.
   */
  public native void testMultipleClassLiteralReferences() /*-{
    var a = @com.google.gwt.dev.jjs.test.CompilerMiscRegressionTest::class;
    var b = @com.google.gwt.dev.jjs.test.CompilerMiscRegressionTest::class;
  }-*/;

  /**
   * Test for issue 9153.
   * <p>
   * Typetightener used to incorrectly tighten method calls marked with STATIC_DISPATCH_ONLY.
   */

  public void testIncorrectDispatch() {
    state = new int[1];
    new B().m();
    assertEquals(1, state[0]);
  }

  static int[] state;
  @JsType
  abstract static class A {
    public void m() {
      state[0] = 1;
    }
  }

  @JsType
  static class B extends A {
    public void m() {
      super.m();
    }
  }

  private static void assertEqualContents(float[] expected, float[] actual) {

    assertEquals("Array length mismatch", expected.length, actual.length);
    for (int i = 0; i < expected.length; i++) {
      assertEquals("Array mismatch at element " + i , expected[i], actual[i]);
    }
  }

  @JsType(isNative = true)
  interface SomeNativeInterface {
    @JsProperty
    String getTextContent();
  }

  @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
  static abstract class AbstractNativeType implements SomeNativeInterface {
  }

  private static native AbstractNativeType createAbstractNativeType(String value) /*-{
    return {textContent : value};
  }-*/;

  // Tests that methods that override native JsMethods are generated properly w.r.t
  // JsMethod/JsProperty annotations even if the overridden method is not live.
  // See bug #9358
  //
  // Make sure this method is part of a suite that is run with -nogenerateJsInteropExports.
  public void testNativeJsMethodDispatch_unreferencedSupertypeMethod() {
    final AbstractNativeType o = createAbstractNativeType("Hello");
    assertEquals("Hello", o.getTextContent());
  }

  @JsMethod
  private static List<String> singletonFrom(int i, String... arguments) {
    // Make the second parameter varargs and pass it as a whole to trigger the arguments copying
    // preamble.
    return Arrays.asList(arguments).subList(i,i + 1);
  }

  @JsMethod
  private static List<String> argumentsParameterClasher(int arguments, String... others) {
    // Make the second parameter varargs and pass it as a whole to trigger the arguments copying
    // preamble.
    return Arrays.asList(others).subList(0, arguments);
  }

  @JsMethod
  private static List<String> argumentsVariableClasher(int i, String... others) {
    // Make the second parameter varargs and pass it as a whole to trigger the arguments copying
    // preamble.
    {
      int arguments = 3;
    }
    return Arrays.asList(others).subList(0, i);
  }

 public void testVarargsNamedArguments() {
    assertEquals("GoodBye", singletonFrom(1, "Hello", "GoodBye").get(0));
    assertEquals("Hello", argumentsParameterClasher(1, "Hello", "GoodBye").get(0));
    assertEquals("Hello", argumentsVariableClasher(1, "Hello", "GoodBye").get(0));
  }

  @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Array")
  private static class NativeArray {
    @JsProperty(name = "length")
    public int len;
    @JsMethod(name = "push")
    public native void add(double element);
  }

  private static native Object newArray() /*-{
    return @NativeArray::new()();
  }-*/;

  private static native int arrayLength(Object array) /*-{
    return array.@NativeArray::len;
  }-*/;

  private static native void arrayAdd(Object array, double d) /*-{
    array.@NativeArray::add(D)(d);
    return array;
  }-*/;

  private static native Object newArrayThroughCtorReference() /*-{
    var ctor =  @NativeArray::new();
    return ctor();
  }-*/;

  private static native boolean isNan(double number) /*-{
    return @Global::isNan(D)(number);
  }-*/;

  private static native double getNan() /*-{
    return @Global::Nan;
  }-*/;

  @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
  private static class Global {
    @JsProperty(namespace = JsPackage.GLOBAL, name = "NaN")
    public static double Nan;
    @JsMethod(namespace = JsPackage.GLOBAL, name = "isNaN")
    public static native boolean isNan(double number);
  }

  // Regression tests for issue #9520.
  public void testNativeConstructorJSNI() {
    Object nativeArray = newArray();
    arrayAdd(nativeArray, 0);
    arrayAdd(nativeArray, 1);
    assertTrue(nativeArray instanceof NativeArray);
    assertEquals(2, arrayLength(nativeArray));
    assertTrue(newArrayThroughCtorReference() instanceof NativeArray);
    assertTrue(Double.isNaN(getNan()));
    assertTrue(isNan(Double.NaN));
  }

  @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
  private static class NativeObjectWithOverlay {
    public NativeObjectWithOverlay() { }
    @JsOverlay
    final NativeObjectWithOverlay getThis() {
      return this;
    }
  }

  public void testOveralyDispatchOnNull() {
    // Define a variable where the compiler can not statically determine that it is actually null.
    NativeObjectWithOverlay objectWithOverlay =
        Math.random() > 1000 ? new NativeObjectWithOverlay() : null;

    assertTrue(objectWithOverlay.getThis() == null);
  }
}
