package ch.epfl.isochrone.geo;

import static java.lang.Math.*;
import static ch.epfl.isochrone.math.Math.*; 
 

/**
 * Un point dans le système de coordonnées WGS 84. 
 * 
 * @author Charles Thiebaut (238935) 
 * @author Arnaud Delamare (234841)
 *
 */
public final class PointWGS84 
{
    private final double longitude; 
    private final double latitude; 
    private final int RAYONTERRE = 6378137;
    
   /**
 * @param longitude
 *          La longitude du point GPS 
 * @param latitude
 *          La latitude du point GPS
 * @throws IllegalArgumentException
 *          si la longitude ou la latitude est en dehors du domaine demandé                   
 */
    public PointWGS84(double longitude, double latitude)
    {          
        
        if (longitude < -PI || longitude > PI)
        {
            throw new IllegalArgumentException(); 
        }
        
      
        
        if (latitude < -PI/2 || latitude > PI/2)
        {
            throw new IllegalArgumentException(); 
        }   
        
        this.longitude = longitude; 
        this.latitude = latitude; 
        
   }
   
   public double latitude()
   {
       return this.latitude; 
   }
   
   public double longitude()
   {
       return this.longitude; 
   }
 /**
 * @return indique la distance entre deux point en coordonnée WSG84, entre celui passe en argument et celui sur lequel on applique la methode.
 */  
   public double distanceTo(PointWGS84 that)
   {
       return 2*RAYONTERRE*asin(sqrt(haversin(this.latitude - that.latitude) + cos(this.latitude)*cos(that.latitude)*haversin(this.longitude - that.longitude)));
   }
   
   /**
 * @param zoom
 *          indique le zoom à laquelle la carte 2D ce situe.
 *          
 * @throws IllegalArgumentExceptions
 *           Si le zooom est négatif. 
 *                   
 * @return
 *          le point WSG84 en coordonnées OSM.
 */
public PointOSM toOSM(int zoom) 
   {
       if(zoom<0)
       {
           throw new IllegalArgumentException(); 
       }
       
       
       double p = PI;
       double s = pow(2,(zoom+8)); 
       double x = ((s)*(this.longitude + p))/(2*PI);
       double y = ((s)*(p-asinh(tan(this.latitude))))/(2*PI);
       
       return new PointOSM(zoom,x,y);
   }
 
/**
 * @return redéfinit la methode toString héritée la classe OBJET, et permet d'affiche le point de la manière lisible.
 */
   public String toString()
   {
       return "("+ toDegrees(this.longitude) + ", " + toDegrees(this.latitude) + ")";
   }
   
}
