/* ----------------------------------------
 * Origin  : GFI INFORMATIQUE 
 * Project : CDPP Propagation Tool 
 * ----------------------------------------
 * History 
 * Version : 01/05/2015 : SCA : V2.1
 * Version : 19/09/2016 : SCA : V2.2 (PSWS-H2020)
 *  Add Z axis in propagation computation 
 *  Move Radial End computation on server side (WS)  
 * Version : 17/10/2018 : SCA : V2.2.5
 *  Redmine #6119 
 * ----------------------------------------
 */
package fr.tlse.irap.tool.radial;

import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import fr.tlse.irap.spaceElement.SpaceElement;
import fr.tlse.irap.spaceElement.Sun;

/**
 * All input information useful for the RADIAL tool 
 */
public class Radial implements Serializable {

	private static final long serialVersionUID = 1L;
	private static double DEFAULT_SPEED = 500.0;
	
	private DragModel innerDragModel = new DragModel(10, 3); // 10 day, 3 minute 
	private DragModel outerDragModel = new DragModel(200, 30);// 200 days, 30 minutes

	private boolean inSitu = true;	// JMap inSitu (true/false)
	private String obs; 			// JMap observer 
	private CMEType cmeType = CMEType.FIXED_POINT;
	private boolean linkcatMode = false;
	
	/* START parameters */
	private Calendar sunTime;
	private Calendar startTime;		 	 
	private SpaceElement startElement;	
	private SpaceElement endElement;
//	private Double timeError = 0.0; 			// error in time t, expressed in hours
	private Double speedSolarWind = DEFAULT_SPEED; 		// speed at time t at START point, expressed in km/s
	private Double speedError = 0.0; 			// error in speed, expressed in km/s
	private boolean dragModel; 					// Drag model (True/False)
	private Double innerBoundary = 3.0; 		// Initial Radial Distance for Drag mode, expressed in Rs
	private Double asymptoticSpeed = DEFAULT_SPEED; 	// Asymptotic Solar Wind Speed, expressed in km/s
	private Double dragParam = 0.0; 			// Drag parameter input, expressed in 10^-7 /km
	private Double extentCME = 45.0;

	/* Position information at time t */
	private double[] sunAttitudeTSun= new double[2];	// HAE longitude of CARRINGTON meridian 0 at time tSun, expressed in degrees 
	private Double radialDistanceStart;		// radial distance at time t of START point, expressed in km
	private Double longStartT;				// HAE longitude of START at time t, expressed in degrees
	private Double latStartT;				// HAE latitude of START at time t, expressed in degrees

	/* Position information at time tSun */
	private double longSource;				// CARRINGTON longitude of CME, expressed in degrees [0,360[
	private double latSource;				// CARRINGTON latitude of CME, expressed in degrees [0,360[

	public Radial() {
		this.startTime = new GregorianCalendar();
		this.startTime.set(GregorianCalendar.MILLISECOND, 0);
		this.sunTime = new GregorianCalendar();
		this.sunTime.set(GregorianCalendar.MILLISECOND, 0);
	}

	/**
	 * Compute RadialDragModel for inner and outer space objects
	 */
	public void computeDrag() {
		if (isDragModel()) {
			//log.debug("==============> Compute drag mode");
			innerDragModel.compute(speedSolarWind, extentCME, innerBoundary, asymptoticSpeed, dragParam);
			outerDragModel.compute(speedSolarWind, extentCME, innerBoundary, asymptoticSpeed, dragParam);
			// update computed Drag param
			dragParam = innerDragModel.getDragParam();
			//log.debug("==============> Drag param computed = " + dragParam);
		}
	}

	/**
	 * Get propagating time using drag model
	 * @param radius
	 * @return propagating time from sun
	 */
	public long getDragTime(double radius) {
		long time = innerDragModel.getDragTime(radius);
		if (time < 0) {
			time = outerDragModel.getDragTime(radius);
			if (time < 0) {
				time = outerDragModel.getDragTimeOver(radius);
			}
		}
		return time*1000;
	}

	/**
	 * Get radius of drag model
	 * @param time : time from start time 
	 * @return
	 */
	public double getDragRadius(double time) {
		return innerDragModel.getRadius((long)(time/1000));
	}

	/**
	 * Get speed of drag model
	 * @param time : time from start time 
	 * @return
	 */
	public double getDragSpeed(double time) {
		return innerDragModel.getSpeed((long)(time/1000));
	}

	public Calendar getStartTime() {
		return startTime;
	}

	public void setStartTime(Calendar cal) {
		this.startTime = cal;
	}

	public void setStartTime(Date d) {
		this.startTime.setTime(d);
	}

//	public Double getTimeError() {
//		return timeError;
//	}
//
//	public void setTimeError(Double timeError) {
//		this.timeError = timeError;
//	}

	public Double getSpeedError() {
		return speedError;
	}

	public void setSpeedError(Double speedError) {
		this.speedError = speedError;
	}

	public Double getRadialDistanceStart() {
		return radialDistanceStart;
	}

	public void setRadialDistanceStart(Double radialDistanceStart) {
		this.radialDistanceStart = radialDistanceStart;
	}

	public Calendar getSunTime() {
		return sunTime;
	}

	public void setSunTime(Calendar cal) {
		this.sunTime = cal;
	}

	public void setSunTime(Date d) {
		this.sunTime.setTime(d);
	}

	public double getLongSource() {
		return longSource;
	}

	public void setLongSource(double longSource) {
		this.longSource = longSource;
	}

	public Double getLatSource() {
		return latSource;
	}

	public void setLatSource(Double latSource) {
		this.latSource = latSource;
	}

	public SpaceElement getStartElement() {
		return startElement;
	}

	public void setStartElement(SpaceElement startElement) {
		this.startElement = startElement;
	}

	public SpaceElement getEndElement() {
		return endElement;
	}

	public void setEndElement(SpaceElement endElement) {
		this.endElement = endElement;
	}

	public Double getSpeedSolarWind() {
		return speedSolarWind;
	}

	public void setSpeedSolarWind(Double speedSolarWind) {
		this.speedSolarWind = speedSolarWind;
	}

	public boolean startIsSun() {
		return startElement != null ? startElement instanceof Sun : false;		
	}

	public Double getExtentCME() {
		return extentCME;
	}

	public void setExtentCME(Double extentCME) {
		this.extentCME = extentCME;
	}

	public double[] getSunAttitudeTSun() {
		return sunAttitudeTSun;
	}

	public void setSunAttitudeTSun(double[] sunAttitudeTSun) {
		this.sunAttitudeTSun = sunAttitudeTSun;
	}

	public Double getLongStartT() {
		return longStartT;
	}

	public void setLongStartT(Double longStartT) {
		this.longStartT = longStartT;
	}
	
	public Double getDragParam() {
		return dragParam;
	}

	public void setDragParam(Double dragParam) {
		this.dragParam = dragParam;
	}

	public Double getComputedDragParam() {
		return innerDragModel.getDragParam();
	}

	public Double getAsymptoticSpeed() {
		return asymptoticSpeed;
	}

	public void setAsymptoticSpeed(Double asymptoticSpeed) {
		this.asymptoticSpeed = asymptoticSpeed;
	}

	public Double getInnerBoundary() {
		return innerBoundary;
	}

	public void setInnerBoundary(Double innerBoundary) {
		this.innerBoundary = innerBoundary;
	}

	public boolean isDragModel() {
		return dragModel;
	}

	public void setDragModel(boolean dragModel) {
		this.dragModel = dragModel;
	}

	public DragModel getInnerDragModel() {
		return innerDragModel;
	}
	
	public void setInnerDragModel(DragModel dragModel) {
		this.innerDragModel = dragModel;
	}

	public DragModel getOuterDragModel() {
		return outerDragModel;
	}
	
	public void setOuterDragModel(DragModel dragModel) {
		this.outerDragModel = dragModel;
	}

	public boolean isInSitu() {
		return inSitu;
	}

	public void setInSitu(boolean inSitu) {
		this.inSitu = inSitu;
	}

	public CMEType getCmeType() {
		return cmeType;
	}

	public void setCmeType(CMEType cmeType) {
		this.cmeType = cmeType;
	}

	public Double getLatStartT() {
		return latStartT;
	}

	public void setLatStartT(Double latStartT) {
		this.latStartT = latStartT;
	}

	public static double getDEFAULT_SPEED() {
		return DEFAULT_SPEED;
	}

	public boolean isLinkcatMode() {
		return linkcatMode;
	}

	public void setLinkcatMode(boolean linkcatMode) {
		this.linkcatMode = linkcatMode;
	}

	public String getObs() {
		return obs;
	}

	public void setObs(String obs) {
		this.obs = obs;
	}
}
