/* ----------------------------------------
 * Origin  : GFI INFORMATIQUE 
 * Project : CDPP Propagation Tool 
 * ----------------------------------------
 * History 
 * Version : 01/05/2015 : SCA : V2.1
 * Version : 06/11/2017 : SCA : V2.2.1 
 *  Redmine #5403 - DMPT3 
 * ----------------------------------------
 */
package fr.tlse.irap.pt.client.controller.tools.carrington;

import java.text.ParseException;
import java.util.Date;
import java.util.GregorianCalendar;

import fr.tlse.irap.pt.client.controller.common.Formatter;
import fr.tlse.irap.map.CarringtonMapCatalog;
import fr.tlse.irap.map.CarringtonMapType;
import fr.tlse.irap.pt.client.services.ServiceFactory;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.scene.image.Image;

public class CarringtonModel {

	// dynamic properties
	private StringProperty startLabel = new SimpleStringProperty();
	private ObjectProperty<Image> carringtonImg = new SimpleObjectProperty<Image>();
	private StringProperty rotationNumber = new SimpleStringProperty();
	private StringProperty measurement = new SimpleStringProperty();
	private StringProperty altitude = new SimpleStringProperty();
	private StringProperty observer = new SimpleStringProperty();
	private StringProperty instrument = new SimpleStringProperty();

	private ChangeListener<String> altitudeChange; // altitude property change listener 

	private static MTreeNode treeCMaps;
	private static CarringtonMapCatalog cMapCatalog; 
	
	public static MTreeNode getTreeCMaps() {
		
		if (treeCMaps == null) {
			treeCMaps = new MTreeNode("Carrington map");
		
			cMapCatalog = ServiceFactory.getCarringtonMapService().getCarringtonMapCatalog();
			
			for (CarringtonMapType cMapType : cMapCatalog.getCatalog()) {
				MTreeNode obsNode = treeCMaps.getChild(cMapType.getProbe());
				if (obsNode == null) {
					// create node
					obsNode = new MTreeNode();
					obsNode.setName(cMapType.getProbe());
					obsNode.setDesc(obsNode.getName());
					obsNode.setParent(treeCMaps);
					treeCMaps.getChildren().add(obsNode);
				}
				MTreeNode instNode = obsNode.getChild(cMapType.getInstrument());
				if (instNode == null) {
					// create node
					instNode = new MTreeNode();
					instNode.setName(cMapType.getInstrument());
					instNode.setDesc(instNode.getName());
					instNode.setParent(obsNode);
					obsNode.getChildren().add(instNode);
				}
				MTreeNode measureNode = instNode.getChild(cMapType.getMeasurement());
				if (measureNode == null) {
					// create node
					measureNode = new MTreeNode();
					measureNode.setName(cMapType.getMeasurement());
					measureNode.setDesc(measureNode.getName());
					measureNode.setParent(instNode);
					instNode.getChildren().add(measureNode);
				}
				for (String rd : cMapType.getRadialDistances()) {
					MTreeNode rdNode = measureNode.getChild(rd);
					if (rdNode == null) {
						// create node
						rdNode = new MTreeNode();
						rdNode.setName(rd);
						rdNode.setDesc(rd + " Rsun");
						rdNode.setParent(measureNode);
						measureNode.getChildren().add(rdNode);
					}
				}
			}
		}
		return treeCMaps;
	}

	/**
	 * Reset default values
	 */
	public void reset(){
		reset(GregorianCalendar.getInstance().getTime());
	}

	/**
	 * Reset default values. Default Carrington map is : 
	 * <li>SOHO/MDI/ML if date is before 2010-04-22T05:53:04 (begin of CR2096).
	 * <li>SDO/MDI/ML else
	 */
	public void reset(Date date) {
		// default values
		if (treeCMaps != null) {
			try {
				// Split date defines limit before CR2096 (SOHO/MDI/ML) and after CR2095 (SDO/HMI/ML)  
				Date splitDate = Formatter.getSdf().parse("2010-04-22T05:53:04");
				int index = date.before(splitDate) ? 1 : 0;
				MTreeNode obs = treeCMaps.getChildren().get(index);
				setObserver(obs.getName());
				MTreeNode instr = obs.getChildren().get(0);
				setInstrument(instr.getName());
				setMeasurement(instr.getChildren().get(0).getName());

			} catch (ParseException e) {
				e.printStackTrace();
			}
		}
		setAltitude("");
		setRotationNumber("");
		
	}

	/**
	 * Set up model view with cmType  
	 */
	public void setUpView(CarringtonMapType cmType) {
		this.setObserver(cmType.getProbe());
		this.setInstrument(cmType.getInstrument());
		this.setMeasurement(cmType.getMeasurement());
		if (cmType.getRadialDistances().size() > 0) {
			this.setAltitude(cmType.getRadialDistances().get(0));
		}
		else {
			this.setAltitude("");
		}
	}

	/**
	 * Update cmType model from view  
	 */
	public void update(CarringtonMapType cmType) {
		cmType.setProbe(this.observer.get());
		cmType.setMeasurement(this.measurement.get());
		cmType.setInstrument(this.instrument.get());
		cmType.getRadialDistances().clear();
		String rd0 = this.altitude.get();
		if (!rd0.isEmpty()) {
			cmType.getRadialDistances().add(rd0);
		}
	}

	public ObjectProperty<Image> getCarringtonImg() {
		return carringtonImg;
	}

	public void setCarringtonImg(Image carringtonImg) {
		this.carringtonImg.set(carringtonImg);
	}

	public StringProperty getRotationNumber() {
		return rotationNumber;
	}

	public void setRotationNumber(String rotationNumber) {
		this.rotationNumber.set(rotationNumber);
	}

	public StringProperty getMeasurement() {
		return measurement;
	}

	public void setMeasurement(String measurement) {
		this.measurement.set(measurement);
	}

	public StringProperty getObserver() {
		return observer;
	}

	public void setObserver(String observer) {
		this.observer.set(observer);
	}

	public StringProperty getStartLabel() {
		return startLabel;
	}

	public void setStartLabel(String startLabel) {
		this.startLabel.set(startLabel);
	}

	public StringProperty getAltitude() {
		return altitude;
	}

	public void setAltitude(String altitude) {
		this.altitude.set(altitude);
	}

	public StringProperty getInstrument() {
		return instrument;
	}

	public void setInstrument(String instrument) {
		this.instrument.set(instrument);
	}

	public void setAltitudeChange(ChangeListener<String> altitudeChange) {
		this.altitudeChange = altitudeChange;
	}

	public ChangeListener<String> getAltitudeChange() {
		return altitudeChange;
	}

}
