import {geoProjection as projection} from "d3-geo";
import {abs, acos, cos, epsilon, pi, sin, sinci, sqrt} from "./math";

export function aitoffRaw(x, y) {
  var cosy = cos(y), sincia = sinci(acos(cosy * cos(x /= 2)));
  return [2 * cosy * sin(x) * sincia, sin(y) * sincia];
}

// Abort if [x, y] is not within an ellipse centered at [0, 0] with
// semi-major axis pi and semi-minor axis pi/2.
aitoffRaw.invert = function(x, y) {
  if (x * x + 4 * y * y > pi * pi + epsilon) return;
  var x1 = x, y1 = y, i = 25;
  do {
    var sinx = sin(x1),
        sinx_2 = sin(x1 / 2),
        cosx_2 = cos(x1 / 2),
        siny = sin(y1),
        cosy = cos(y1),
        sin_2y = sin(2 * y1),
        sin2y = siny * siny,
        cos2y = cosy * cosy,
        sin2x_2 = sinx_2 * sinx_2,
        c = 1 - cos2y * cosx_2 * cosx_2,
        e = c ? acos(cosy * cosx_2) * sqrt(f = 1 / c) : f = 0,
        f,
        fx = 2 * e * cosy * sinx_2 - x,
        fy = e * siny - y,
        dxdx = f * (cos2y * sin2x_2 + e * cosy * cosx_2 * sin2y),
        dxdy = f * (0.5 * sinx * sin_2y - e * 2 * siny * sinx_2),
        dydx = f * 0.25 * (sin_2y * sinx_2 - e * siny * cos2y * sinx),
        dydy = f * (sin2y * cosx_2 + e * sin2x_2 * cosy),
        z = dxdy * dydx - dydy * dxdx;
    if (!z) break;
    var dx = (fy * dxdy - fx * dydy) / z,
        dy = (fx * dydx - fy * dxdx) / z;
    x1 -= dx, y1 -= dy;
  } while ((abs(dx) > epsilon || abs(dy) > epsilon) && --i > 0);
  return [x1, y1];
};

export default function() {
  return projection(aitoffRaw)
      .scale(152.63);
}
