/*
 * Copyright 2015 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.core.interop;

import com.google.gwt.core.client.ScriptInjector;
import com.google.gwt.junit.client.GWTTestCase;

import jsinterop.annotations.JsFunction;
import jsinterop.annotations.JsPackage;
import jsinterop.annotations.JsProperty;
import jsinterop.annotations.JsType;

/**
 * Tests JsType with array functionality.
 */
public class JsTypeArrayTest extends GWTTestCase {
  @Override
  protected void gwtSetUp() throws Exception {
    ScriptInjector.fromString("function JsTypeArrayTest_SimpleJsTypeReturnForMultiDimArray() {}")
        .setWindow(ScriptInjector.TOP_WINDOW)
        .inject();
  }

  @Override
  public String getModuleName() {
    return "com.google.gwt.core.Interop";
  }

  /* MAKE SURE EACH TYPE IS ONLY USED ONCE PER TEST CASE */

  @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "String")
  private static class SomeJsType { }

  @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
  private static class SomeOtherJsType { }

  public void testJsTypeArray() {
    Object[] array = new SomeJsType[10];

    array[0] = new SomeJsType();
    array[0] = new SomeOtherJsType();
    array[0] = new Object();

    assertTrue(array instanceof SomeJsType[]);
    assertTrue(array instanceof SomeOtherJsType[]);
    assertTrue(array instanceof Object[]);

    SomeOtherJsType[] other1 = (SomeOtherJsType[]) array;
    SomeOtherJsType[] other2 = (SomeOtherJsType[]) new Object[0];
  }

  @JsType(isNative = true)
  interface SimpleJsTypeReturnFromNative { }

  public void testJsTypeArray_returnFromNative() {
    SimpleJsTypeReturnFromNative[] array = returnJsTypeFromNative();
    assertEquals(2, array.length);
    assertNotNull(array[0]);
  }

  private native SimpleJsTypeReturnFromNative[] returnJsTypeFromNative() /*-{
    return [{}, {}];
  }-*/;

  @JsType(isNative = true)
  interface SimpleJsTypeReturnFromNativeWithAMethod {
    @JsProperty int getId();
  }

  public void testJsTypeArray_returnFromNativeWithACall() {
    SimpleJsTypeReturnFromNativeWithAMethod[] array = returnJsTypeWithIdsFromNative();
    assertEquals(2, array[1].getId());
  }

  private native SimpleJsTypeReturnFromNativeWithAMethod[] returnJsTypeWithIdsFromNative() /*-{
    return [{id:1}, {id:2}];
  }-*/;

  @JsType(isNative = true)
  interface SimpleJsTypeAsAField { }

  @JsType
  static class SimpleJsTypeAsAFieldHolder {
    public SimpleJsTypeAsAField[] arrayField;
  }

  public void testJsTypeArray_asAField() {
    SimpleJsTypeAsAFieldHolder holder = new SimpleJsTypeAsAFieldHolder();
    fillArrayField(holder);
    SimpleJsTypeAsAField[] array = holder.arrayField;
    assertEquals(2, array.length);
    assertNotNull(array[0]);
  }

  private native static void fillArrayField(SimpleJsTypeAsAFieldHolder holder) /*-{
    holder.arrayField = [{}, {}];
  }-*/;

  @JsType(isNative = true)
  interface SimpleJsTypeAsAParam { }

  @JsType
  static class SimpleJsTypeAsAParamHolder {
    private SimpleJsTypeAsAParam[] theParam;

    public void setArrayParam(SimpleJsTypeAsAParam[] param) {
      theParam = param;
    }
  }

  public void testJsTypeArray_asAParam() {
    SimpleJsTypeAsAParamHolder holder = new SimpleJsTypeAsAParamHolder();
    fillArrayParam(holder);
    SimpleJsTypeAsAParam[] array = holder.theParam;
    assertEquals(2, array.length);
    assertNotNull(array[0]);
  }

  private native void fillArrayParam(SimpleJsTypeAsAParamHolder holder) /*-{
    holder.setArrayParam([{}, {}]);
  }-*/;

  @JsType(isNative = true, namespace = JsPackage.GLOBAL,
      name = "JsTypeArrayTest_SimpleJsTypeReturnForMultiDimArray")
  static class SimpleJsTypeReturnForMultiDimArray {
    @JsProperty public native int getId();
  }

  public void testJsType3DimArray_castFromNativeWithACall() {
    SimpleJsTypeReturnForMultiDimArray[][][] array =
        (SimpleJsTypeReturnForMultiDimArray[][][]) returnJsType3DimFromNative();
    assertEquals(1, array.length);
    assertEquals(2, array[0].length);
    assertEquals(3, array[0][0].length);
    assertEquals(2, array[0][0][1].getId());
  }

  private native Object returnJsType3DimFromNative() /*-{
    return [ [ [{id:1}, {id:2}, {}], [] ] ];
  }-*/;

  private native SimpleJsTypeReturnForMultiDimArray getSimpleJsType(int i) /*-{
    return {id:i};
  }-*/;

  public void testObjectArray_castFromNative() {
    SimpleJsTypeReturnForMultiDimArray[] array =
        (SimpleJsTypeReturnForMultiDimArray[]) returnObjectArrayFromNative();
    assertNotNull((Object[]) array);
    assertEquals(3, array.length);
    assertEquals("1", array[0]);
  }

  public void testJsTypeArray_objectArrayInterchangeability() {
    Object[] objArray = new Object[1];

    SimpleJsTypeReturnForMultiDimArray[][][] array =
        (SimpleJsTypeReturnForMultiDimArray[][][]) objArray;

    objArray[0] = new Object[2];
    ((Object[]) objArray[0])[0] = new Object[3];
    array[0][0][1] = getSimpleJsType(2);
    assertEquals(1, array.length);
    assertEquals(2, array[0].length);
    assertEquals(3, array[0][0].length);
    assertEquals(2, array[0][0][1].getId());
  }

  public void testObjectArray_instanceOf() {
    Object array = new Object[0];
    assertTrue(array instanceof Object[]);
    assertFalse(array instanceof Double[]);
    assertFalse(array instanceof int[]);
    assertFalse(array instanceof SimpleJsTypeReturnForMultiDimArray);
    assertTrue(array instanceof SimpleJsTypeReturnForMultiDimArray[]);
    assertTrue(array instanceof SimpleJsTypeReturnForMultiDimArray[][]);
    assertTrue(array instanceof SimpleJsTypeReturnForMultiDimArray[][][]);
  }

  public void testJsTypeArray_instanceOf() {
    Object array = returnJsType3DimFromNative();
    assertTrue(array instanceof Object[]);
    assertFalse(array instanceof Double[]);
    assertFalse(array instanceof int[]);
    assertFalse(array instanceof SimpleJsTypeReturnForMultiDimArray);
    assertTrue(array instanceof SimpleJsTypeReturnForMultiDimArray[]);
    assertTrue(array instanceof SimpleJsTypeReturnForMultiDimArray[][]);
    assertTrue(array instanceof SimpleJsTypeReturnForMultiDimArray[][][]);
  }

  @JsType(isNative = true)
  private static class UnreferencedNativeType { }

  private static native Object createArray() /*-{
    return [];
  }-*/;

  public void testJsTypeArray_unreferencedNativeArrayInstanceOf() {
    assertTrue(createArray() instanceof UnreferencedNativeType[]);
  }

  @JsFunction
  interface SomeFunction {
    int m(int i);
  }

  @JsFunction
  interface SomeOtherFunction {
    int m(int i);
  }

  public void testJsFunctionArray() {
    Object[] array = new SomeFunction[10];

    array[0] = returnSomeFunction();

    assertTrue(array instanceof SomeFunction[]);
    assertFalse(array instanceof SomeOtherFunction[]);

    try {
      SomeOtherFunction[] other = (SomeOtherFunction[]) array;
      fail("Should have thrown");
    } catch (ClassCastException expected) {
    }

    try {
      array[1] = new Object();
      fail("Should have thrown");
    } catch (ArrayStoreException expected) {
    }
  }

  private native Object returnObjectArrayFromNative() /*-{
    return ["1", "2", "3"];
  }-*/;

  private native Object returnSomeFunction() /*-{
    return function(a) { return a + 2; };
  }-*/;

}
