/* ----------------------------------------
 * Origin  : GFI INFORMATIQUE 
 * Project : CDPP Propagation Tool 
 * ----------------------------------------
 * History 
 * Version : 01/05/2015 : SCA : V2.1
 * ----------------------------------------
 */
package fr.tlse.irap.pt.client.controller.drawingPlane;

import java.util.ArrayList;
import java.util.List;

import fr.tlse.irap.utils.CoordConverter;
import javafx.scene.Node;
import javafx.scene.paint.Color;
import javafx.scene.shape.Arc;
import javafx.scene.shape.ArcType;
import javafx.scene.shape.Circle;

public class CmeSSE implements IDrawingCme {

	private static Color CME_COLOR = Color.web("#BDBDBD");
	
	private Arc arc;
	private Circle circle;
	private double longitude = 0.0; // CME longitude in HAE
	private double extent = DEFAULT_EXTENT;   // extent of CME in degrees
	private double deltaLong = 0.0; // small angle between central axis of CME and target
	private double radialDistKm = 0;  	// target distance in km
	
	public CmeSSE() {
		createCMEArc(longitude, extent, 0);
		createCMECircle(0, 0, 0);
	}

	public void updateViewWith(double longSource, double deltaLong, double extent) {
		setLongitude(longSource);
		setDeltaLong(deltaLong);
		setExtent(extent);
		update();
	}

	public void updateViewWith(double radialDistKm, double deltaLong) {
		setRadialDistKm(radialDistKm);
		setDeltaLong(deltaLong);
		update();
	}

	public void update(){
		double angle = DrawHelper.HAEToHEE(longitude);
		double scale = DrawHelper.INIT_SCALE * DrawHelper.getScale();
		double di = CoordConverter.toEcliptic(radialDistKm * scale);
		
		double lambda = Math.toRadians(extent/2);
		double delta = Math.toRadians(deltaLong);
		double rSSE;
		if (delta == 0 || delta > lambda) {
			rSSE = di;
		}
		else {
			// compute RSSE according to target radial distance 
			rSSE = di * (1 + Math.sin(lambda)) / (Math.cos(delta) + Math.sqrt(Math.pow(Math.sin(lambda), 2) - Math.pow(Math.sin(delta), 2)));
			//System.out.println("====> CME SSE : rSSE = " + rSSE);
		}
		// compute radius of arc according to RSSE 
		double radius = rSSE * Math.cos(lambda) / (1 + Math.tan(lambda));
		
		modifyCMEWith(angle, radius, extent);
	}
	
	/**
	 * Create CME arc 
	 * @param angle
	 * @param length
	 * @param radius
	 * @return
	 */
	private void createCMEArc(double angle, double length, double radius) {
		arc = new Arc();
		arc.setType(ArcType.ROUND);
		arc.setId("CME");

		arc.setRadiusX(radius);
		arc.setRadiusY(radius);
		arc.setStartAngle(angle - length / 2);
		arc.setLength(length);
		arc.setFill(CME_COLOR);
		arc.setStroke(CME_COLOR);
		// CME not visible by default
		arc.setVisible(false);
	}

	/**
	 * Create CME circle 
	 * @param center XY
	 * @param radius
	 * @return
	 */
	private void createCMECircle(double centerX, double centerY, double radius) {
		circle = new Circle(radius);
		circle.setId("CME");
		circle.setFill(CME_COLOR);
		circle.setStroke(Color.TRANSPARENT);
		circle.setCenterX(centerX);
		circle.setCenterY(centerY);
		circle.setVisible(false);
	}

	/**
	 * Modify CME with new parameters
	 * @param angle : HEE longitude of the center axis of CME 
	 * @param radius : radius of the CME
	 * @param length : longitude extent of the CME
	 */
	private void modifyCMEWith(double angle, double radius, double length) {
		arc.setStartAngle(angle - length/2);
		arc.setLength(length);
		arc.setRadiusX(radius);
		arc.setRadiusY(radius);

		double alpha = Math.toRadians(angle);
		double lambda = Math.toRadians(length/2);
		double c = radius / Math.cos(lambda);
		circle.setCenterX(c * Math.cos(alpha));
		circle.setCenterY(- c * Math.sin(alpha));
		circle.setRadius(c * Math.sin(lambda));
	}

	public Arc getArc() {
		return arc;
	}
	public void setArc(Arc arc) {
		this.arc = arc;
	}
	public double getExtent() {
		return extent;
	}

	public void setExtent(double extent) {
		if (extent < 180) {
			this.extent = extent;
		}
	}

	public double getLongitude() {
		return longitude;
	}

	public void setLongitude(double longitude) {
		this.longitude = longitude;
	}

	public void show() {
		if (!arc.isDisable()) {
			arc.setVisible(true);
			circle.setVisible(true);
		}
	}

	public void hide() {
		arc.setVisible(false);
		circle.setVisible(false);
	}

	public boolean isVisible(){
		return arc.isVisible();
	}

	public void setDisable(boolean disable) {
		arc.setDisable(disable);
		circle.setDisable(disable);
	}
			
	public double getRadius() {
		return arc.getRadiusX();
	}

	public void setRadius(double radius) {
		this.arc.setRadiusX(radius);
		this.arc.setRadiusY(radius);
	}

	public List<Node> getNodes() {
		List<Node> nodes = new ArrayList<Node>();
		nodes.add(arc);
		nodes.add(circle);
		return nodes;
	}

	public double getDeltaLong() {
		return deltaLong;
	}

	/**
	 * Set the small angle between CME and target 
	 * @param deltaLong
	 */
	public void setDeltaLong(double deltaLong) {
		this.deltaLong = deltaLong > 180 ? 360.0 - deltaLong : deltaLong;
	}

	public double getRadialDistKm() {
		return radialDistKm;
	}

	public void setRadialDistKm(double radialDistKm) {
		this.radialDistKm = radialDistKm;
	}
}
