import { Cartesian2 } from "../../Source/Cesium.js";
import { Cartesian3 } from "../../Source/Cesium.js";
import { Cartographic } from "../../Source/Cesium.js";
import { Ellipsoid } from "../../Source/Cesium.js";
import { Math as CesiumMath } from "../../Source/Cesium.js";
import { WebMercatorProjection } from "../../Source/Cesium.js";

describe("Core/WebMercatorProjection", function () {
  it("construct0", function () {
    var projection = new WebMercatorProjection();
    expect(projection.ellipsoid).toEqual(Ellipsoid.WGS84);
  });

  it("construct1", function () {
    var ellipsoid = Ellipsoid.UNIT_SPHERE;
    var projection = new WebMercatorProjection(ellipsoid);
    expect(projection.ellipsoid).toEqual(ellipsoid);
  });

  it("project0", function () {
    var height = 10.0;
    var cartographic = new Cartographic(0.0, 0.0, height);
    var projection = new WebMercatorProjection();
    expect(projection.project(cartographic)).toEqual(
      new Cartesian3(0.0, 0.0, height)
    );
  });

  it("project1", function () {
    var ellipsoid = Ellipsoid.WGS84;
    var cartographic = new Cartographic(Math.PI, CesiumMath.PI_OVER_FOUR, 0.0);

    // expected equations from Wolfram MathWorld:
    // http://mathworld.wolfram.com/MercatorProjection.html
    var expected = new Cartesian3(
      ellipsoid.maximumRadius * cartographic.longitude,
      ellipsoid.maximumRadius *
        Math.log(Math.tan(Math.PI / 4.0 + cartographic.latitude / 2.0)),
      0.0
    );

    var projection = new WebMercatorProjection(ellipsoid);
    expect(projection.project(cartographic)).toEqualEpsilon(
      expected,
      CesiumMath.EPSILON8
    );
  });

  it("project2", function () {
    var ellipsoid = Ellipsoid.UNIT_SPHERE;
    var cartographic = new Cartographic(-Math.PI, CesiumMath.PI_OVER_FOUR, 0.0);

    // expected equations from Wolfram MathWorld:
    // http://mathworld.wolfram.com/MercatorProjection.html
    var expected = new Cartesian3(
      ellipsoid.maximumRadius * cartographic.longitude,
      ellipsoid.maximumRadius *
        Math.log(Math.tan(Math.PI / 4.0 + cartographic.latitude / 2.0)),
      0.0
    );

    var projection = new WebMercatorProjection(ellipsoid);
    expect(projection.project(cartographic)).toEqualEpsilon(
      expected,
      CesiumMath.EPSILON15
    );
  });

  it("project3", function () {
    var ellipsoid = Ellipsoid.WGS84;
    var cartographic = new Cartographic(Math.PI, CesiumMath.PI_OVER_FOUR, 0.0);

    // expected equations from Wolfram MathWorld:
    // http://mathworld.wolfram.com/MercatorProjection.html
    var expected = new Cartesian3(
      ellipsoid.maximumRadius * cartographic.longitude,
      ellipsoid.maximumRadius *
        Math.log(Math.tan(Math.PI / 4.0 + cartographic.latitude / 2.0)),
      0.0
    );

    var projection = new WebMercatorProjection(ellipsoid);
    var result = new Cartesian3(0.0, 0.0, 0.0);
    var returnValue = projection.project(cartographic, result);
    expect(result).toEqual(returnValue);
    expect(result).toEqualEpsilon(expected, CesiumMath.EPSILON8);
  });

  it("unproject0", function () {
    var cartographic = new Cartographic(
      CesiumMath.PI_OVER_TWO,
      CesiumMath.PI_OVER_FOUR,
      12.0
    );
    var projection = new WebMercatorProjection();
    var projected = projection.project(cartographic);
    expect(projection.unproject(projected)).toEqualEpsilon(
      cartographic,
      CesiumMath.EPSILON14
    );
  });

  it("unproject1", function () {
    var cartographic = new Cartographic(
      CesiumMath.PI_OVER_TWO,
      CesiumMath.PI_OVER_FOUR,
      12.0
    );
    var projection = new WebMercatorProjection();
    var projected = projection.project(cartographic);
    var result = new Cartographic(0.0, 0.0, 0.0);
    var returnValue = projection.unproject(projected, result);
    expect(result).toEqual(returnValue);
    expect(result).toEqualEpsilon(cartographic, CesiumMath.EPSILON14);
  });

  it("unproject is correct at corners", function () {
    var projection = new WebMercatorProjection();
    var southwest = projection.unproject(
      new Cartesian2(-20037508.342787, -20037508.342787)
    );
    expect(southwest.longitude).toEqualEpsilon(-Math.PI, CesiumMath.EPSILON12);
    expect(southwest.latitude).toEqualEpsilon(
      CesiumMath.toRadians(-85.05112878),
      CesiumMath.EPSILON11
    );

    var southeast = projection.unproject(
      new Cartesian2(20037508.342787, -20037508.342787)
    );
    expect(southeast.longitude).toEqualEpsilon(Math.PI, CesiumMath.EPSILON12);
    expect(southeast.latitude).toEqualEpsilon(
      CesiumMath.toRadians(-85.05112878),
      CesiumMath.EPSILON11
    );

    var northeast = projection.unproject(
      new Cartesian2(20037508.342787, 20037508.342787)
    );
    expect(northeast.longitude).toEqualEpsilon(Math.PI, CesiumMath.EPSILON12);
    expect(northeast.latitude).toEqualEpsilon(
      CesiumMath.toRadians(85.05112878),
      CesiumMath.EPSILON11
    );

    var northwest = projection.unproject(
      new Cartesian2(-20037508.342787, 20037508.342787)
    );
    expect(northwest.longitude).toEqualEpsilon(-Math.PI, CesiumMath.EPSILON12);
    expect(northwest.latitude).toEqualEpsilon(
      CesiumMath.toRadians(85.05112878),
      CesiumMath.EPSILON11
    );
  });

  it("project is correct at corners.", function () {
    var maxLatitude = WebMercatorProjection.MaximumLatitude;

    var projection = new WebMercatorProjection();

    var southwest = projection.project(
      new Cartographic(-Math.PI, -maxLatitude)
    );
    expect(southwest.x).toEqualEpsilon(-20037508.342787, CesiumMath.EPSILON3);
    expect(southwest.y).toEqualEpsilon(-20037508.342787, CesiumMath.EPSILON3);

    var southeast = projection.project(new Cartographic(Math.PI, -maxLatitude));
    expect(southeast.x).toEqualEpsilon(20037508.342787, CesiumMath.EPSILON3);
    expect(southeast.y).toEqualEpsilon(-20037508.342787, CesiumMath.EPSILON3);

    var northeast = projection.project(new Cartographic(Math.PI, maxLatitude));
    expect(northeast.x).toEqualEpsilon(20037508.342787, CesiumMath.EPSILON3);
    expect(northeast.y).toEqualEpsilon(20037508.342787, CesiumMath.EPSILON3);

    var northwest = projection.project(new Cartographic(-Math.PI, maxLatitude));
    expect(northwest.x).toEqualEpsilon(-20037508.342787, CesiumMath.EPSILON3);
    expect(northwest.y).toEqualEpsilon(20037508.342787, CesiumMath.EPSILON3);
  });

  it("projected y is clamped to valid latitude range.", function () {
    var projection = new WebMercatorProjection();
    var southPole = projection.project(
      new Cartographic(0.0, -CesiumMath.PI_OVER_TWO)
    );
    var southLimit = projection.project(
      new Cartographic(0.0, -WebMercatorProjection.MaximumLatitude)
    );
    expect(southPole.y).toEqual(southLimit.y);

    var northPole = projection.project(
      new Cartographic(0.0, CesiumMath.PI_OVER_TWO)
    );
    var northLimit = projection.project(
      new Cartographic(0.0, WebMercatorProjection.MaximumLatitude)
    );
    expect(northPole.y).toEqual(northLimit.y);
  });

  it("project throws without cartesian", function () {
    var projection = new WebMercatorProjection();
    expect(function () {
      return projection.unproject();
    }).toThrowDeveloperError();
  });
});
