/* ----------------------------------------
 * 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 : 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.corotation;

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.corotation.Corotation;
import fr.tlse.irap.tool.corotation.CorotationEnd;
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.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 CorotationStartEndController extends GridPane implements ICustomComponent, IStartEndController {
	
	private static CorotationStartModel corotationStartModel = new CorotationStartModel();
	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();
	private static BooleanProperty hasDeltaTChanged = new SimpleBooleanProperty();
	private static BooleanProperty hasDeltaVChanged = new SimpleBooleanProperty();
	private static BooleanProperty hasSpreadChanged = new SimpleBooleanProperty();

	@FXML protected CorotationStartEndController corotationStartEndController;
	// start fields
    @FXML private Button startBtn;
    @FXML private TextField startTime;
    @FXML private TextField speed;
    @FXML private TextField deltaSpeed;
    @FXML private TextField spread;
    @FXML private TextField rotPeriod;
    @FXML private TextField longStart;

	// end fields
    @FXML private Button endBtn;
    @FXML private TextField endTime;
    @FXML private TextField deltaSpeedMin;
    @FXML private TextField deltaSpeedMax;
    @FXML private TextField deltaSpreadMin;
    @FXML private TextField deltaSpreadMax;
    @FXML private TextField longEnd;
    @FXML private TextField deltaLong;
	
    //11678
    @FXML
    private Label labelError;
    @FXML
    private Label labelPlus;
    @FXML
    private Label labelHours;
    
    final MapMenu mapStartMenu = new MapMenu();
	final MapMenu mapEndMenu = new MapMenu();
	Sun sun = new Sun();
       
	public CorotationStartEndController() {
		super();
		CustomComponent.initCustomComponent(this);

		createToolTips();
		// set default start end source
		runStartPoint(sun);
		endSource.set(earth);
		
		// bind values between start fields and model properties 
		corotationStartModel.getStartTime().bindBidirectional(startTime.textProperty());
		corotationStartModel.getSpeed().bindBidirectional(speed.textProperty());
		corotationStartModel.getDeltaSpeed().bindBidirectional(deltaSpeed.textProperty());
		corotationStartModel.getSpread().bindBidirectional(spread.textProperty());
		corotationStartModel.getRotPeriod().bindBidirectional(rotPeriod.textProperty());
		corotationStartModel.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(), hasDeltaVChanged, deltaSpeed.focusedProperty()));
		spread.addEventFilter(KeyEvent.ANY, new FilterKeyEvent(spread, 22.5, 0, 179, Formatter.getFormatter(), hasSpreadChanged, spread.focusedProperty()));
		rotPeriod.addEventFilter(KeyEvent.ANY, new FilterKeyEvent(rotPeriod, 25.38, 20, 50, Formatter.getFormatter(), hasFieldChanged, rotPeriod.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);
				}
			}
		});

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

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

		hasSpreadChanged.addListener(new ChangeListener<Boolean>() {
			@Override
			public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
				if (!newValue){                                   
					corotationStartModel.setDeltaSpeed("0.0");
					// Notify change
					getHasChanged().set(true);
					getHasChanged().set(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
		corotationStartModel.setStartSource(element);
		this.startBtn.setText("Start : "+element.getName());
		// set edit mode of long start
		Style.setEditMode(longStart, jMapTool == null || jMapTool.equals(JMapTool.INSITU) ? element instanceof Sun : false);
	}

	@Override
	public void runEndPoint(SpaceElement element) {
		if (!element.getName().equals(corotationStartModel.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  
	 */
	public void setUpViewWith(CorotationEnd cEnd) {
		endBtn.setText("End : " + endSource.get().getLongName());
		if (cEnd.isImpacted()) {
                    //12109
                    //endTime.setText(Formatter.toSdf(cEnd.getEndTime()));
                    endTime.setText(Formatter.getSdf().format(cEnd.getEndTime().getTime()));
                   
		} 
		else {
			endTime.setText("No impact");
		}
		// Display long End at TSUN
		longEnd.setText(Formatter.toDecimal1D(cEnd.getLongEnd()));
		deltaLong.setText(Formatter.toDecimal1D(cEnd.getLongSep()));
		
		deltaSpeedMin.setText(Formatter.toDecimal(cEnd.getDvMin()));
		deltaSpeedMax.setText(Formatter.toDecimal(cEnd.getDvMax()));
		deltaSpreadMin.setText(Formatter.toDecimal(cEnd.getDphiMin()));
		deltaSpreadMax.setText(Formatter.toDecimal(cEnd.getDphiMax()));
	}

	public void clearView() {
		endBtn.setText("End :");
		endTime.setText("");
		longEnd.setText("");
		deltaLong.setText("");
		deltaSpeedMin.setText("");
		deltaSpeedMax.setText("");
		deltaSpreadMin.setText("");
		deltaSpreadMax.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
		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(longStart, 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 Corotation propagation
	 * @param corotationModel
	 */
	public CorotationEnd compute(Corotation corotation) {
		return ServiceFactory.getToolService().computeCorotation(corotation, 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));
		rotPeriod.setTooltip(new Tooltip(TOOLTIP.ROT_PERIOD));
		endTime.setTooltip(new Tooltip(TOOLTIP.END_TIME));
		deltaSpeedMin.setTooltip(new Tooltip(TOOLTIP.DELTA_SPEED_MIN));
		deltaSpeedMax.setTooltip(new Tooltip(TOOLTIP.DELTA_SPEED_MAX));
		deltaSpreadMin.setTooltip(new Tooltip(TOOLTIP.DELTA_SPREAD_MIN));
		deltaSpreadMax.setTooltip(new Tooltip(TOOLTIP.DELTA_SPREAD_MAX));
		longEnd.setTooltip(new Tooltip(TOOLTIP.LONG_END));
		deltaLong.setTooltip(new Tooltip(TOOLTIP.DELTA_LONG));
	}

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

	public CorotationStartModel getStartModel() {
		return corotationStartModel;
	}

	public void setStartModel(CorotationStartModel startModel) {
		corotationStartModel = startModel;
	}

	public BooleanProperty getHasChanged() {
		return hasChanged;
	}

	public void setHasChanged(BooleanProperty hasChanged) {
		CorotationStartEndController.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 BooleanProperty getHasSpreadChanged() {
        return hasSpreadChanged;
    }

    public void setHasSpreadChanged(BooleanProperty hasSpreadChanged) {
        CorotationStartEndController.hasSpreadChanged = hasSpreadChanged;
    }
  
}
