/* ----------------------------------------
 * Origin  : GFI INFORMATIQUE 
 * Project : CDPP Propagation Tool 
 * ----------------------------------------
 * History 
 * Version : 01/05/2015 : SCA : V2.1
 * Version : 14/04/2016 : SCA : V2.2 (PSWS-H2020)
 * Version : 30/11/2023 : LBE : avoid triggering changes before init
 * VERSION : V2.12
 * DM-ID : redmine#11799 : 08/04/2025 : KHK : PFSS mode – Br Factor
 * 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.sep;

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.sep.Sep;
import fr.tlse.irap.tool.sep.Sep.Particle;
import fr.tlse.irap.tool.sep.SepEnd;
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.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
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 SepStartEndController extends GridPane implements ICustomComponent, IStartEndController {

    private static SepStartModel sepStartModel = new SepStartModel();
    private static ObjectProperty<SpaceElement> endSource = new SimpleObjectProperty<SpaceElement>();
    private static BooleanProperty endVisible = new SimpleBooleanProperty();
    private Planet earth = new Planet("EARTH");
    private JMapTool jMapTool;

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

    @FXML
    protected SepStartEndController sepStartEndController;
    // start fields
    @FXML
    private Button startBtn;
    @FXML
    private TextField startTime;
    @FXML
    private TextField speed;
    @FXML
    private TextField deltaSpeed;
    @FXML
    private TextField startLength;
    @FXML
    private TextField rotPeriod;
    @FXML
    private TextField spread;
    @FXML
    private ChoiceBox<Particle> particle;
    @FXML
    private TextField particleEnergy;
    @FXML
    private TextField longStart;

    // end fields
    @FXML
    private Button endBtn;
    @FXML
    private TextField endTime;
    @FXML
    private TextField endLength;
    @FXML
    private TextField deltaLengthMin;
    @FXML
    private TextField deltaLengthMax;
    @FXML
    private TextField deltaTimeMinL;
    @FXML
    private TextField deltaTimeMaxL;
    @FXML
    private TextField longEnd;
    @FXML
    private TextField deltaLong;

    //11678
    @FXML
    private Label labelError;
    @FXML
    private Label labelPlus;
    @FXML
    private Label labelMin;
    @FXML
    private Label labelErrorAu;
    
    final MapMenu mapStartMenu = new MapMenu();
    final MapMenu mapEndMenu = new MapMenu();
    Sun sun = new Sun();
        
    public SepStartEndController() {
        super();
        CustomComponent.initCustomComponent(this);

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

        // bind values between start fields and model properties 
        sepStartModel.getStartTime().bindBidirectional(startTime.textProperty());
        sepStartModel.getSpeed().bindBidirectional(speed.textProperty());
        sepStartModel.getDeltaSpeed().bindBidirectional(deltaSpeed.textProperty());
        sepStartModel.getStartLength().bindBidirectional(startLength.textProperty());
        sepStartModel.getRotPeriod().bindBidirectional(rotPeriod.textProperty());
        sepStartModel.getSpread().bindBidirectional(spread.textProperty());
        sepStartModel.getParticle().bindBidirectional(particle.valueProperty());
        sepStartModel.getParticleEnergy().bindBidirectional(particleEnergy.textProperty());
        sepStartModel.getLongStart().bindBidirectional(longStart.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()));
        spread.addEventFilter(KeyEvent.ANY, new FilterKeyEvent(spread, 22.5, 0, 179, Formatter.getFormatter(), hasFieldChanged, spread.focusedProperty()));
        rotPeriod.addEventFilter(KeyEvent.ANY, new FilterKeyEvent(rotPeriod, 25.38, 20, 50, Formatter.getFormatter(), hasFieldChanged, rotPeriod.focusedProperty()));
        particleEnergy.addEventFilter(KeyEvent.ANY, new FilterKeyEvent(particleEnergy, 30, 0, 999, Formatter.getFormatter4D(), hasFieldChanged, particleEnergy.focusedProperty()));
        longStart.addEventFilter(KeyEvent.ANY, new FilterKeyEvent(longStart, 0, 359, Formatter.getFormatter(), hasFieldChanged, longStart.focusedProperty()));

        hasFieldChanged.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);
                }
            }
        });

        // init particle combo
        particle.getItems().clear();
        for (Particle p : Particle.values()) {
            particle.getItems().add(p);
        }
        // set default value
        particle.setValue(Particle.proton);

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

        initMenus();
        //116784
        labelError.setVisible(false);
        labelPlus.setVisible(false);
        labelMin.setVisible(false);
        labelErrorAu.setVisible(false);
        deltaSpeed.setVisible(false);
        deltaTimeMinL.setVisible(false);
        deltaTimeMaxL.setVisible(false);
        deltaLengthMin.setVisible(false);
        deltaLengthMax.setVisible(false);
        
    }

    @Override
    public void runStartPoint(SpaceElement spaceElement) {
        if (endVisible.get() && spaceElement.getName().equals(endSource.get().getName())) {
            resetEndSource();
        }
        // update view with start source
        sepStartModel.setStartSource(spaceElement);
        this.startBtn.setText("Start : " + spaceElement.getLongName());
        // set edit mode of long start
        Style.setEditMode(longStart, jMapTool == null || jMapTool.equals(JMapTool.INSITU) ? spaceElement.getClass().equals(Sun.class) : false);
    }

    @Override
    public void runEndPoint(SpaceElement spaceElement) {
        if (!spaceElement.getName().equals(sepStartModel.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(spaceElement);
        }
    }

    /**
     * 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
     */
    public void setUpViewWith(SepEnd sepEnd) {
        endBtn.setText("End : " + endSource.get().getLongName());
        if (sepEnd.isImpacted()) {
            //12109
//            endTime.setText(Formatter.toSdf(sepEnd.getEndTime()));
            endTime.setText(Formatter.getSdf().format(sepEnd.getEndTime().getTime()));

        } else {
            endTime.setText("No impact");
        }
        // Display long End at TSUN
        longEnd.setText(Formatter.toDecimal1D(sepEnd.getLongEnd()));
        deltaLong.setText(Formatter.toDecimal1D(sepEnd.getLongSep()));

        endLength.setText(Formatter.toDecimal(sepEnd.getLength()));
        deltaTimeMinL.setText(Formatter.toDecimal(sepEnd.getDtMinL()));
        deltaTimeMaxL.setText(Formatter.toDecimal(sepEnd.getDtMaxL()));
        deltaLengthMin.setText(Formatter.toDecimal(sepEnd.getDlMin()));
        deltaLengthMax.setText(Formatter.toDecimal(sepEnd.getDlMax()));
    }

    public void clearView() {
        endBtn.setText("End :");
        endTime.setText("");
        longEnd.setText("");
        deltaLong.setText("");
        endLength.setText("");
        deltaTimeMinL.setText("");
        deltaTimeMaxL.setText("");
        deltaLengthMin.setText("");
        deltaLengthMax.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(spread, editMode);
        Style.setEditMode(rotPeriod, editMode);
        Style.setEditMode(particleEnergy, editMode);
        Style.setEditMode(longStart, editMode);
        //particle.setEditable(editMode);
        particle.setDisable(!editMode);
    }

    /**
     * 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 SEP propagation
     *
     * @param SEP model
     */
    public SepEnd compute(Sep sep) {
        return ServiceFactory.getToolService().computeSep(sep, 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));
        spread.setTooltip(new Tooltip(TOOLTIP.SPREAD));
        longStart.setTooltip(new Tooltip(TOOLTIP.LONG_START));
        startLength.setTooltip(new Tooltip(TOOLTIP.START_LENGTH));
        rotPeriod.setTooltip(new Tooltip(TOOLTIP.ROT_PERIOD));
        particleEnergy.setTooltip(new Tooltip(TOOLTIP.PARTICLE_ENERGY));
        endTime.setTooltip(new Tooltip(TOOLTIP.END_TIME));
        endLength.setTooltip(new Tooltip(TOOLTIP.DELTA_LENGTH));
        deltaLengthMin.setTooltip(new Tooltip(TOOLTIP.DELTA_LENGTH_MIN));
        deltaLengthMax.setTooltip(new Tooltip(TOOLTIP.DELTA_LENGTH_MAX));
        deltaTimeMinL.setTooltip(new Tooltip(TOOLTIP.DELTA_TIME_MINL));
        deltaTimeMaxL.setTooltip(new Tooltip(TOOLTIP.DELTA_TIME_MAXL));
        longEnd.setTooltip(new Tooltip(TOOLTIP.LONG_END));
        deltaLong.setTooltip(new Tooltip(TOOLTIP.DELTA_LONG));
    }

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

    public SepStartModel getStartModel() {
        return sepStartModel;
    }

    public void setStartModel(SepStartModel startModel) {
        sepStartModel = startModel;
    }

    public BooleanProperty getHasChanged() {
        return hasChanged;
    }

    public void setHasChanged(BooleanProperty hasChanged) {
        SepStartEndController.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;
    }

    //11799

    public static BooleanProperty getHasFieldChanged() {
        return hasFieldChanged;
    }

    public static void setHasFieldChanged(BooleanProperty hasFieldChanged) {
        SepStartEndController.hasFieldChanged = hasFieldChanged;
    }
    
}
