/* ----------------------------------------
 * Origin  : GFI INFORMATIQUE 
 * Project : CDPP Propagation Tool 
 * ----------------------------------------
 * History 
 * Version : 01/05/2015 : SCA : V2.1
 * Version : 19/09/2016 : SCA : V2.2 (PSWS-H2020)
 *  Move Radial End computation on server side (WS)  
 * Version : 17/10/2018 : SCA : V2.2.5
 *  Redmine #6119 
 * Version : V2.12
 * DM-ID : Redmine#10626 : 04/04/2025 : Speed profile Chart
 * VERSION : V2.13
 * DM-ID : redmine#12109 : 10/09/2025 : KHK : Update endTime format 
 * DM-ID : redmine#11678 : 17/09/2025 : KHK : Delete the Speed Error column
 * ----------------------------------------
 */
package fr.tlse.irap.pt.client.controller.tools.radial;

import java.util.ArrayList;
import java.util.List;

import fr.tlse.irap.pt.client.component.CustomComponent;
import fr.tlse.irap.pt.client.component.ICustomComponent;
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.Item;
import fr.tlse.irap.pt.client.controller.common.MapMenu;
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.tools.IToolController.JMapTool;
import fr.tlse.irap.pt.client.controller.tools.common.IStartEndController;
import fr.tlse.irap.pt.client.controller.tools.common.StartEndItemBuilder;
import fr.tlse.irap.pt.client.services.ServiceFactory;
import fr.tlse.irap.spaceElement.Planet;
import fr.tlse.irap.spaceElement.SpaceElement;
import fr.tlse.irap.spaceElement.Sun;
import fr.tlse.irap.tool.radial.Radial;
import fr.tlse.irap.tool.radial.RadialEnd;
import java.util.Date;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;

public class RadialStartEndController extends GridPane implements ICustomComponent, IStartEndController {

    private static RadialStartModel radialStartModel = new RadialStartModel();
    private static ObjectProperty<SpaceElement> endSource = new SimpleObjectProperty<SpaceElement>();
    private static BooleanProperty endVisible = new SimpleBooleanProperty();
    private Planet earth = new Planet("EARTH");

    private Radial currentRadial = null;
    private JMapTool jMapTool;

    private static BooleanProperty hasChanged = new SimpleBooleanProperty();
    private static BooleanProperty hasFieldChanged = new SimpleBooleanProperty();
    private static BooleanProperty hasDragParamChanged = new SimpleBooleanProperty();

    @FXML
    protected RadialStartEndController radialStartEndComponent;
    // start fields
    @FXML
    private Button startBtn;
    @FXML
    private TextField startTime;
    @FXML
    private TextField speed;
    @FXML
    private TextField deltaSpeed;
    @FXML
    private TextField longStart;
    // drag model input params
    @FXML
    private CheckBox dragModel;
    @FXML
    private Button dragPlotBtn;
    @FXML
    private TextField innerBoundary;
    @FXML
    private TextField asymptoticSpeed;
    @FXML
    private TextField dragParam;
    @FXML
    private Label dragParamLabel;
    
    //11678
    @FXML
    private Label labelError;
    @FXML
    private Label labelPlus;
    @FXML
    private Label labelHours;
            
    // end fields
    @FXML
    private Button endBtn;
    @FXML
    private TextField endTime;
    @FXML
    private TextField deltaSpeedMin;
    @FXML
    private TextField deltaSpeedMax;
    @FXML
    private TextField longEnd;
    @FXML
    private TextField deltaLong;

    final MapMenu mapStartMenu = new MapMenu();
    final MapMenu mapEndMenu = new MapMenu();
    Sun sun = new Sun();

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

        createToolTips();
        // set default start end source
        runStartPoint(sun);
        endSource.set(earth);

        dragParamLabel.setText("Drag Parameter\n   (10\u207B\u2077/km)");

        // bind values between start fields and model properties 
        radialStartModel.getStartTime().bindBidirectional(startTime.textProperty());
        radialStartModel.getSpeed().bindBidirectional(speed.textProperty());
        radialStartModel.getDeltaSpeed().bindBidirectional(deltaSpeed.textProperty());
        radialStartModel.getLongStart().bindBidirectional(longStart.textProperty());
        radialStartModel.getDragModel().bindBidirectional(dragModel.selectedProperty());
        radialStartModel.getInnerBoundary().bindBidirectional(innerBoundary.textProperty());
        radialStartModel.getAsymptoticSpeed().bindBidirectional(asymptoticSpeed.textProperty());
        radialStartModel.getDragParam().bindBidirectional(dragParam.textProperty());

        speed.addEventFilter(KeyEvent.ANY, new FilterKeyEvent(speed, 500, 100, 9999, Formatter.getFormatter(), hasFieldChanged, speed.focusedProperty()));
        deltaSpeed.addEventFilter(KeyEvent.ANY, new FilterKeyEvent(deltaSpeed, 0, 0, 99, Formatter.getFormatter(), hasFieldChanged, deltaSpeed.focusedProperty()));
        longStart.addEventFilter(KeyEvent.ANY, new FilterKeyEvent(longStart, 0, 359, Formatter.getFormatter(), hasFieldChanged, longStart.focusedProperty()));
        innerBoundary.addEventFilter(KeyEvent.ANY, new FilterKeyEvent(innerBoundary, 10, 0, 999, Formatter.getFormatter(), hasFieldChanged, innerBoundary.focusedProperty()));
        asymptoticSpeed.addEventFilter(KeyEvent.ANY, new FilterKeyEvent(asymptoticSpeed, 500, 100, 9999, Formatter.getFormatter(), hasFieldChanged, asymptoticSpeed.focusedProperty()));
        dragParam.addEventFilter(KeyEvent.ANY, new FilterKeyEvent(dragParam, 0, 0, 999, Formatter.getFormatter(), hasDragParamChanged, dragParam.focusedProperty()));

        hasFieldChanged.addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                if (!newValue) {
                    // init drag parameter
                    radialStartModel.setDragParam("0.0");
                    // Notify change
                    getHasChanged().set(true);
                    getHasChanged().set(false);
                }
            }
        });

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

        radialStartModel.getDragModel().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                setDragEditMode(newValue);
                // Notify change
                getHasChanged().set(true);
                getHasChanged().set(false);
            }
        });

        radialStartModel.getStartTime().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                if (SpeedChartDialogBox.getSpeedChartComponent().getDialog().isShowing()) {
                    SpeedChartDialogBox.getSpeedChartComponent().getDialog().close();
                }
            }
        });
        
        // recompute drag model plot on changes
        getHasChanged().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observedBoolean, Boolean oldValue, Boolean newValue) {
                if (SpeedChartDialogBox.getSpeedChartComponent().getDialog().isShowing()
                        && !SpeedChartDialogBox.getSpeedChartComponent().isComputing()) {
                    SpeedChartDialogBox.getSpeedChartComponent().setRadial(currentRadial);
                    //System.out.println("*** getHasChanged updatePlotFromData");
                    SpeedChartDialogBox.getSpeedChartComponent().updatePlotFromData();
                }
            }
        });

        setDragEditMode(false);

        initMenus();
        
        //11678
        labelError.setVisible(false);
        labelPlus.setVisible(false);
        deltaSpeed.setVisible(false);
        deltaSpeedMin.setVisible(false);
        deltaSpeedMax.setVisible(false);
        labelHours.setVisible(false);
        
    }

    @Override
    public void runStartPoint(SpaceElement element) {
        if (endVisible.get() && element.getName().equals(endSource.get().getName())) {
            resetEndSource();
        }
        // update view with start source
        radialStartModel.setStartSource(element);
        startBtn.setText("Start : " + element.getLongName());
        // set edit mode of long start and drag model
        Style.setEditMode(longStart, jMapTool == null || jMapTool.equals(JMapTool.INSITU) ? element instanceof Sun : false);
        if (jMapTool != null && jMapTool.equals(JMapTool.INSITU) && element instanceof Sun) {
            dragModel.setDisable(false);
        } else {
            radialStartModel.setDragModel(false);
            dragModel.setDisable(true);
        }
    }

    @Override
    public void runEndPoint(SpaceElement element) {
        if (!element.getName().equals(radialStartModel.getStartSource().get().getName())) {
            if (!endVisible.get()) {
                // force default endSource to be changed
                endSource.set(null);
            }
            // set End model visible in all interfaces
            endVisible.set(true);
            endSource.set(element);
        }
    }

    /**
     * Reset end source
     */
    public void resetEndSource() {
        // force default endSource to be changed
        endSource.set(null);
        endVisible.set(false);
        endSource.set(earth);
    }

    /**
     * Set up end fields
     *
     * @param radialEnd
     */
    public void setUpViewWith(RadialEnd rEnd) {
        // update end fieds 
        endBtn.setText("End : " + endSource.get().getLongName());
        if (rEnd.isImpacted()) {
            //12109
            //endTime.setText(Formatter.toSdf(rEnd.getEndTime()));
            endTime.setText(Formatter.getSdf().format(rEnd.getEndTime().getTime()));            
        } else {
            endTime.setText("No impact");
        }
        // Display long End at TSUN
        longEnd.setText(Formatter.toDecimal1D(rEnd.getLongEnd()));
        deltaLong.setText(Formatter.toDecimal1D(rEnd.getLongSep()));
        deltaSpeedMin.setText(Formatter.toDecimal(rEnd.getDvMin()));
        deltaSpeedMax.setText(Formatter.toDecimal(rEnd.getDvMax()));
    }

    public void clearView() {
        endBtn.setText("End :");
        endTime.setText("");
        longEnd.setText("");
        deltaLong.setText("");
        deltaSpeedMin.setText("");
        deltaSpeedMax.setText("");
    }

    public JMapTool getJMapTool() {
        return jMapTool;
    }

    /**
     * Configure Start view according to JMap Tool
     *
     * @param jMapTool
     */
    public void setJMapTool(JMapTool jMapTool) {
        this.jMapTool = jMapTool;
        // configure menu and fields
        if (jMapTool.equals(JMapTool.INSITU)) {
            setDisableStartMenu(false);
            setEditMode(true);
        } else {
            setDisableStartMenu(true);
            setEditMode(false);
        }
        // set default start source
        runStartPoint(sun);
    }

    /**
     * Set fields edit mode
     *
     * @param editMode
     */
    public void setEditMode(boolean editMode) {
        Style.setEditMode(speed, editMode);
        Style.setEditMode(deltaSpeed, editMode);
        Style.setEditMode(longStart, editMode);

        if (editMode && jMapTool != null && jMapTool.equals(JMapTool.INSITU) && radialStartModel.startIsSun()) {
            dragModel.setDisable(false);
        } else {
            radialStartModel.setDragModel(false);
            dragModel.setDisable(true);
        }
    }

    /**
     * Set Drag fields edit mode
     *
     * @param editMode
     */
    public void setDragEditMode(boolean editMode) {
        innerBoundary.setDisable(!editMode);
        asymptoticSpeed.setDisable(!editMode);
        dragParam.setDisable(!editMode);
        dragPlotBtn.setDisable(!editMode);
    }

    @FXML
    void dragPlotBtnAction(ActionEvent event) {
        SpeedChartDialogBox.show(currentRadial);
    }

    /**
     * init context menu
     */
    private void initMenus() {

        startBtn.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                event.consume();

                if (event.getButton() == MouseButton.PRIMARY) {
                    mapStartMenu.show(startBtn, event.getScreenX(), event.getScreenY());
                    event.consume();
                }
                if (event.getButton() == MouseButton.SECONDARY) {
                    mapStartMenu.hide();
                    event.consume();
                }
            }
        });

        endBtn.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                event.consume();

                if (event.getButton() == MouseButton.PRIMARY) {
                    mapEndMenu.show(endBtn, event.getScreenX(), event.getScreenY());
                    event.consume();
                }
                if (event.getButton() == MouseButton.SECONDARY) {
                    mapEndMenu.hide();
                    event.consume();
                }
            }
        });
    }

    /**
     * load context menu
     */
    public void loadMenu() {
        // create context start menu
        List<Item> menus = new ArrayList<Item>();
        menus.add(StartEndItemBuilder.getStartingPlanetItem(mapStartMenu.getMap(), this));
        menus.add(StartEndItemBuilder.getStartingProbeItem(mapStartMenu.getMap(), this));
        menus.add(StartEndItemBuilder.getStartingCometItem(mapStartMenu.getMap(), this));
        menus.add(StartEndItemBuilder.getStartingSunItem(mapStartMenu.getMap(), this));

        mapStartMenu.getItems().clear();
        mapStartMenu.addAll(menus);

        // create context end menu
        menus = new ArrayList<Item>();
        menus.add(StartEndItemBuilder.getEndingPlanetItem(mapEndMenu.getMap(), this));
        menus.add(StartEndItemBuilder.getEndingProbeItem(mapEndMenu.getMap(), this));
        menus.add(StartEndItemBuilder.getEndingCometItem(mapEndMenu.getMap(), this));
        menus.add(StartEndItemBuilder.getEndingSunItem(mapEndMenu.getMap(), this));

        mapEndMenu.getItems().clear();
        mapEndMenu.addAll(menus);
    }

    /**
     * Call WS Computing Radial propagation
     *
     * @param radial model
     */
    public RadialEnd compute(Radial radial) {
        currentRadial = radial;
        return ServiceFactory.getToolService().computeRadial(radial, endSource.get());
    }

    private void createToolTips() {
        startBtn.setTooltip(new Tooltip(TOOLTIP.START_CLICK));
        endBtn.setTooltip(new Tooltip(TOOLTIP.END_CLICK));
        startTime.setTooltip(new Tooltip(TOOLTIP.START_TIME));
        speed.setTooltip(new Tooltip(TOOLTIP.SPEED));
        deltaSpeed.setTooltip(new Tooltip(TOOLTIP.DELTA_SPEED));
        longStart.setTooltip(new Tooltip(TOOLTIP.LONG_START));
        dragModel.setTooltip(new Tooltip(TOOLTIP.DRAG_MODEL));
        innerBoundary.setTooltip(new Tooltip(TOOLTIP.INNER_BOUNDARY));
        asymptoticSpeed.setTooltip(new Tooltip(TOOLTIP.ASYMPTOTIC_SPEED));
        dragParam.setTooltip(new Tooltip(TOOLTIP.DRAG_PARAM));
        endTime.setTooltip(new Tooltip(TOOLTIP.END_TIME));
        deltaSpeedMin.setTooltip(new Tooltip(TOOLTIP.DELTA_SPEED_MIN));
        deltaSpeedMax.setTooltip(new Tooltip(TOOLTIP.DELTA_SPEED_MAX));
        longEnd.setTooltip(new Tooltip(TOOLTIP.LONG_END));
        deltaLong.setTooltip(new Tooltip(TOOLTIP.DELTA_LONG));
    }

    public void setDisableStartMenu(boolean isDisable) {
        startBtn.setDisable(isDisable);
    }

    public RadialStartModel getStartModel() {
        return radialStartModel;
    }

    public void setStartModel(RadialStartModel startModel) {
        radialStartModel = startModel;
    }

    public BooleanProperty getHasChanged() {
        return hasChanged;
    }

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

    public void setStartLabel(SpaceElement startElement) {
        this.startBtn.setText("Start : " + startElement.getLongName());
    }

    public ObjectProperty<SpaceElement> getEndSource() {
        return endSource;
    }

    public boolean isEndVisible() {
        return endVisible.get();
    }

    public BooleanProperty getEndVisible() {
        return endVisible;
    }

}
