/* ----------------------------------------
 * 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)
 *  Set a default J-map image if not exists
 * ----------------------------------------
 */
package fr.tlse.irap.pt.client.controller.tools.jmap;

import java.util.Date;

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.RootController;
import fr.tlse.irap.pt.client.controller.common.FilterKeyEvent;
import fr.tlse.irap.pt.client.controller.common.Formatter;
import fr.tlse.irap.pt.client.controller.common.SpaceElementCollection;
import fr.tlse.irap.pt.client.controller.common.Style;
import fr.tlse.irap.pt.client.controller.common.constant.TOOLTIP;
import fr.tlse.irap.pt.client.controller.dialogbox.DialogBox;
import fr.tlse.irap.pt.client.controller.eclipticPlane.EclipticPlaneController;
import fr.tlse.irap.pt.client.controller.tools.IToolController.JMapTool;
import fr.tlse.irap.pt.client.controller.tools.IToolController.Tool;
import fr.tlse.irap.pt.client.controller.tools.fitParameter.FitParameterComponent;
import fr.tlse.irap.fit.Fit;
import fr.tlse.irap.fit.FitCatalog;
import fr.tlse.irap.map.JMap;
import fr.tlse.irap.pt.client.services.ServiceFactory;
import fr.tlse.irap.spaceElement.Probe;
import fr.tlse.irap.spaceElement.SpaceElement;
import fr.tlse.irap.spaceElement.Sun;
import fr.tlse.irap.tool.radial.CMEType;
import fr.tlse.irap.tool.radial.Radial;
import fr.tlse.irap.tool.radial.RadialEnd;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.fxml.FXML;
import javafx.scene.Cursor;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;

public class JMapRadialComponent extends AnchorPane implements IJMapMenu, ICustomComponent {

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

    @FXML
    protected GridPane gridPane;
    @FXML
    protected JMapComponent jMapComponent;
    @FXML
    protected TextField cmeType;
    @FXML
    protected TextField speed;
    @FXML
    protected TextField extent;
    @FXML
    protected TextField beta;
    @FXML
    protected TextField southPa;
    @FXML
    protected TextField northPa;
    @FXML
    protected TextField centralPa;
    @FXML
    protected Label paLabel;
    @FXML
    protected Label southPaLabel;
    @FXML
    protected Label northPaLabel;
    @FXML
    protected Label centralPaLabel;

    private BooleanProperty hasChanged = new SimpleBooleanProperty();
    private BooleanProperty hasFieldChanged = new SimpleBooleanProperty();
    private ObjectProperty<Date> currentDate;
    private Tab fitResultTab;

    private JMapRadialModel jMapRadialModel = new JMapRadialModel();
    private JMapModel jMapModel;
    private JMapPosition jMapPosition;
    private JMapCompute jMapCompute;

    private JMapWorker worker = new JMapWorker();

    private FitParameterComponent fitParameterComponent;
    private EclipticPlaneController eclipticPlaneComponent;

    public JMapRadialComponent() {
        super();
        CustomComponent.initCustomComponent(this);

        jMapCompute = jMapRadialModel.jMapCompute;
        jMapPosition = jMapCompute.jMapPosition;
        jMapModel = jMapComponent.jMapModel;

        Sun sun = new Sun();
        jMapComponent.setStartSource(sun);
        jMapPosition.setStartSource(sun);

        // Create tooltips
        beta.setTooltip(new Tooltip(TOOLTIP.JMAP_BETA));
        extent.setTooltip(new Tooltip(TOOLTIP.CME_EXTENT));
        speed.setTooltip(new Tooltip(TOOLTIP.SPEED));

        jMapRadialModel.getSpeed().bindBidirectional(speed.textProperty());
        jMapRadialModel.getExtent().bindBidirectional(extent.textProperty());
        jMapRadialModel.getBeta().bindBidirectional(beta.textProperty());
        jMapRadialModel.getCentralPa().bindBidirectional(centralPa.textProperty());
        jMapRadialModel.getSouthPa().bindBidirectional(southPa.textProperty());
        jMapRadialModel.getNorthPa().bindBidirectional(northPa.textProperty());
        jMapRadialModel.getCmeType().bindBidirectional(cmeType.textProperty());

        beta.addEventFilter(KeyEvent.ANY, new FilterKeyEvent(beta, 0, 359, Formatter.getFormatter(), hasFieldChanged, beta.focusedProperty()));

        hasFieldChanged.addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                if (!newValue) {
                    // update from view
                    jMapRadialModel.update();
                    // Notify change
                    getHasChanged().set(true);
                    getHasChanged().set(false);
                }
            }
        });

        // Listen to the change of JMapComponent
        jMapComponent.getHasChanged().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observedBoolean, Boolean oldValue, Boolean newValue) {
                if (newValue) {
                    if (jMapRadialModel.getJMapTool().equals(JMapTool.CLICK)) {
                        // compute fit from click points
                        computeClick();
                    } else if (jMapRadialModel.getJMapTool().equals(JMapTool.FIT)) {
                        // set selected fit from catalog
                        setFitFromCatalog();
                    }
                }
            }
        });

    }

    /**
     * @param eclipticPlaneComponent
     * @param selectedDate
     * @param jMapTool
     */
    public void initComponentWith(EclipticPlaneController eclipticPlaneComponent, ObjectProperty<Date> selectedDate) {
        if (this.currentDate == null) {
            this.eclipticPlaneComponent = eclipticPlaneComponent;
            // bind jmap current date to the selected start date
            currentDate = selectedDate;
            // listen for start date change
            currentDate.addListener(new InvalidationListener() {
                public void invalidated(Observable observable) {
                    // clear positions of all observers and sources
                    if (jMapPosition.isBindStartDate()) {
                        jMapPosition.setDates(currentDate.get());
                        worker.updateImage();
                    } else {
                        jMapPosition.bindStartDate();
                    }
                }
            });
            // setting initialization
            final IJMapMenu jMapMenu = this;
            jMapPosition.setDates(currentDate.get());
            jMapComponent.initComponent(jMapPosition);
            jMapComponent.initMenu(jMapMenu, jMapRadialModel.getJMapTool(), Tool.RADIAL);
            SpaceElementCollection.getHasChanged().addListener(new ChangeListener<Boolean>() {
                @Override
                public void changed(ObservableValue<? extends Boolean> observedBoolean, Boolean oldValue, Boolean newValue) {
                    if (!newValue) {
                        jMapComponent.initMenu(jMapMenu, jMapRadialModel.getJMapTool(), Tool.RADIAL);
                    }
                }
            });
            jMapModel.reset();
            worker.updateImage();
        }
    }

    /**
     *
     * @param startSourceProperty
     */
    public void setStartSource(ObjectProperty<SpaceElement> startSourceProperty) {
        jMapComponent.setStartSource(startSourceProperty.get());
        jMapPosition.setStartSource(startSourceProperty.get());
        // bind start property change
        startSourceProperty.addListener(new ChangeListener<SpaceElement>() {
            @Override
            public void changed(ObservableValue<? extends SpaceElement> observable, SpaceElement oldValue, SpaceElement newValue) {
                jMapComponent.setStartSource(newValue);
                jMapPosition.setStartSource(newValue);
                // set beta edit mode 
                Style.setEditMode(beta, jMapRadialModel.getJMapTool() == JMapTool.INSITU ? jMapPosition.getStartSource().getClass().equals(Sun.class) : false);
            }
        });
        Style.setEditMode(beta, jMapRadialModel.getJMapTool() == JMapTool.INSITU ? jMapPosition.getStartSource().getClass().equals(Sun.class) : false);
    }

    /**
     * configure component according to jMapTool
     *
     * @param jMapTool
     */
    public void setJMapTool(JMapTool jMapTool) {

        jMapCompute.setLinkcatMode(false);
        jMapCompute.setCmeType(CMEType.FIXED_POINT);
        jMapRadialModel.setJMapTool(jMapTool);
        jMapComponent.setJMapTool(jMapTool, Tool.RADIAL);
        // set beta edit mode 
        Style.setEditMode(beta, jMapTool == JMapTool.INSITU ? jMapPosition.getStartSource().getClass().equals(Sun.class) : false);
        // set pa visible mode 
        setVisiblePA(jMapTool == JMapTool.FIT);
        // update jmap header view 
        jMapModel.updateView(null);

        if (fitParameterComponent != null) {
            fitParameterComponent.reset();
        }
        // Launch automatic compute 
        if (jMapRadialModel.getJMapTool() == JMapTool.INSITU) {
            computeInSitu();
        } else if (jMapRadialModel.getJMapTool() == JMapTool.FIT) {
            computeCatalog();
        }
    }

    /**
     * configure fit result tab
     *
     * @param fitResultTab
     */
    public void setFitResultTab(Tab fitResultTab) {
        this.fitResultTab = fitResultTab;
        if (jMapRadialModel.getJMapTool() == JMapTool.CLICK) {
            fitResultTab.setDisable(false);
        } else {
            fitResultTab.setDisable(false);
            fitResultTab.setDisable(true);
        }
    }

    /**
     * Update Radial model from JMapRadialModel
     */
    public void updateRadial(Radial radial) {
        jMapRadialModel.updateRadial(radial);
    }

    /**
     * Update view from Radial
     *
     * @param radial
     */
    public void updateView(Radial radial) {
        //log.debug("Update view from Radial :");
        //log.debug("===> update JMap Sun Time from radial : " + radial.getSunTime().getTime());
        jMapRadialModel.updateViewFrom(radial);

        if (jMapRadialModel.getJMapTool() == JMapTool.INSITU) {
            // Launch compute InSitu
            //log.debug("===> call ComputeInSitu()");
            computeInSitu();
        }
    }

    /**
     * Update View from RadialEnd
     */
    public void updateView(RadialEnd rEnd, boolean endIsVisible) {
        if (endIsVisible) {
            jMapPosition.setEndSource(rEnd.getEndSource());
            jMapPosition.setImpactTime(rEnd.getEndTime().getTime());
        } else {
            jMapPosition.setEndSource(null);
            jMapPosition.setImpactTime(null);
        }
        jMapComponent.resetView();
    }

    /**
     * Accessors
     */
    public JMapRadialModel getModel() {
        return jMapRadialModel;
    }

    public JMapComponent getJMapComponent() {
        return jMapComponent;
    }

    public void updateEclipticFOV() {
        eclipticPlaneComponent.updateFovWith(jMapComponent.jMapModel);
    }

    /**
     * Set fields visible mode
     *
     * @param visibleMode
     */
    private void setVisiblePA(boolean visibleMode) {
        centralPa.setVisible(visibleMode);
        northPa.setVisible(visibleMode);
        southPa.setVisible(visibleMode);
        paLabel.setVisible(visibleMode);
        centralPaLabel.setVisible(visibleMode);
        northPaLabel.setVisible(visibleMode);
        southPaLabel.setVisible(visibleMode);
    }

    /**
     * ***********************************************************************
     ********************* jMapComponent menu actions ************************
     * ***********************************************************************
     */
    @Override
    public void runShowPlanet(SpaceElement spaceElement) {
        jMapComponent.showHideElement(spaceElement);
    }

    @Override
    public void runShowAllPlanets() {
        jMapComponent.showAllPlanets();
    }

    @Override
    public void runShowStartEnd() {
        jMapComponent.showStartEnd();
    }

    @Override
    public void runShowAllProbes() {
        jMapComponent.showAllProbes();
    }

    @Override
    public void runShowProbe(SpaceElement spaceElement) {
        jMapComponent.showHideElement(spaceElement);
    }

    @Override
    public void runShowAllComets() {
        jMapComponent.showAllComets();
    }

    @Override
    public void runShowComet(SpaceElement spaceElement) {
        jMapComponent.showHideElement(spaceElement);
    }

    @Override
    public void runZoomP1() {
        jMapComponent.zoomP1();
    }

    @Override
    public void runZoomP2() {
        jMapComponent.zoomP2();
    }

    @Override
    public void runResetZoom() {
        jMapComponent.resetZoom();
    }

    @Override
    public void runReset() {
        jMapComponent.resetStartEnd();
    }

    /**
     * ***********************************************************************
     ************************ Specific menu actions **************************
     * ***********************************************************************
     */
    @Override
    public void runChooseCatalog(boolean linkcatMode, CMEType cmeType) {
        jMapCompute.setLinkcatMode(linkcatMode);
        jMapCompute.setCmeType(cmeType);
        jMapComponent.clearFitSeries();
        jMapComponent.clearCatalogSeries();
        // Launch compute Catalog
        computeCatalog();
    }

    @Override
    public void runSelectFit() {
        jMapComponent.setSelectFitInProgress(true);
    }

    @Override
    public void runRemoveLastPoint() {
        jMapComponent.removeLastPoint();
    }

    @Override
    public void runFitPoints() {
        jMapComponent.fitPoints();
    }

    @Override
    public void runClickPoints() {
        jMapRadialModel.clearView();
        jMapComponent.startClickPoints();
        fitParameterComponent.reset();
    }

    @Override
    public void runClickPointsFile() {
        if (jMapComponent.updloadClickPoints()) {
            jMapRadialModel.clearView();
        }
    }

    @Override
    public void runSavePoints() {
        jMapComponent.saveClickPoints();
    }

    /**
     * ***********************************************************************
     **************************** choose map menu ****************************
     * ***********************************************************************
     */
    @Override
    public void runChooseMap(String source, String type) {
        worker.updateImage(source, type);
    }

    /**
     * Workers sub-class - Upload data from server and display on IHM
     */
    private class JMapWorker {

        private JMap jMap = null;
        private Probe observer = null;
        private boolean defaultImage;
        private boolean newSource;

        /**
         * Update J-map image from observer at the current date.
         */
        public void updateImage(String source, String type) {
            jMapModel.update(source, type);
            newSource = true;
            update();
        }

        /**
         * Update J-map image from a new date
         */
        public void updateImage() {
            // clear positions of obs and sources
            jMapPosition.clearPositionsObservers();
            jMapPosition.clearPositionsSources();
            newSource = false;
            update();
        }

        public void update() {
            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 && jMap!=null) {
                        // thread is done with success
                        defaultImage = false;
                        if (jMapComponent.updateImage(jMap)) {
                            // update view
                            jMapModel.updateView();
                            jMapPosition.setObserverInSitu(jMapModel.getObserver());
                        }
                        // Reset JMap and Fit parameter components
                        jMapComponent.resetView();
                        fitParameterComponent.reset();
                        updateEclipticFOV();
                        endCursor();

                        // clear all fit series
                        jMapComponent.clearFitSeries();
                        jMapComponent.clearCatalogSeries();

                        //log.debug("Image has changed => call Compute()");
                        if (jMapRadialModel.getJMapTool() == JMapTool.INSITU) {
                            computeInSitu();
                        } else if (jMapRadialModel.getJMapTool() == JMapTool.FIT) {
                            jMapComponent.clearCatalogSeries();
                            computeCatalog();
                        }
//                    } else {
                    } else if (newState == Worker.State.FAILED || newState == Worker.State.CANCELLED) {
                        // thread is aborted
                        if (observer == null) {
                            DialogBox.warn(jMapModel.getObserver() + " probe is not available at this date !");
                            jMapModel.reset();
                            //update();
                        } else if (!defaultImage) {
                            if (newSource) {
                                DialogBox.warn("Image not available !");
                            }
                            // get default image
                            defaultImage = true;
                            update();
                        } else {
                            defaultImage = false;
                            jMapComponent.clearImage();
                        }

                        if (updateImageWorker.getException() != null) {
                            log.info("Jmap not found - " + updateImageWorker.getException().getMessage());
                            updateImageWorker.getException().printStackTrace();
                        }
                        endCursor();
                    }
                }
            });
            new Thread(updateImageWorker).start();
            waitCursor();
        }

        private Task<Object> updateImageWorker() {
            return new Task<Object>() {
                @Override
                protected Object call() {
                    observer = null;
                    // Get position of observer at time tStart
                    observer = jMapPosition.getPositionObserver(jMapModel.getObserver());

                    if (defaultImage) {
                        // Load default J-map for observer between t1 and t2
                        jMap = ServiceFactory.getJMapService().getDefaultJMap(observer, jMapModel.getType(), jMapPosition.getT1(), jMapPosition.getT2());
                    } else {
                        // Load J-map for observer between t1 and t2
                        jMap = ServiceFactory.getJMapService().getJMap(observer, jMapModel.getType(), jMapPosition.getT1(), jMapPosition.getT2());
                    }
                    if (jMap==null || jMap.getHeader() == null) {
                        jMap = null;
                        throw new NullPointerException("No JMap Found");
                    }
                    return true;
                }
            };
        }
    }

    /**
     * Compute Click
     */
    public void computeClick() {
        final Task<Object> computeClickWorker = this.computeClickWorker();
        computeClickWorker.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) {
                    // Add fit in situ series
                    jMapComponent.addFitSeries(jMapCompute.getFitPoints());
                    // update view
                    jMapRadialModel.updateView();
                    // notify change
                    getHasChanged().set(true);
                    getHasChanged().set(false);
                    try {
                        // redraw FitParameter fitPoints plot
                        fitParameterComponent.setFitParam(
                                jMapCompute.getBetaStart(),
                                jMapCompute.getSpeedSolarWind(),
                                jMapCompute.getFitPoints(),
                                jMapCompute.getClickPoints(),
                                jMapCompute.getFitError());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    // Clear
                    jMapCompute.setClickPoints(null);
                    jMapCompute.setFitPoints(null);
                    endCursor();

                } else if (newState == Worker.State.FAILED || newState == Worker.State.CANCELLED) {
                    // aborted
                    DialogBox.error("Compute Click has failed  !");
                    if (computeClickWorker.getException() != null) {
                        log.info("Compute Click failed - " + computeClickWorker.getException().getMessage());
                    }
                    endCursor();
                }
            }
        });
        new Thread(computeClickWorker).start();
        waitCursor();
    }

    private Task<Object> computeClickWorker() {
        return new Task<Object>() {
            @Override
            protected Object call() {
                jMapCompute.setClickPoints(jMapComponent.getClickPoints());
                // compute click algorithm
                jMapCompute.computeClick();
                // set position of observer in situ from computed time tStart 
                jMapPosition.setPositionObsInSitu();
                // compute Fit
                jMapCompute.computeFit();
                //log.debug("Compute Click successful ended - ");
                return true;
            }
        };
    }

    /**
     * Compute In Situ
     */
    public void computeInSitu() {
        final Task<Object> computeInSituWorker = this.computeInSituWorker();
        computeInSituWorker.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 view
                    jMapRadialModel.updateViewInSitu();
                    // Add fit in situ series
                    jMapComponent.addFitSeries(jMapCompute.getFitPoints());
                    // Clear
                    jMapCompute.setFitPoints(null);
                    endCursor();

                } else if (newState == Worker.State.FAILED || newState == Worker.State.CANCELLED) {
                    endCursor();
                }
            }
        });
        new Thread(computeInSituWorker).start();
        waitCursor();
    }

    private Task<Object> computeInSituWorker() {
        return new Task<Object>() {
            @Override
            protected Object call() {
                // Compute InSitu
                jMapCompute.computeInSitu();

                return true;
            }
        };
    }

    /**
     * Compute Catalog
     */
    public void computeCatalog() {
        final Task<Object> computeCatalogWorker = this.computeCatalogWorker();
        computeCatalogWorker.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) {
                    // clearance
                    jMapComponent.clearFitSeries();
                    jMapComponent.clearCatalogSeries();
                    // add computed fit series
                    if (jMapCompute.getFitCatalog() != null) {
                        for (Fit fit : jMapCompute.getFitCatalog()) {
                            jMapComponent.addCatalogSeries(fit.getFitPoints());
                        }
                    }
                    // update jmap header view 
                    jMapModel.updateView((jMapCompute.isLinkcatMode() ? "LINKCAT " : "") + jMapCompute.getCmeType().getShortName());
                    RootController.endCursor();
                    // disable Fit Parameter tab
                    fitResultTab.setDisable(false);
                    fitResultTab.setDisable(true);

                } else if (newState == Worker.State.FAILED || newState == Worker.State.CANCELLED) {
                    // clearance
                    jMapComponent.clearFitSeries();
                    jMapComponent.clearCatalogSeries();
                    // aborted
                    log.info("Compute Catalog failed - " + computeCatalogWorker.getException().getMessage());
                    DialogBox.error("Compute Catalog has failed  !");
                    RootController.endCursor();
                }
            }
        });
        new Thread(computeCatalogWorker).start();
        RootController.waitCursor();
    }

    private Task<Object> computeCatalogWorker() {
        return new Task<Object>() {
            @Override
            protected Object call() {
                // Load catalog parameters of fits (time, beta, speed) for obsInSitu between t1 and t2
                FitCatalog fitCatalog = ServiceFactory.getFitService().
                        fetchFitsCME(jMapPosition.getT1(), jMapPosition.getT2(), jMapCompute.isLinkcatMode(),
                                jMapCompute.getCmeType(), jMapPosition.getObsInSitu().getName());
                // Compute fits from catalog parameters
                jMapCompute.computeFits(fitCatalog.getFits());
                //log.debug("Compute J-Map Catalog successful ended - ");
                return true;
            }
        };
    }

    /**
     * Select Fit from Catalog
     */
    public void setFitFromCatalog() {
        final Task<Object> setFitFromCatalogWorker = this.setFitFromCatalogWorker();
        setFitFromCatalogWorker.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 view
                    jMapRadialModel.updateViewFromFit(jMapComponent.getSelectedFit());
                    // notify change
                    getHasChanged().set(true);
                    getHasChanged().set(false);
//                    try {
//                        // redraw FitParameter fitPoints plot
//                        fitParameterComponent.setFitParam(
//                        		jMapPosition.getObsInSitu().getName(), 
//                        		jMapCompute.getFitCatalog().get(jMapComponent.getSelectedFit()));
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    }
                    endCursor();

                } else if (newState == Worker.State.FAILED || newState == Worker.State.CANCELLED) {
                    // aborted
                    log.info("Compute Catalog failed - " + setFitFromCatalogWorker.getException().getMessage());
                    DialogBox.error("Compute Catalog has failed  !");
                    endCursor();
                }
            }
        });
        new Thread(setFitFromCatalogWorker).start();
        waitCursor();
    }

    private Task<Object> setFitFromCatalogWorker() {
        return new Task<Object>() {
            @Override
            protected Object call() {
                // update computed data from selected fit
                jMapCompute.updateFromFit(jMapComponent.getSelectedFit());
                // set position of observer in situ from selected time tStart 
                jMapPosition.setPositionObsInSitu();
                return true;
            }
        };
    }

    private void waitCursor() {
        this.setCursor(Cursor.WAIT);
        gridPane.setDisable(true);
    }

    private void endCursor() {
        this.setCursor(null);
        gridPane.setDisable(false);
    }

    public void setFitParameterComponent(FitParameterComponent fitParameterComponent) {
        this.fitParameterComponent = fitParameterComponent;
    }

    public BooleanProperty getHasChanged() {
        return hasChanged;
    }

    public void setHasChanged(BooleanProperty hasChanged) {
        this.hasChanged = hasChanged;
    }

}
