/* ----------------------------------------
 * Origin  : GFI INFORMATIQUE 
 * Project : CDPP Propagation Tool 
 * ----------------------------------------
 * History 
 * Version : 01/05/2015 : SCA : V2.1
 * Creation 
 * Version : 24/03/2016 : SCA : V2.2 (PSWS-H2020)
 * Add comets
 * Version : 06/04/2023 : LBE : V2.7
 * DM-ID : redmine#8642 : 06/04/2023 : Added 3D shockwave
 * Version : 12/09/2023 : LBE : V2.8
 * DM-ID : Redmine#10500 : 12/09/2023 : new END points
 * Version : 19/07/2024 : KKH 
 * DM-ID : Redmine#11685 : 19/07/2024 : Change min/max value color bar
 * DM-ID : Redmine#l0763 : 05/08/2024 : Field lines added
 * Version : V2.13
 * DM-ID : redmine#12279 : 10/09/2025 : LBE : Add field lines in 3d panel
 * FA-ID : redmine#12154 : 16/09/2025 : KHK : Fix bug on SC position
 * ----------------------------------------
 */
package fr.tlse.irap.pt.client.controller.eclipticPlane;

import java.net.URL;
import java.util.Date;
import java.util.ResourceBundle;

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

import fr.tlse.irap.pt.client.component.CustomComponent;
import fr.tlse.irap.pt.client.component.ICustomComponent;
import fr.tlse.irap.pt.client.controller.common.Formatter;
import fr.tlse.irap.pt.client.controller.common.ShockCollection;
import fr.tlse.irap.pt.client.controller.common.SpaceElementCollection;
import fr.tlse.irap.pt.client.controller.dialogbox.DialogBox;
import fr.tlse.irap.pt.client.controller.dialogbox.ProgressDialogBox;
import fr.tlse.irap.pt.client.controller.drawing3d.Drawing3dController;
import fr.tlse.irap.pt.client.controller.drawingPlane.DrawHelper;
import fr.tlse.irap.pt.client.controller.drawingPlane.DrawHelper.ViewType;
import fr.tlse.irap.pt.client.controller.drawingPlane.DrawingPlaneController;
import fr.tlse.irap.pt.client.controller.menu.MenuController;
import fr.tlse.irap.pt.client.controller.searchComets.SearchCometsComponent;
import fr.tlse.irap.pt.client.controller.searchComets.SearchCometsDialogBox;
import fr.tlse.irap.pt.client.controller.timestamp.TimestampController;
import fr.tlse.irap.pt.client.controller.tools.IToolController.Tool;
import fr.tlse.irap.pt.client.controller.tools.jmap.JMapModel;
import fr.tlse.irap.fieldLine.FieldLine;
import fr.tlse.irap.spaceElement.SpaceElement;
import fr.tlse.irap.spaceElement.Sun;
import fr.tlse.irap.tool.radial.CMEType;
import fr.tlse.irap.utils.CoordConverter;
import java.util.List;
import java.util.logging.Level;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Cursor;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Slider;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class EclipticPlaneController extends VBox implements Initializable, IEclipticPlane, ICustomComponent {

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

    private final static double zoomFactorInner = 1.25;
    private final static double zoomFactorOuter = 1.75;

    @FXML
    private EclipticPlaneController rootEclipticPlane;

    @FXML
    protected DrawingPlaneController drawingPlaneComponent;
    @FXML
    protected DrawingPlaneController drawingPlaneComponentXZ;
    @FXML
    protected Drawing3dController drawingPlaneComponent3d;
    @FXML
    protected ScrollPane sPane;
    @FXML
    protected ScrollPane sPaneXZ;
    @FXML
    protected ScrollPane sPane3d;
    @FXML
    protected Label coordsysLabel;
    @FXML
    protected VBox vBox;
    @FXML
    protected HBox buttonsBar;
    @FXML
    protected Button zoomOutBtn;
    @FXML
    protected Button zoomInBtn;
    
    
    /**
     * For 3d scene control
     */
    @FXML
    protected CheckBox viewXzCb;
    @FXML
    protected CheckBox view3dCb;
    @FXML
    private Slider swEventSlider;
    //@FXML
    //protected ComboBox swEventParamCbx;
    @FXML
    private GridPane palette;
    @FXML
    private GridPane palette3d;
    @FXML
    private Label firstBotLabel;
    @FXML
    private Label sndBotLabel;
    @FXML
    private Label trdBotLabel;
    @FXML
    private Label frthBotLabel;
    @FXML
    private Label botLabel;
    @FXML
    private Label firstTopLabel;
    @FXML
    private Label sndTopLabel;
    @FXML
    private Label trdTopLabel;
    @FXML
    private Label frthTopLabel;
    @FXML
    private Label topLabel;

    
    @FXML
    private Label firstBotLabel3d;
    @FXML
    private Label sndBotLabel3d;
    @FXML
    private Label trdBotLabel3d;
    @FXML
    private Label frthBotLabel3d;
    @FXML
    private Label botLabel3d;
    
    protected TimestampController timestampComponent;
    protected MenuController menuComponent;

    Tool tool;
    SpaceElement startSource;
    SpaceElement endSource;
    Date currentDate = new Date(0);
    java.awt.Image awtImage = null;

    public EclipticPlaneController() {
        super();
        CustomComponent.initCustomComponent(this);
    }

    @Override
    public void initialize(URL fxmlFileLocation, ResourceBundle resources) {

        drawingPlaneComponent.initComponent(sPane, ViewType.XY);
        drawingPlaneComponentXZ.initComponent(sPaneXZ, ViewType.XZ);
        drawingPlaneComponent3d.initComponent(sPane3d, this);
        
        //remove 3d components at start
        rootEclipticPlane.getChildren().remove(sPane3d);
        //buttonsBar.getChildren().remove(palette);
        buttonsBar.getChildren().remove(swEventSlider);
        buttonsBar.getChildren().remove(palette3d);

        zoomOutBtn.setOnMouseClicked(new EventHandler<MouseEvent>() {
            public void handle(MouseEvent arg0) {
                zoomOut();
            }
        });

        zoomInBtn.setOnMouseClicked(new EventHandler<MouseEvent>() {
            public void handle(MouseEvent arg0) {
                zoomIn();
            }
        });

        viewXzCb.selectedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                if (newValue) {
                    sPaneXZ.setMinHeight(130);
                } else {
                    sPaneXZ.setMinHeight(0);
                }
                sPaneXZ.setVisible(newValue);
            }
        });
        view3dCb.selectedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                //System.out.println("**** view 3D pane "+newValue);
                if (newValue) {
                    rootEclipticPlane.getChildren().remove(sPane);
                    rootEclipticPlane.getChildren().remove(sPaneXZ);
                    rootEclipticPlane.getChildren().add(0, sPane3d);
                    sPane3d.setVisible(true);
                    buttonsBar.getChildren().remove(zoomInBtn);
                    buttonsBar.getChildren().remove(zoomOutBtn);
                    buttonsBar.getChildren().remove(viewXzCb);
                    buttonsBar.getChildren().remove(palette);
                    buttonsBar.getChildren().add(getSwEventSlider());
                    buttonsBar.getChildren().add(getPalette3d());
                    coordsysLabel.setText("Coordinate system : Carrington");
                    //buttonsBar.getChildren().add(swEventParamCbx);
                    //if(drawingPlaneComponent3d.isDrawingShock()) {
                    //    getSwEventSlider().setVisible(true);
                    //}
                    
                } else {
                    rootEclipticPlane.getChildren().remove(sPane3d);
                    rootEclipticPlane.getChildren().add(0, sPaneXZ);
                    rootEclipticPlane.getChildren().add(0, sPane);
                    
                    buttonsBar.getChildren().remove(getSwEventSlider());
                    buttonsBar.getChildren().remove(getPalette3d());
                    //buttonsBar.getChildren().remove(swEventParamCbx);
                    buttonsBar.getChildren().add(0,viewXzCb);
                    buttonsBar.getChildren().add(0,zoomInBtn);
                    buttonsBar.getChildren().add(0,zoomOutBtn);
                    buttonsBar.getChildren().add(palette);
                    timestampComponent.updateResultDate();
                    coordsysLabel.setText("Coordinate system : HEE");
                }
                //sPane3d.setVisible(newValue);
                //sPane.setVisible(!newValue);
                //sPaneXZ.setVisible(!newValue);
                //palette.setVisible(false);
                
                //showCMEColorMap();
                //viewXzCb.setDisable(newValue);
                //zoomInBtn.setDisable(newValue);
                //zoomOutBtn.setDisable(newValue);
            }
        });
//		sPane.addEventFilter(ScrollEvent.ANY, new EventHandler() {
//			@Override
//			public void handle(Event event) {
//				double dy = ((ScrollEvent)event).getDeltaY();
//				if (dy > 0) {
//					zoomIn();
//				} else if (dy < 0) {
//					zoomOut();
//				}
//			}
//		});

        // update label size
        double fontSize = 13.0; // define font size 
        firstBotLabel3d.setFont(new Font(fontSize));// set to Label
        sndBotLabel3d.setFont(new Font(fontSize));
        trdBotLabel3d.setFont(new Font(fontSize));
        frthBotLabel3d.setFont(new Font(fontSize));
        botLabel3d.setFont(new Font(fontSize));
        coordsysLabel.setFont(new Font(fontSize));
        //view3dCb.setFont(new Font(fontSize));
        
    }

    /**
     * Dynamic component initialization
     */
    public void initComponentWith(final TimestampController timestampComponent, MenuController menuComponent) {
        this.timestampComponent = timestampComponent;
        this.menuComponent = menuComponent;
        drawingPlaneComponent3d.initComponentWith(timestampComponent);
        // Listen to ecliptic date slider pressed change  
        this.timestampComponent.getResultTScrollBar().pressedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> arg0, Boolean oldHasPressed, Boolean hasPressed) {
                if (!hasPressed) {
                    // set result date property from result time => ask ecliptic plane to be refreshed
                    //log.debug("Time slider has released => update result date ");
                    timestampComponent.updateResultDate();
                }
            }
        });
        // Listen to current result date change  
        this.timestampComponent.getResultDateProperty().addListener(new ChangeListener<Date>() {
            @Override
            public void changed(ObservableValue<? extends Date> observableObject, Date oldDate, Date newDate) {
                if (newDate != null) {
                    log.debug("Result date has changed => request positions");
                    currentDate = newDate;
                    requestPositions();
                }
            }
        });
        
//		this.timestampComponent.getResultTScrollBar().valueProperty().addListener(new ChangeListener<Number>() {
//			@Override
// 			public void changed(ObservableValue<? extends Number> arg0, Number oldValue, Number newValue) {
//			}
//		});

        startSource = new Sun();
    }

    /**
     * Init the drawing elements
     *
     * @param currentTool
     */
    public void initDrawingElements(Tool currentTool) {
        tool = currentTool;
        if (tool == Tool.RADIAL) {
            drawingPlaneComponent.setDrawingCME(true);
            drawingPlaneComponent.setDrawingSpiral(false);
            drawingPlaneComponent.setDrawingJMapFOV(true);
            drawingPlaneComponent.spiral.hide();
        } else if (tool == Tool.COROTATION) {
            drawingPlaneComponent.setDrawingCME(false);
            drawingPlaneComponent.setDrawingSpiral(true);
            drawingPlaneComponent.setDrawingJMapFOV(true);
            drawingPlaneComponent.cme.hide();
            hideCMEColorMap();
        } else if (tool == Tool.SEP) {
            drawingPlaneComponent.setDrawingCME(false);
            drawingPlaneComponent.setDrawingSpiral(true);
            drawingPlaneComponent.setDrawingJMapFOV(false);
            drawingPlaneComponent.cme.hide();
            drawingPlaneComponent.jMapFOV.hide();
            hideCMEColorMap();
        } else {
            drawingPlaneComponent.setDrawingCME(false);
            drawingPlaneComponent.setDrawingSpiral(false);
            drawingPlaneComponent.setDrawingJMapFOV(false);
            drawingPlaneComponent.cme.hide();
            drawingPlaneComponent.spiral.hide();
            drawingPlaneComponent.jMapFOV.hide();
            hideCMEColorMap();
        }
        drawingPlaneComponent.loadMenu(this);
        drawingPlaneComponent3d.loadMenu();
    }

    /**
     * Used to refresh quick drawing elements
     */
    public void setCurrentTime(Date pDate) {
        drawingPlaneComponent3d.showGridFieldLine(pDate);
    }
    
    
    /**
     * Update FOV with jMap model
     *
     * @param jMapModel
     */
    public void updateFovWith(JMapModel jMapModel) {
        drawingPlaneComponent.updateFOV(jMapModel);
    }

    /**
     * Update field lines to draw
     * @param pFl field lines
     * @param pSunAtt Sun attitude to convert carrington to ecliptic
     */
    public void updateFieldLinesWith(List<FieldLine> pFl, double[] pSunAtt) {
        drawingPlaneComponent.getFieldlines().setLines(pFl, pSunAtt);
    }
    
    /**
     * Update Grid field lines for drawing outside of carrington map
     * @param pFl field lines
     */
    public void updateGridFieldLinesWith(List<List<FieldLine>> pFl, List<Date> pDate) {
        drawingPlaneComponent3d.setGridFieldLines(pFl, pDate);
        drawingPlaneComponent3d.showGridFieldLine(currentDate);
    }
    
//	public void updateShocks() {
//		drawingPlaneComponent.updateShocks();
//	}
    /**
     * Update ecliptic view
     */
    public void updateView() {
        initScale();
        // init XY view
        drawingPlaneComponent.saveConfig();
        drawingPlaneComponent.resetView();
        drawingPlaneComponent.addSpaceElementNodes();
        drawingPlaneComponent.addSpecificNodes();
        drawingPlaneComponent.restoreConfig();
        //updateImage();
        drawingPlaneComponent.loadMenu(this);
        drawingPlaneComponent3d.loadMenu();
        // Re-Center Ecliptic plane
        sPane.setVvalue(sPane.getVmax() / 2);
        sPane.setHvalue(sPane.getHmax() / 2);
        // init XZ view
        drawingPlaneComponentXZ.saveConfig();
        drawingPlaneComponentXZ.resetView();
        drawingPlaneComponentXZ.addSpaceElementNodes();
        drawingPlaneComponentXZ.restoreConfig();
        // Re-Center Ecliptic plane
        sPaneXZ.setVvalue(sPaneXZ.getVmax() / 2);
        sPaneXZ.setHvalue(sPaneXZ.getHmax() / 2);
        enableDynamicControls();
    }

    /**
     * Reset ecliptic view
     */
    public void resetView() {
        drawingPlaneComponent.resetView();
        drawingPlaneComponentXZ.resetView();
        initScale();
        disableDynamicControls();
    }

    /**
     * Update CME with
     *
     * @param cmeType
     * @param longSource in HAE
     * @param extentCME
     */
    public void updateCmeWith(CMEType cmeType, double longSource, double extentCME) {
        drawingPlaneComponent.updateCmeWith(cmeType, longSource, extentCME);
    }

    /**
     * Update Fix Point CME from radius
     *
     * @param radiusInKm
     * @param t1
     * @param t2
     * @param t3
     */
    public void updateCmeRadius(double radiusInKm, double t1, double t2, double t3) {
        drawingPlaneComponent.updateRadiusCme(radiusInKm, 0.0);
        refreshCMEColorMap(t1, t2, t3);
    }

    /**
     * Update SSE CME from a fix point identify by a radius and a longitude
     *
     * @param radiusInKm
     * @param deltaLongitude
     */
    public void updateCmeRadius(double radiusInKm, double deltaLong) {
        drawingPlaneComponent.updateRadiusCme(radiusInKm, deltaLong);
        hideCMEColorMap();
    }

    /**
     * Draw spiral with
     *
     * @param fptLong : HAE longitude of the spiral footpoint
     * @param rotPeriod
     * @param speed
     * @param spread
     */
    public void drawSpiral(double fptLong, double rotPeriod, double speed, double spread) {
        drawingPlaneComponent.drawSpiralWith(fptLong, rotPeriod, speed, spread);
    }

    /**
     * Update spiral
     *
     * @param fptLong : HAE longitude of the spiral footpoint
     */
    public void updateSpiralWith(double ftpLong) {
        drawingPlaneComponent.drawSpiralWith(ftpLong);
    }

    public void disableDynamicControls() {
        zoomInBtn.setVisible(false);
        zoomOutBtn.setVisible(false);
    }

    public void enableDynamicControls() {
        zoomInBtn.setVisible(true);
        zoomOutBtn.setVisible(true);
    }

    private void zoomIn() {
        if (DrawHelper.getScale() < 100) {
            if (DrawHelper.getScale() > 0.9) {
                zoom(zoomFactorInner);
            } else {
                zoom(zoomFactorOuter);
            }
        }
    }

    private void zoomOut() {
        if (DrawHelper.getScale() > 1.1) {
            zoom(1 / zoomFactorInner);
        } else if (DrawHelper.getScale() > 0.01) {
            zoom(1 / zoomFactorOuter);
        }
        //else stop zoooming out
    }

    private void zoom(double zoomFactor) {
        drawingPlaneComponent.zoom(zoomFactor);
        drawingPlaneComponentXZ.zoom(zoomFactor);
        // update scale
        DrawHelper.setScale(DrawHelper.getScale() * zoomFactor);
        //log.debug("New scale is " + DrawHelper.getScale());

        // Re-Center Ecliptic plane
        sPane.setVvalue(sPane.getVmax() / 2);
        sPane.setHvalue(sPane.getHmax() / 2);
        sPaneXZ.setVvalue(sPaneXZ.getVmax() / 2);
        sPaneXZ.setHvalue(sPaneXZ.getHmax() / 2);
    }

    public void initScale() {
        DrawHelper.setScale(1.0);
    }

    /**
     * *************************************************************
     ********************** Menu actions *************************
	 **************************************************************
     */
    @Override
    public void runShowAllPlanets() {
        if (drawingPlaneComponent.isVisibleAllPlanets()) {
            drawingPlaneComponent.showAllPlanets(false);
            drawingPlaneComponentXZ.showAllPlanets(false);
        } else {
            drawingPlaneComponent.showAllPlanets(true);
            drawingPlaneComponentXZ.showAllPlanets(true);
        }
    }

    @Override
    public void runShowStartEnd() {
        if (!(startSource == null || startSource instanceof Sun)) {
            drawingPlaneComponent.showElement(startSource);
            drawingPlaneComponentXZ.showElement(startSource);
        }
        if (!(endSource == null || endSource instanceof Sun)) {
            drawingPlaneComponent.showElement(endSource);
            drawingPlaneComponentXZ.showElement(endSource);
        }
    }

    @Override
    public void runShowPlanet(SpaceElement spaceElement) {
        drawingPlaneComponent.showElement(spaceElement);
        drawingPlaneComponentXZ.showElement(spaceElement);
    }

    @Override
    public void runShowProbe(SpaceElement spaceElement) {
        drawingPlaneComponent.showElement(spaceElement);
        drawingPlaneComponentXZ.showElement(spaceElement);
    }

    @Override
    public void runShowComet(SpaceElement spaceElement) {
        drawingPlaneComponent.showElement(spaceElement);
        drawingPlaneComponentXZ.showElement(spaceElement);
    }

    @Override
    public void runShowAllProbes() {
        if (drawingPlaneComponent.isVisibleAllProbes()) {
            drawingPlaneComponent.showAllProbes(false);
            drawingPlaneComponentXZ.showAllProbes(false);
        } else {
            drawingPlaneComponent.showAllProbes(true);
            drawingPlaneComponentXZ.showAllProbes(true);
        }
    }

    @Override
    public void runShowAllComets() {
        if (drawingPlaneComponent.isVisibleAllComets()) {
            drawingPlaneComponent.showAllComets(false);
            drawingPlaneComponentXZ.showAllComets(false);
        } else {
            drawingPlaneComponent.showAllComets(true);
            drawingPlaneComponentXZ.showAllComets(true);
        }
    }

//	@Override
//	public void runShowMap(String typeMap) {
//		drawingPlaneComponent.setTypeMap(typeMap);
//		if (typeMap == null) {
//			drawingPlaneComponent.setShowingMap(false);
//		}
//		else {
//			drawingPlaneComponent.setShowingMap(true);
//		}
//		updateImage();
//	}
    @Override
    public void runShowCME() {
        if (drawingPlaneComponent.isDrawingCME()) {
            if (drawingPlaneComponent.cme.isVisible()) {
                drawingPlaneComponent.cme.hide();
                hideCMEColorMap();
            } else {
                drawingPlaneComponent.cme.show();
                showCMEColorMap();
            }
        }
    }

    @Override
    public void runShowSpiral(String item) {
        if (drawingPlaneComponent.isDrawingSpiral()) {
            hideCMEColorMap();
            if (drawingPlaneComponent.getSpiral().isVisible()) {
                drawingPlaneComponent.getSpiral().hide();
            } else {
                drawingPlaneComponent.getSpiral().show();
            }
        }
    }

    @Override
    public void runShowJMapFOV() {
        drawingPlaneComponent.showJMapFOV();
    }

    @Override
    public void runShowFOV(String probeName, String camera) {
        drawingPlaneComponent.showFOV(probeName, camera);
    }

    @Override
    public void runShowAllFOVs(String obs) {
        if (drawingPlaneComponent.isVisibleAllFOVs(obs)) {
            drawingPlaneComponent.showAllFOV(obs, false);
        } else {
            drawingPlaneComponent.showAllFOV(obs, true);
        }
    }

    @Override
    public void runShowShocks() {
        if (drawingPlaneComponent.isVisibleAllShocks()) {
            drawingPlaneComponent.showAllShocks(false);
        } else {
            drawingPlaneComponent.showAllShocks(true);
        }
    }

    @Override
    public void runReset() {
        drawingPlaneComponent.showAllPlanets(true);
        drawingPlaneComponent.showAllComets(false);
        drawingPlaneComponent.resetAllFOVs();
        drawingPlaneComponent.showAllProbes(true);
        drawingPlaneComponent.showAllShocks(false);

        drawingPlaneComponentXZ.showAllPlanets(true);
        drawingPlaneComponentXZ.showAllComets(false);
        drawingPlaneComponentXZ.showAllProbes(true);

        if (zoomInBtn.isVisible()) {
            drawingPlaneComponent.cme.show();
            showCMEColorMap();
            // reset zoom
            if (DrawHelper.getScale() > 1.1) {
                while (DrawHelper.getScale() > 1.1) {
                    zoomOut();
                }
            } else if (DrawHelper.getScale() < 0.9) {
                while (DrawHelper.getScale() < 0.9) {
                    zoomIn();
                }
            }
            // Re-Center Ecliptic plane
            sPane.setVvalue(sPane.getVmax() / 2);
            sPane.setHvalue(sPane.getHmax() / 2);
            sPaneXZ.setVvalue(sPaneXZ.getVmax() / 2);
            sPaneXZ.setHvalue(sPaneXZ.getHmax() / 2);
        }
    }

    private void refreshCMEColorMap(double t1, double t2, double t3) {
        double rAU = CoordConverter.toAU(drawingPlaneComponent.cme.getRadialDistKm());

        sndBotLabel.setText(Formatter.toDecimal1D(rAU / 3));
        trdBotLabel.setText(Formatter.toDecimal1D(2 * rAU / 3));
        frthBotLabel.setText(Formatter.toDecimal1D(rAU));

        sndTopLabel.setText(Formatter.toDecimal0D(t1 / (3600 * 1000)));
        trdTopLabel.setText(Formatter.toDecimal0D(t2 / (3600 * 1000)));
        frthTopLabel.setText(Formatter.toDecimal0D(t3 / (3600 * 1000)));
        
        //showColorMapLabels(2);
        showCMEColorMap();
    }


    /**
     * Show and update colorBar with only one label line
     * @param lMin Min value
     * @param lMax Max value
     * @param pUnit Unit to show at end of colorbar
     */
    public void refreshColorMap3d(double lMin, double lMax, String pUnit) {
        
        firstBotLabel3d.setText(Formatter.toDecimal1D(lMin));
        sndBotLabel3d.setText(Formatter.toDecimal1D(lMin+(lMax-lMin)/3));
        trdBotLabel3d.setText(Formatter.toDecimal1D(lMin+2*(lMax-lMin)/3));
        frthBotLabel3d.setText(Formatter.toDecimal1D(lMax));
        botLabel3d.setText(pUnit);       
        //showColorMapLabels(1);
        //showCMEColorMap();
    }
    
//    /**
//     * if pNb = 1, only show bottom label
//     * if 2, show top and bottom label
//     * @param lNb 
//     */
//    private void showColorMapLabels(int lNb) {
//        firstTopLabel.setVisible(lNb==2);
//        sndTopLabel.setVisible(lNb==2);
//        trdTopLabel.setVisible(lNb==2);
//        frthTopLabel.setVisible(lNb==2);
//        topLabel.setVisible(lNb==2);
////        firstBotLabel.setVisible(lNb==2);
////        sndBotLabel.setVisible(lNb==2);
////        trdBotLabel.setVisible(lNb==2);
////        frthBotLabel.setVisible(lNb==2);
//    }
    
    
    private void showCMEColorMap() {
        if (drawingPlaneComponent.isDrawingCME() && !view3dCb.isSelected()) {
            palette.setVisible(true);
        }
//        if(drawingPlaneComponent3d.isDrawingShock() && view3dCb.isSelected()) {
//            palette3d.setVisible(true);
//        }
    }

    private void hideCMEColorMap() {
        palette.setVisible(false);
    }

    /**
     * Request the positions of the space element according to new result date within detached thread and update the
     * ecliptic plane
     */
    protected void requestPositions() {
        final Task<Object> requestPositionsWorker;
        requestPositionsWorker = requestPositionsWorker();

        requestPositionsWorker.stateProperty().addListener(new ChangeListener<Worker.State>() {
            @Override
            public void changed(ObservableValue<? extends Worker.State> observableValue, Worker.State oldState, Worker.State newState) {
                if (newState == Worker.State.SUCCEEDED) {
                    
                    // 12154
                    // when changing "START" field PT update:
                    // - computing Radial 
                    // - update View  jMap
                    // - update Ecliptic plane 
                    // Waiting JMapPosition updating "START" probes positions
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ex) {
                        java.util.logging.Logger.getLogger(EclipticPlaneController.class.getName()).log(Level.SEVERE, null, ex);
                    }                   
                    
                    // update Ecliptic plane
                    SpaceElementCollection.updatePositions(currentDate);
                    endCursor();
                    updateView();

                } else if (newState == Worker.State.FAILED || newState == Worker.State.CANCELLED) {
                    // thread is failed or cancelled
                    endCursor();
                    DialogBox.warn(" Error while requesting positions. \n Make sure that server is running ! ");
                    log.warn("Error while requesting positions. " + requestPositionsWorker.getException().getMessage());
                }
            }
        });

        new Thread(requestPositionsWorker).start();
        this.waitCursor();
    }

    private Task<Object> requestPositionsWorker() {
        return new Task<Object>() {
            @Override
            protected Object call() throws Exception {
                Date startDate = timestampComponent.selectedDateProperty().getValue();
                // request space elements at currentDate
                SpaceElementCollection.getPositions(currentDate, startDate);
                // request shocks between current start date and start date + 30 days
                ShockCollection.requestShocks(SpaceElementCollection.getCurrentStartDate());
                return true;
            }
        };
    }

    /**
     * Open search comets parameter screen
     */
    @Override
    public void searchComets() {
        Date startDate = timestampComponent.selectedDateProperty().getValue();
        SearchCometsDialogBox.show(startDate);

        final SearchCometsComponent scc = SearchCometsDialogBox.getSearchCometsComponent();

        scc.okBtn.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent e) {
                if (scc.checkValues()) {
                    log.debug("Search comets between " + scc.getStartDate() + " and " + scc.getEndDate());
                    searchComets(scc.getStartSource(), scc.getDistance(), scc.getStartDate(), scc.getEndDate());
                    scc.close();
                }
            }
        });
    }

    /**
     * Search the positions of the comets according to new result date within detached thread and update the ecliptic
     * plane
     *
     * @param radius
     */
    public void searchComets(final SpaceElement startSource, final long distance, final Date tStart, final Date tEnd) {
        final Task<Object> searchCometsWorker;
        searchCometsWorker = searchCometsWorker(startSource, distance, tStart, tEnd);

        searchCometsWorker.stateProperty().addListener(new ChangeListener<Worker.State>() {
            @Override
            public void changed(ObservableValue<? extends Worker.State> observableValue, Worker.State oldState, Worker.State newState) {
                if (newState == Worker.State.SUCCEEDED) {
                    // update current comets position
                    SpaceElementCollection.updateCometsPositions(currentDate);
                    endCursor();
                    ProgressDialogBox.hide();
                    if (SpaceElementCollection.getComets().size() == SpaceElementCollection.COMETS_NB_MAX) {
                        DialogBox.info("More than " + SpaceElementCollection.COMETS_NB_MAX + " comets have been found. Only the first " + SpaceElementCollection.COMETS_NB_MAX + " comets will be displayed");
                    } else {
                        DialogBox.info("" + SpaceElementCollection.getComets().size() + " comets have been found.");
                    }
                    // update Ecliptic plane
                    updateView();

                } else if (newState == Worker.State.FAILED || newState == Worker.State.CANCELLED) {
                    // thread is failed or cancelled
                    endCursor();
                    ProgressDialogBox.hide();
                    DialogBox.error(" Error while searching comets. \n Make sure that server is running ! ");
                    log.error("Error while searching comets. " + searchCometsWorker.getException().getMessage());
                }
            }
        });

        new Thread(searchCometsWorker).start();
        ProgressDialogBox.show("Searching comets ...");
        this.waitCursor();
    }

    private Task<Object> searchCometsWorker(final SpaceElement startSource, final long distance, final Date tStart, final Date tEnd) {
        return new Task<Object>() {
            @Override
            protected Object call() throws Exception {
                SpaceElementCollection.getAvailableComets(startSource, distance, tStart, tEnd);
                SpaceElementCollection.getCometsPositions(tStart);
                return true;
            }
        };
    }

//    public void updateImage() {
//    	final Task<Object> updateImageWorker = this.updateImageWorker();
//    	updateImageWorker.stateProperty().addListener(new ChangeListener<Worker.State>() {
//            @Override
//            public void changed(ObservableValue<? extends Worker.State> observableValue, Worker.State oldState, Worker.State newState) {
//
//                if (newState == Worker.State.SUCCEEDED) {
//                    // thread is done with success
//	       	    	endCursor();
//	       	    	// update view
//	       	    	drawingPlaneComponent.setImage(awtImage);
//
//                } else if (newState == Worker.State.FAILED || newState == Worker.State.CANCELLED) {
//                    // thread is aborted
//	       	    	endCursor();
//                    //DialogBox.show("Image not available !");
//	       	    	log.info("Image not available !");
//	       	    	// update view
//	       	    	drawingPlaneComponent.setImage(null);
//                }
//            }
//        });
//        new Thread(updateImageWorker).start();
//        waitCursor();
//    }
//
//    private Task<Object> updateImageWorker() {
//        return new Task<Object>() {
//            @Override
//            protected Object call() {
//            	awtImage = null;
//            	if (drawingPlaneComponent.isShowingMap()) {
//	        	    // Call the webservice to download images
//	        		//awtImage = ServiceFactoryImpl.getEclipticMapService().getEclipticImage(currentDate, drawingPlaneComponent.getTypeMap());
//	                //awtImage = SwingFXUtils.fromFXImage(new Image("images/mvp_enlil_2055.gif"), null);
//	                awtImage = SwingFXUtils.fromFXImage(new Image("images/logo_cnrs.gif"), null);
//            	}
//        	    return true;
//            }
//        };
//    }
    private void waitCursor() {
        sPane.setDisable(true);
        sPaneXZ.setDisable(true);
        timestampComponent.setDisable(true);
        rootEclipticPlane.setCursor(Cursor.WAIT);
    }

    private void endCursor() {
        sPane.setDisable(false);
        sPaneXZ.setDisable(false);
        timestampComponent.setDisable(false);
        menuComponent.setDisable(false);
        rootEclipticPlane.setCursor(null);
    }

    public void setStartSource(SpaceElement startElement) {
        if (!startSource.getName().equals(startElement.getName())) {
            log.debug("Source has changed => request positions");
            startSource = startElement;
            requestPositions();
        } else {
            startSource = startElement;
        }
    }

    public void setEndSource(SpaceElement endElement) {
        endSource = endElement;
    }

    public Tool getTool() {
        return tool;
    }

    public void setTool(Tool tool) {
        this.tool = tool;
    }

    /**
     * @return the swEventSlider
     */
    public Slider getSwEventSlider() {
        return swEventSlider;
    }

    /**
     * @return the palette3d
     */
    public GridPane getPalette3d() {
        return palette3d;
    }

    
    
    
//    @FXML
    public void displayMinMaxWindow() {
        try {
            FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MinMaxComponent.fxml"));
            Parent root = fxmlLoader.load();
            MinMaxComponentController minMaxController = fxmlLoader.getController();
            
            //init min max value          
            int lDataType = drawingPlaneComponent3d.getDataTypeNo();
            minMaxController.setMinField(drawingPlaneComponent3d.getTminColorBar(lDataType));
            minMaxController.setMaxField(drawingPlaneComponent3d.getTmaxColorBar(lDataType));
            
            
            String lMsg = "Change Min / Max value of the " + drawingPlaneComponent3d.gettDataTypeName(lDataType) +  " color bar";
            minMaxController.setLblMsg(lMsg );
            
            Stage stage = new Stage();
            stage.setTitle(drawingPlaneComponent3d.gettDataTypeName(lDataType) + " Color bar");
            stage.setScene(new Scene(root));
            stage.showAndWait();
         
            if (minMaxController.isValidated()) {
                Double minValue = minMaxController.getMinValue();
                Double maxValue = minMaxController.getMaxValue();
                // set min/max color bar for given data type
                drawingPlaneComponent3d.setTminColorBar(lDataType, minValue);
                drawingPlaneComponent3d.setTmaxColorBar(lDataType, maxValue);
                
                drawingPlaneComponent3d.buildShockwavesShapes();
                
                minMaxController.setMinField(minValue);
                minMaxController.setMaxField(maxValue);

                
            }else{
                //System.out.println("Saisie annulée.");
            }
   
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
