/* ----------------------------------------
 * Origin  : GFI INFORMATIQUE 
 * Project : CDPP Propagation Tool 
 * ----------------------------------------
 * History 
 * Version : 01/05/2015 : SCA : V2.1
 * VERSION : V2.12
 * DM-ID : redmine#11799 : 15/04/2025 : KHK : PFSS mode – Br Factor
 * ----------------------------------------
 */
package fr.tlse.irap.pt.client.controller.tools;

import java.util.Date;

import fr.tlse.irap.pt.client.component.CustomComponent;
import fr.tlse.irap.pt.client.component.ICustomComponent;
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.timestamp.TimestampController;
import fr.tlse.irap.pt.client.controller.tools.catalog.CorotationCatalogDialogBox;
import fr.tlse.irap.pt.client.controller.tools.corotation.CorotationDashboardController;
import fr.tlse.irap.pt.client.controller.tools.externalLinks.AmdaDialogBox;
import fr.tlse.irap.pt.client.controller.tools.externalLinks.ApisDialogBox;
import fr.tlse.irap.pt.client.controller.tools.externalLinks.MedocDialogBox;
import fr.tlse.irap.pt.client.controller.tools.fitParameter.FitParameterComponent;
import fr.tlse.irap.pt.client.controller.tools.jmap.JMapCorotationComponent;
import fr.tlse.irap.pt.client.controller.tools.samp.JSampController;
import fr.tlse.irap.pt.client.controller.tools.timetable.TimeTableCorotationController;
import fr.tlse.irap.spaceElement.SpaceElement;
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.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Tab;
import javafx.scene.layout.GridPane;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CorotationController extends GridPane implements ICustomComponent, IToolController{

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

	private BooleanProperty hasChanged = new SimpleBooleanProperty();
	private ObjectProperty<JMapTool> jMapTool = new SimpleObjectProperty<JMapTool>();

	
	
	@FXML protected CorotationController rootCorotation;
    @FXML public CorotationDashboardController corotationDashboardComponent;
    @FXML protected JMapCorotationComponent jMapCorotationComponent;
    @FXML protected TimeTableCorotationController timeTableComponent;
    @FXML protected FitParameterComponent fitParameterComponent;
    @FXML protected Tab fitResultTab;
    @FXML protected Tab timetableTab;
    @FXML protected Button amdaBtn;
    @FXML protected Button medocBtn;
    @FXML protected Button apisBtn;
    @FXML protected Button sampBtn;

    private boolean isInitialized;
    
	public CorotationController() {
		super();
		CustomComponent.initCustomComponent(this);
		
        // listen for Corotation Start changed
		corotationDashboardComponent.getHasChanged().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observedBoolean, Boolean oldValue, Boolean newValue) {
                if (newValue) {
					// refresh timetable
					timeTableComponent.updateModel(corotationDashboardComponent.corotation);
			    	if (timetableTab.isSelected()) {
			    		timeTableComponent.updateView();
			    	}
                	// refresh jMap
                	jMapCorotationComponent.updateView(corotationDashboardComponent.corotation);
                	// notify change
                	getHasChanged().set(true);
                }
            }
        });
        
        // listen for jMapTool changed
		jMapTool.addListener(new ChangeListener<JMapTool>() {
			@Override
			public void changed(ObservableValue<? extends JMapTool> observableObject, JMapTool oldValue, JMapTool newValue) {
				if (newValue != null) {
					corotationDashboardComponent.setJMapTool(newValue);
					jMapCorotationComponent.setJMapTool(newValue);
					jMapCorotationComponent.setFitResultTab(fitResultTab);
				}
			}
		});

        // listen for jMapCorotationComponent changed
        jMapCorotationComponent.getHasChanged().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observedBoolean, Boolean oldValue, Boolean newValue) {
                if (newValue) {
                	// update Corotation from Jmap
                	jMapCorotationComponent.updateCorotation(corotationDashboardComponent.corotation);
                	
                	if (jMapTool.get().equals(JMapTool.INSITU)) { 
            			// update carrington
                		corotationDashboardComponent.updateCarringtonFromCorotation();
            			// update start fields and notify changed
                		corotationDashboardComponent.updateStartView();
                	}
                	else {
                		// Set InSitu mode to false => Corotation is computed from J-map parameters (computed or selected)
            			corotationDashboardComponent.corotation.setInSitu(false);
                		// update start date
                		corotationDashboardComponent.getStartDate().set(corotationDashboardComponent.corotation.getStartTime().getTime());
                	}
                }
            }
        });
        
    	// listen for corotation End change
		this.getHasChanged().addListener(new ChangeListener<Boolean>() {
			@Override
			public void changed(ObservableValue<? extends Boolean> observedBoolean, Boolean oldValue, Boolean newValue) {
				if (newValue) {
                	// compute propagation
					computeCorotation();                                       
				}
			}
		});

	}

	@Override
	public void initComponentWith(EclipticPlaneController eclipticPlaneComponent, TimestampController timestampComponent) {
		if (isInitialized) {
			// update only the active tool
			if (eclipticPlaneComponent.getTool() == Tool.COROTATION) {
				// refresh ecliptic from corotation + Jmap
				corotationDashboardComponent.updateEcliptic();
				jMapCorotationComponent.updateEclipticFOV();
			}
		}
		else {
			// first init
			isInitialized = true;
	        // Init dynamic part of components
			corotationDashboardComponent.initComponentWith(eclipticPlaneComponent, timestampComponent);
			jMapCorotationComponent.initComponentWith(eclipticPlaneComponent, timestampComponent.selectedDateProperty());
			// Set start Source to controller which need it
			jMapCorotationComponent.setStartSource(corotationDashboardComponent.corotationStartEndController.getStartModel().getStartSource());
			// Listen for end source change
			corotationDashboardComponent.corotationStartEndController.getEndSource().addListener(new ChangeListener<SpaceElement>() {
				@Override
				public void changed(ObservableValue<? extends SpaceElement> observable, SpaceElement oldValue, SpaceElement newValue) {
					if (newValue == null || (oldValue != null && oldValue.getName().equals(newValue.getName()))) {
						return;
					}
					if (corotationDashboardComponent.corotationStartEndController.isEndVisible()) {
						corotationDashboardComponent.corotation.setEndElement(newValue);
					}
					else {
						corotationDashboardComponent.corotation.setEndElement(null);
					}
					// notify for computation
					getHasChanged().set(true);
				}
			});
	        // bind fitParamComponent with JMap
	        fitParameterComponent.setJMapCorotationComponent(jMapCorotationComponent);
		}
	}

	/**
	 * Thread dedicated to Compute Corotation process
	 */
	private void computeCorotation() {
		final Task<Object> computeCorotationWorker = computeCorotationWorker();

		computeCorotationWorker.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) {
							corotationDashboardComponent.endCursor();
							// update all components from corotation model
							corotationDashboardComponent.updateView();
							corotationDashboardComponent.updateEcliptic();
							jMapCorotationComponent.updateView(
									corotationDashboardComponent.corotationEnd, 
									corotationDashboardComponent.corotationStartEndController.isEndVisible());
                                                        
                                                        
                                                       //11799 - calling several time : remove it?
                                                        log.debug("Listen for Corotation End change : check pfss mode.");
                                                        corotationDashboardComponent.updatingWithBrFactor(); 
                                                          //corotationDashboardComponent.getCbxPfssMode().setSelected(false);
							
		                	getHasChanged().set(false);
							
						} else if (newState == Worker.State.FAILED || newState == Worker.State.CANCELLED) {
							// thread is failed or cancelled
		                	getHasChanged().set(false);
		                	corotationDashboardComponent.endCursor();
		                	String target = corotationDashboardComponent.corotationStartEndController.getEndSource().get().getName();
							corotationDashboardComponent.corotationStartEndController.resetEndSource();
							DialogBox.warn("Position of " + target + " at start time has not be found.\nDefault End has been reset");
							computeCorotationWorker.getException().printStackTrace();
						}
					}

				});

		new Thread(computeCorotationWorker).start();
		corotationDashboardComponent.waitCursor();
	}

	private Task<Object> computeCorotationWorker() {
		return new Task<Object>() {
			@Override
			protected Object call() throws Exception {
				return corotationDashboardComponent.computeCorotation();
			}
		};
	}

	/**
	 *  Buttons Action
	 */
	
    @FXML 
    void catalogBtnAction(ActionEvent event) {
    	Date tStart = corotationDashboardComponent.corotation.getStartTime().getTime();
		CorotationCatalogDialogBox.show(tStart);
    }
	
    @FXML 
    void amdaBtnAction(ActionEvent event) {
    	Date tStart = corotationDashboardComponent.corotation.getStartTime().getTime();
    	Date tEnd = corotationDashboardComponent.corotationEnd.getEndTime().getTime();
		AmdaDialogBox.show(tStart, tEnd);
    }

    @FXML 
    void medocBtnAction(ActionEvent event) {
    	Date tStart = corotationDashboardComponent.corotation.getStartTime().getTime();
    	Date tEnd = corotationDashboardComponent.corotationEnd.getEndTime().getTime();
		MedocDialogBox.show(tStart, tEnd);
    }

    @FXML 
    void apisBtnAction(ActionEvent event) {
    	SpaceElement endSource = corotationDashboardComponent.corotationEnd.getEndSource();
    	Date tEnd = corotationDashboardComponent.corotationEnd.getEndTime().getTime();
		ApisDialogBox.show(endSource.getName(), tEnd);
    }

    @FXML 
    void sampBtnAction(ActionEvent event) {
    	JSampController.getJSampFrame().setVisible(true);
    }

    @FXML 
    void timetableTabChange(Event event) {
    	if (timetableTab.isSelected()) {
    		timeTableComponent.updateView();
    	}
    }

	public BooleanProperty getHasChanged() {
		return hasChanged;
	}

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

	public ObjectProperty<JMapTool> getJMapTool() {
		return jMapTool;
	}
	
	public void setJMapTool(JMapTool jMapTool) {
		this.jMapTool.set(jMapTool);
	}

}
