/**
 * 
 */
package test.geotools;

import java.util.Collections;
import java.util.Map;

import org.geotools.geometry.GeneralDirectPosition;
import org.geotools.referencing.FactoryFinder;
import org.geotools.referencing.factory.FactoryGroup;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.crs.GeographicCRS;
import org.opengis.referencing.crs.ProjectedCRS;
import org.opengis.referencing.cs.CartesianCS;
import org.opengis.referencing.operation.CoordinateOperation;
import org.opengis.referencing.operation.CoordinateOperationFactory;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.spatialschema.geometry.DirectPosition;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.LineSegment;

/**
 * @author mariano
 *
 */
public class ProyectedRelationCalculator {

	MathTransform mathTransform = null;
	
	/**
	 * Define a math transformation betwen coordinates (lat,long) to (x,y)
	 */
	private void setMathTransform()
		throws Exception
	{
		GeographicCRS geoCRS = org.geotools.referencing.crs.DefaultGeographicCRS.WGS84;
		CartesianCS cartCS = org.geotools.referencing.cs.DefaultCartesianCS.GENERIC_2D;

		MathTransformFactory mtFactory = FactoryFinder.getMathTransformFactory(null);
		FactoryGroup factories = new FactoryGroup();

		ParameterValueGroup parameters = mtFactory.getDefaultParameters("Mercator_1SP");
//		parameters.parameter("scale_factor").setValue(0.9996);
		parameters.parameter("scale_factor").setValue(1.000);
////	parameters.parameter("central_meridian").setValue(0.0);
//		parameters.parameter("latitude_of_origin").setValue(0.0);
////		parameters.parameter("false_easting").setValue(0.0);
////		parameters.parameter("false_northing").setValue(0.0);

		Map properties = Collections.singletonMap("name", "WGS 84 / Mercator_1SP");
		ProjectedCRS projCRS = factories.createProjectedCRS(properties, geoCRS, null, parameters, cartCS);
	
		CoordinateOperationFactory coFactory = FactoryFinder.getCoordinateOperationFactory(null);

		CoordinateReferenceSystem sourceCRS = geoCRS;
		CoordinateReferenceSystem targetCRS = projCRS;
		CoordinateOperation op = coFactory.createOperation(sourceCRS, targetCRS);
		this.mathTransform = op.getMathTransform();
		System.out.println("Math Transform: " + this.mathTransform.toWKT());
	}
	
	public MathTransform getMathTransform()
	 throws Exception
	{
		if (this.mathTransform == null)
		{
			this.setMathTransform();
		}
		return mathTransform;
	}
	
	/**
	 * Transform the given point using mathTransform
	 * @param point
	 * @return
	 */
	public DirectPosition transformPoint(DirectPosition point)
		throws Exception
	{
		return this.getMathTransform().transform(point,null);
	}
	
	/**
	 * calculate the relation betwen the points - represented by the segment
	 * @param coordinate1
	 * @param coordinate2
	 */
	public LineSegment calculateRelation(DirectPosition point1, DirectPosition point2)
	{
		double[] coords1 = point1.getCoordinates();
		Coordinate coord1 = new Coordinate(coords1[0],coords1[1]);
		double[] coords2 = point2.getCoordinates();
		Coordinate coord2 = new Coordinate(coords2[0],coords2[1]);
		return new LineSegment(coord1,coord2);
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) 
	 throws Exception
	{
//example 1
		DirectPosition pt1 = new GeneralDirectPosition(-5.986944, 37.377222); 
		DirectPosition pt2 = new GeneralDirectPosition(-58.366667, -34.600000);
		String city1="Sevilla";
		String city2="Bs. As";

//example 2
//		DirectPosition pt1 = new GeneralDirectPosition(-64.2, -31.39);
//		DirectPosition pt2 = new GeneralDirectPosition(-68.32, -54.82);
//		String city1="Cordoba";
//		String city2="Ushuaia";

		System.out.println("Point1 ("+city1+"): " + pt1+" \nPoint2 ("+city2+"):"+pt2);
		
		ProyectedRelationCalculator proyectedRelationCalculator = new ProyectedRelationCalculator();
		//transforming de points
		pt1 = proyectedRelationCalculator.transformPoint(pt1);
		pt2 = proyectedRelationCalculator.transformPoint(pt2);
		System.out.println("Transformation (x,y) \n====================\nPoint1 ("+city1+"): " + pt1+" \nPoint2 ("+city2+"): "+pt2);

		//calculating the relation
		LineSegment relation = proyectedRelationCalculator.calculateRelation(pt1, pt2);
		double distance = relation.getLength();
		double angle = relation.angle();
		System.out.println("Distance = "+distance+" - Orientation = "+((angle)*180/Math.PI));
		double realDistance = 9670316.0; //obtenida de http://jan.ucc.nau.edu/%7Ecvm/latlongdist.html 
		System.out.println("aditional distance = "+(distance - realDistance));
	}

}
