/*
 * Licensed Materials - Property of Rogue Wave Software, Inc. 
 * © Copyright Rogue Wave Software, Inc. 2014, 2015 
 * © 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 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;
import java.io.IOException;

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);
  }

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

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

  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));
  }

  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);
  }

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

  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;
  }
}