/* ----------------------------------------
 * Origin  : GFI INFORMATIQUE 
 * Project : CDPP Propagation Tool 
 * ----------------------------------------
 * History 
 * Version : 01/05/2015 : SCA : V2.1
 * Version : 07/04/2016 : SCA : V2.2 (PSWS-H2020)
 * => Add Z axis in propagation computation 
 * ----------------------------------------
 */
package fr.tlse.irap.pt.client.controller.tools.corotation;

import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import fr.tlse.irap.pt.client.controller.common.Formatter;
import fr.tlse.irap.pt.client.services.ServiceFactory;
import fr.tlse.irap.spaceElement.SpaceElement;
import fr.tlse.irap.spaceElement.Sun;
import fr.tlse.irap.tool.corotation.Corotation;
import fr.tlse.irap.utils.CoordConverter;
import fr.tlse.irap.utils.ToolHelper;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class CorotationStartModel {

	protected static final Logger log = LoggerFactory.getLogger(CorotationStartModel.class);

	ObjectProperty<SpaceElement> startSource = new SimpleObjectProperty<SpaceElement>();
	StringProperty startTime = new SimpleStringProperty();
	StringProperty speed = new SimpleStringProperty();
	StringProperty deltaSpeed = new SimpleStringProperty();
	StringProperty spread = new SimpleStringProperty();
	StringProperty rotPeriod = new SimpleStringProperty();
	StringProperty longStart = new SimpleStringProperty();
	
	SpaceElement src;
	Sun sun = new Sun();

	/**
	 * Set up start fields from model
	 * @param corotation
	 */
	public void setUpViewWith(Corotation c) {
		if (c != null) {
			setSpeed(Formatter.toDecimal(c.getSpeedSolarWind()));
			setDeltaSpeed(Formatter.toDecimal(c.getSpeedError()));
			setSpread(Formatter.toDecimal(c.getSpreadCIR()));
			setRotPeriod(Formatter.toDecimal(c.getRotationPeriod()));
			setLongStart(Formatter.toDecimal1D(c.getLongStartT()));
		}
	}

	/**
	 * Update Corotation model from Start fields
	 * @param corotation
	 */
	public void update(Corotation c) {
		c.setSpeedSolarWind(Formatter.toDouble(speed.getValue()));
		c.setSpeedError(Formatter.toDouble(deltaSpeed.getValue()));
		c.setSpreadCIR(Formatter.toDouble(spread.getValue()));
		c.setRotationPeriod(Formatter.toDouble(rotPeriod.getValue()));
		c.setLongStartT(Formatter.toDouble(longStart.getValue()));
	}

	/**
	 * 
	 * Compute Start fields from date 
	 */
	public void compute(Corotation c, Date date) {
		src = ServiceFactory.getPositionService().getPositionElement(startSource.get(), date);
		if (src != null) {
			c.setStartTime(date);
			if (c.startIsSun()) {
				// HAE spheric coordinates of attitude sun at time t
				c.setLongStartT(src.getAttitude()[0]);
				c.setLatStartT(src.getAttitude()[1]);
			} else {
				// HAE spheric coordinates of start at time t
				double[] longLat = CoordConverter.toSpheric(src.getX(), src.getY(), src.getZ());
				c.setLongStartT(longLat[0]);
				c.setLatStartT(longLat[1]);
			}
	
			//log.debug("Computed longStartT, latStartT = " + c.getLongStartT() + ", " + c.getLatStartT());
	
			// Radial distance away SUN of START point.
			double radialDistanceStart = ToolHelper.computeRadialDistance(src);
			c.setRadialDistanceStart(radialDistanceStart);
			//log.debug("radialDistanceStart=" + CoordConverter.toAU(radialDistanceStart) + " AU");
			double radialDistStartXY = ToolHelper.computeRadialDistanceXY(src);
			c.setRadialDistStartXY(radialDistStartXY);
			//log.debug("radialDistXYStart=" + CoordConverter.toAU(radialDistStartXY) + " AU");
			// compute source
			computeSource(c);
		}
	}

	/**
	 * 
	 * Compute Start fields from Carrington source 
	 */
	public void computeFromSource(Corotation corotation) {
		if (corotation.startIsSun()) {
			corotation.setLongStartT(CoordConverter.normalizeLongitude(corotation.getSunAttitudeT()[0] + corotation.getLongSource()));
			corotation.setLatStartT(CoordConverter.normalizeLongitude(corotation.getSunAttitudeT()[1] + corotation.getLatSource()));
			// set the HAE source of the CIR spiral at time tsun
			corotation.setLongSourceT(corotation.getLongStartT());
			corotation.setLatSourceT(corotation.getLatStartT());
		}
	}

	/**
	 * Compute carrington source from start fields and a new date  
	 * @param radial
	 */
	public void computeSource(Corotation corotation, Date date) {
		src = ServiceFactory.getPositionService().getPositionElement(startSource.get(), date);
		if (src != null) {
			// Radial distance away SUN of START point.
			double radialDistanceStart = ToolHelper.computeRadialDistance(src);
			corotation.setRadialDistanceStart(radialDistanceStart);
			//log.debug("radialDistanceStart=" + CoordConverter.toAU(radialDistanceStart) + " AU");
			double radialDistStartXY = ToolHelper.computeRadialDistanceXY(src);
			corotation.setRadialDistStartXY(radialDistStartXY);
			//log.debug("radialDistXYStart=" + CoordConverter.toAU(radialDistStartXY) + " AU");
			// compute source
			computeSource(corotation);
		}
	}

	/**
	 * Compute Carrington source footpoint of the CIR spiral from start fields
	 * Compute also HAE source footpoint longitude of the CIR spiral at time t
	 * @param corotation
	 */
	public void computeSource(Corotation c) {
		// Compute sun time
		computeSunTime(c);
		
		if (c.startIsSun()) {
			// set the Carrington source of the CIR spiral at time tsun
			c.setLongSource(CoordConverter.normalizeLongitude(c.getLongStartT() - c.getSunAttitudeT()[0]));
			c.setLatSource(CoordConverter.normalizeLatitude(c.getLatStartT() - c.getSunAttitudeT()[1]));
			// set the HAE longitude of the CIR spiral footpoint at time t
			c.setLongSourceT(c.getLongStartT());
			c.setLatSourceT(c.getLatStartT());
		}
		else {
			double[] longLat = CoordConverter.rectangularToCarrington(src.getX(), src.getY(), src.getZ(), c.getSunAttitudeT());
			double omega = Math.toDegrees(ToolHelper.getRotationFrequency(c.getRotationPeriod()));
			// compute delta longitude between START and spiral footpoint
			double dPhi = (c.getRadialDistStartXY() * omega) / c.getSpeedSolarWind();
			// set the Carrington source of the CIR spiral at time tsun
			c.setLongSource(CoordConverter.normalizeLongitude(longLat[0] + dPhi));
			c.setLatSource(longLat[1]);
			// set the HAE longitude of the CIR spiral footpoint at time t
			c.setLongSourceT(CoordConverter.normalizeLongitude(c.getLongStartT() + dPhi));
			c.setLatSourceT(CoordConverter.normalizeLongitude(c.getLatStartT()));
		}
	}

	/** 
	 * Compute attitude sun at time t
	 * @param c
	 */
	private void computeSunTime(Corotation c) {
		if (c.startIsSun()) {
			// Sun time = start time => attitude at sun time = attitude at start time
			c.setSunTime(c.getStartTime().getTime());
			// Get attitude sun at tSun
			c.setSunAttitudeT(src.getAttitude());
		}
		else {
			// Compute Sun time
			double initialSeconds = c.getStartTime().getTimeInMillis() / 1000.0;
			double sunSeconds = initialSeconds - (c.getRadialDistanceStart() / c.getSpeedSolarWind());
			Date sunTime = new Date();
			sunTime.setTime((long)sunSeconds * 1000);
			c.setSunTime(sunTime);
			// Get attitude sun at t
			//log.debug("Get position of " + sun.getName() + " at time " + c.getStartTime().getTime());
			sun = (Sun) ServiceFactory.getPositionService().getPositionElement(sun, c.getStartTime().getTime());
			if (sun != null) {
				c.setSunAttitudeT(sun.getAttitude());
			}
		}
	}

	public StringProperty getStartTime() {
		return startTime;
	}
	public void setStartTime(String startTime) {
		this.startTime.set(startTime);
	}
	public StringProperty getSpeed() {
		return speed;
	}
	public void setSpeed(String speed) {
		this.speed.set(speed);
	}
	public StringProperty getDeltaSpeed() {
		return deltaSpeed;
	}
	public void setDeltaSpeed(String deltaSpeed) {
		this.deltaSpeed.set(deltaSpeed);
	}
	public StringProperty getLongStart() {
		return longStart;
	}
	public void setLongStart(String longStart) {
		this.longStart.set(longStart);
	}

	public ObjectProperty<SpaceElement> getStartSource() {
		return startSource;
	}

	public void setStartSource(SpaceElement startSource) {
		this.startSource.set(startSource);
	}

	public StringProperty getSpread() {
		return spread;
	}

	public void setSpread(String spread) {
		this.spread.set(spread);
	}

	public StringProperty getRotPeriod() {
		return rotPeriod;
	}

	public void setRotPeriod(String rotPeriod) {
		this.rotPeriod.set(rotPeriod);
	}

}
