'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var base = require('./base.cjs');
var moonphase = require('./moonphase.cjs');

/**
 * @copyright 2013 Sonia Keys
 * @copyright 2016 commenthol
 * @license MIT
 * @module eclipse
 */

/**
 * @private
 */
const g = function (k, jm, c1, c2) { // (k, jm, c1, c2 float64)  (eclipse bool, jdeMax, γ, u, Mʹ float64)
  const ck = 1 / 1236.85;
  const p = Math.PI / 180;
  const T = k * ck;
  const F = base['default'].horner(T, 160.7108 * p, 390.67050284 * p / ck,
    -0.0016118 * p, -0.00000227 * p, 0.000000011 * p);
  if (Math.abs(Math.sin(F)) > 0.36) {
    return [false] // no eclipse
  }
  const eclipse = true;
  const E = base['default'].horner(T, 1, -0.002516, -0.0000074);
  const M = base['default'].horner(T, 2.5534 * p, 29.1053567 * p / ck,
    -0.0000014 * p, -0.00000011 * p);
  const Mʹ = base['default'].horner(T, 201.5643 * p, 385.81693528 * p / ck,
    0.0107582 * p, 0.00001238 * p, -0.000000058 * p);
  const Ω = base['default'].horner(T, 124.7746 * p, -1.56375588 * p / ck,
    0.0020672 * p, 0.00000215 * p);
  const sΩ = Math.sin(Ω);
  const F1 = F - 0.02665 * p * sΩ;
  const A1 = base['default'].horner(T, 299.77 * p, 0.107408 * p / ck, -0.009173 * p);
  // (54.1) p. 380
  const jdeMax = jm +
    c1 * Math.sin(Mʹ) +
    c2 * Math.sin(M) * E +
    0.0161 * Math.sin(2 * Mʹ) +
    -0.0097 * Math.sin(2 * F1) +
    0.0073 * Math.sin(Mʹ - M) * E +
    -0.005 * Math.sin(Mʹ + M) * E +
    -0.0023 * Math.sin(Mʹ - 2 * F1) +
    0.0021 * Math.sin(2 * M) * E +
    0.0012 * Math.sin(Mʹ + 2 * F1) +
    0.0006 * Math.sin(2 * Mʹ + M) * E +
    -0.0004 * Math.sin(3 * Mʹ) +
    -0.0003 * Math.sin(M + 2 * F1) * E +
    0.0003 * Math.sin(A1) +
    -0.0002 * Math.sin(M - 2 * F1) * E +
    -0.0002 * Math.sin(2 * Mʹ - M) * E +
    -0.0002 * sΩ;
  const P = 0.207 * Math.sin(M) * E +
    0.0024 * Math.sin(2 * M) * E +
    -0.0392 * Math.sin(Mʹ) +
    0.0116 * Math.sin(2 * Mʹ) +
    -0.0073 * Math.sin(Mʹ + M) * E +
    0.0067 * Math.sin(Mʹ - M) * E +
    0.0118 * Math.sin(2 * F1);
  const Q = 5.2207 +
    -0.0048 * Math.cos(M) * E +
    0.002 * Math.cos(2 * M) * E +
    -0.3299 * Math.cos(Mʹ) +
    -0.006 * Math.cos(Mʹ + M) * E +
    0.0041 * Math.cos(Mʹ - M) * E;
  const [sF1, cF1] = base['default'].sincos(F1);
  const W = Math.abs(cF1);
  const γ = (P * cF1 + Q * sF1) * (1 - 0.0048 * W);
  const u = 0.0059 +
    0.0046 * Math.cos(M) * E +
    -0.0182 * Math.cos(Mʹ) +
    0.0004 * Math.cos(2 * Mʹ) +
    -0.0005 * Math.cos(M + Mʹ);
  return [eclipse, jdeMax, γ, u, Mʹ] // (eclipse bool, jdeMax, γ, u, Mʹ float64)
};

/**
 * Eclipse type identifiers returned from Solar and Lunar.
 */
const TYPE = {
  None: 0,
  Partial: 1, // for solar eclipses
  Annular: 2, // solar
  AnnularTotal: 3, // solar
  Penumbral: 4, // for lunar eclipses
  Umbral: 5, // lunar
  Total: 6 // solar or lunar
};

/**
 * Snap returns k at specified quarter q nearest year y.
 * Cut and paste from moonphase.  Time corresponding to k needed in these
 * algorithms but otherwise not meaningful enough to export from moonphase.
 */
const snap = function (y, q) { // (y, q float64)  float64
  const k = (y - 2000) * 12.3685; // (49.2) p. 350
  return Math.floor(k - q + 0.5) + q
};

/**
 * Solar computes quantities related to solar eclipses.
 *
 * Argument year is a decimal year specifying a date.
 *
 * eclipseType will be None, Partial, Annular, AnnularTotal, or Total.
 * If None, none of the other return values may be meaningful.
 *
 * central is true if the center of the eclipse shadow touches the Earth.
 *
 * jdeMax is the jde when the center of the eclipse shadow is closest to the
 * Earth center, in a plane through the center of the Earth.
 *
 * γ is the distance from the eclipse shadow center to the Earth center
 * at time jdeMax.
 *
 * u is the radius of the Moon's umbral cone in the plane of the Earth.
 *
 * p is the radius of the penumbral cone.
 *
 * mag is eclipse magnitude for partial eclipses.  It is not valid for other
 * eclipse types.
 *
 * γ, u, and p are in units of equatorial Earth radii.
 */
function solar (year) { // (year float64)  (eclipseType int, central bool, jdeMax, γ, u, p, mag float64)
  let eclipseType = TYPE.None;
  let mag;

  const [e, jdeMax, γ, u, _] = g(snap(year, 0), moonphase['default'].meanNew(year), -0.4075, 0.1721); // eslint-disable-line no-unused-vars

  const p = u + 0.5461;
  if (!e) {
    return { type: eclipseType } // no eclipse
  }
  const aγ = Math.abs(γ);
  if (aγ > 1.5433 + u) {
    return { type: eclipseType } // no eclipse
  }
  const central = aγ < 0.9972; // eclipse center touches Earth

  if (!central) {
    eclipseType = TYPE.Partial; // most common case
    if (aγ < 1.026) { // umbral cone may touch earth
      if (aγ < 0.9972 + Math.abs(u)) { // total or annular
        eclipseType = TYPE.Total; // report total in both cases
      }
    }
  } else if (u < 0) {
    eclipseType = TYPE.Total;
  } else if (u > 0.0047) {
    eclipseType = TYPE.Annular;
  } else {
    const ω = 0.00464 * Math.sqrt(1 - γ * γ);
    if (u < ω) {
      eclipseType = TYPE.AnnularTotal;
    } else {
      eclipseType = TYPE.Annular;
    }
  }

  if (eclipseType === TYPE.Partial) {
    // (54.2) p. 382
    mag = (1.5433 + u - aγ) / (0.5461 + 2 * u);
  }

  return {
    type: eclipseType,
    central: central,
    jdeMax: jdeMax,
    magnitude: mag,
    distance: γ,
    umbral: u,
    penumbral: p
  }
}

/**
 * Lunar computes quantities related to lunar eclipses.
 *
 * Argument year is a decimal year specifying a date.
 *
 * eclipseType will be None, Penumbral, Umbral, or Total.
 * If None, none of the other return values may be meaningful.
 *
 * jdeMax is the jde when the center of the eclipse shadow is closest to the
 * Moon center, in a plane through the center of the Moon.
 *
 * γ is the distance from the eclipse shadow center to the moon center
 * at time jdeMax.
 *
 * σ is the radius of the umbral cone in the plane of the Moon.
 *
 * ρ is the radius of the penumbral cone.
 *
 * mag is eclipse magnitude.
 *
 * sd- return values are semidurations of the phases of the eclipse, in days.
 *
 * γ, σ, and ρ are in units of equatorial Earth radii.
 */
function lunar (year) { // (year float64)  (eclipseType int, jdeMax, γ, ρ, σ, mag, sdTotal, sdPartial, sdPenumbral float64)
  let eclipseType = TYPE.None;
  let mag;
  let sdTotal;
  let sdPartial;
  let sdPenumbral;

  const [e, jdeMax, γ, u, Mʹ] = g(snap(year, 0.5),
    moonphase['default'].meanFull(year), -0.4065, 0.1727);
  if (!e) {
    return { type: eclipseType } // no eclipse
  }
  const ρ = 1.2848 + u;
  const σ = 0.7403 - u;
  const aγ = Math.abs(γ);
  mag = (1.0128 - u - aγ) / 0.545; // (54.3) p. 382

  if (mag > 1) {
    eclipseType = TYPE.Total;
  } else if (mag > 0) {
    eclipseType = TYPE.Umbral;
  } else {
    mag = (1.5573 + u - aγ) / 0.545; // (54.4) p. 382
    if (mag < 0) {
      return { type: eclipseType } // no eclipse
    }
    eclipseType = TYPE.Penumbral;
  }

  const p = 1.0128 - u;
  const t = 0.4678 - u;
  const n = 0.5458 + 0.04 * Math.cos(Mʹ);
  const γ2 = γ * γ;

  /* eslint-disable no-fallthrough */
  switch (eclipseType) {
    case TYPE.Total: {
      sdTotal = Math.sqrt(t * t - γ2) / n / 24;
    }
    case TYPE.Umbral: {
      sdPartial = Math.sqrt(p * p - γ2) / n / 24;
    }
    default: {
      const h = 1.5573 + u;
      sdPenumbral = Math.sqrt(h * h - γ2) / n / 24;
    }
  }
  /* eslint-enable */

  return {
    type: eclipseType,
    jdeMax: jdeMax,
    magnitude: mag,
    distance: γ,
    umbral: σ,
    penumbral: ρ,
    sdTotal: sdTotal,
    sdPartial: sdPartial,
    sdPenumbral: sdPenumbral
  }
}

var eclipse = {
  TYPE,
  solar,
  lunar
};

exports.TYPE = TYPE;
exports.default = eclipse;
exports.lunar = lunar;
exports.solar = solar;
