/*
 * Licensed Materials - Property of Perforce Software, Inc. 
 * © Copyright Perforce Software, Inc. 2014, 2021 
 * © Copyright IBM Corp. 2009, 2014
 * © Copyright ILOG 1996, 2009
 * All Rights Reserved.
 *
 * Note to U.S. Government Users Restricted Rights:
 * The Software and Documentation were developed at private expense and
 * are "Commercial Items" as that term is defined at 48 CFR 2.101,
 * consisting of "Commercial Computer Software" and
 * "Commercial Computer Software Documentation", as such terms are
 * used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4,
 * as applicable.
 */

import java.io.IOException;

import ilog.views.io.IlvInputStream;
import ilog.views.io.IlvOutputStream;
import ilog.views.io.IlvReadFileException;
import ilog.views.maps.IlvCoordinate;
import ilog.views.maps.projection.IlvProjection;
import ilog.views.maps.projection.IlvToleranceConditionException;

class Mercator extends IlvProjection {
  public Mercator() {
    super(true, true, IlvProjection.CONFORMAL);
  }

  // copy constructor
  public Mercator(Mercator source) {
    super(source);
  }

  // IO constructor
  public Mercator(IlvInputStream stream) throws IlvReadFileException, IOException {
    super(stream);
  }

  Override
  public void write(IlvOutputStream stream) throws IOException {
    super.write(stream);
  }

  Override
  public IlvProjection copy() {
    return new Mercator(this);
  }

  Override
  protected void sForward(IlvCoordinate ll) throws IlvToleranceConditionException {
    if (Math.abs(Math.abs(ll.y) - Math.PI / 2D) <= 1e-10D)
      throw new IlvToleranceConditionException();
    ll.y = Math.log(Math.tan(Math.PI / 4D + .5D * ll.y));
  }

  Override
  protected void eForward(IlvCoordinate ll) throws IlvToleranceConditionException {
    if (Math.abs(Math.abs(ll.y) - Math.PI / 2D) <= 1e-10D)
      throw new IlvToleranceConditionException();
    double e = Math.sqrt(getEllipsoid().getES());
    double sinphi = e * Math.sin(ll.y);
    ll.y = Math.tan(.5D * (Math.PI / 2D - ll.y)) / Math.pow((1D - sinphi) / (1D + sinphi), .5D * e);
    ll.y = -Math.log(ll.y);
  }

  Override
  protected void sInverse(IlvCoordinate xy) {
    xy.y = Math.PI / 2D - 2D * Math.atan(Math.exp(-xy.y));
  }

  Override
  protected void eInverse(IlvCoordinate xy) throws IlvToleranceConditionException {
    double ts = Math.exp(-xy.y);
    double e = Math.sqrt(getEllipsoid().getES());
    double eccnth = .5D * e;
    double Phi = Math.PI / 2D - 2D * Math.atan(ts);
    int i = 15;
    double dphi;
    do {
      double con = e * Math.sin(Phi);
      dphi = Math.PI / 2D - 2D * Math.atan(ts * Math.pow((1D - con) / (1D + con), eccnth)) - Phi;
      Phi += dphi;
    } while ((Math.abs(dphi) > 1e-10D) && (--i != 0));
    if (i <= 0)
      throw new IlvToleranceConditionException("non-convergent inverse phi2");
    xy.y = Phi;
  }
}