/* ----------------------------------------
 * Origin  : GFI INFORMATIQUE 
 * Project : CDPP Propagation Tool 
 * ----------------------------------------
 * History 
 * Version : 01/05/2015 : SCA : V2.1
 * ----------------------------------------
 */
package fr.tlse.irap.pt.client.controller.tools.externalLinks;

import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.ResourceBundle;

import eu.schudt.javafx.controls.calendar.DatePicker;
import fr.tlse.irap.pt.client.component.DialogComponent;
import fr.tlse.irap.pt.client.component.IDialogComponent;
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.dialogbox.DialogBox;
import fr.tlse.irap.pt.client.controller.tools.externalLinks.MedocModel.Observer;
import fr.tlse.irap.pt.client.controller.tools.externalLinks.MedocModel.WaveLength;
import fr.tlse.irap.spaceElement.Camera;
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.event.Event;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Cursor;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.MenuButton;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
/**
 * 
 * @author frup03304
 * @version
 */
public class MedocComponent extends AnchorPane implements Initializable, IDialogComponent, IMedoc {

	private DialogComponent dialog;

	@FXML protected GridPane startTimeGridPane;
	@FXML protected final DatePicker datePicker = new DatePicker("startTime");
    @FXML private TextField timeInterval;
    @FXML private ChoiceBox<String> unitTimeInt;
    @FXML private TextField timeStep;
    @FXML private ChoiceBox<String> unitTimeStep;
    @FXML private MenuButton chooseMenuBtn;
    @FXML private TextField observer;    
    @FXML private TextField instrument;
    @FXML private TextField detector;
    @FXML private TextField measure;
    @FXML private Button javaBtn;
    @FXML private Button httpBtn;
    @FXML private Button startTimeBtn;
    @FXML private Button endTimeBtn;

    private MapMenu medocMenu;
    private Observer obs;
	private Date startDate;
	private Date endDate;

	@Override
	public void initialize(URL location, ResourceBundle resources) {
		// init date picker
		datePicker.selectedDateProperty().set(new Date());
		addDatePicker();

		// init combo boxes
		ExternalLinks.initUnitTime(unitTimeInt);
		ExternalLinks.initUnitTime(unitTimeStep);

		// init context menu
		medocMenu = new MapMenu();
		List<Item> menus = new ArrayList<Item>();
		for (Observer obs : Observer.values()) {
			menus.add(MedocItemBuilder.getObserverItem(obs, medocMenu.getMap(), this));
		}
		medocMenu.addAll(menus);

		// Init buttons state
		javaBtn.setDisable(true);
		httpBtn.setDisable(true);

		chooseMenuBtn.getItems().clear();
		chooseMenuBtn.setOnMouseClicked(new EventHandler<MouseEvent>() {
			@Override
			public void handle(MouseEvent event) {
				event.consume();
				if (event.getButton() == MouseButton.PRIMARY) {
					medocMenu.show(chooseMenuBtn, event.getScreenX(), event.getScreenY());
					event.consume();
				}
				if (event.getButton() == MouseButton.SECONDARY) {
					medocMenu.hide();
					event.consume();
				}
			}
		});
		observer.setOnMouseClicked(new EventHandler<MouseEvent>() {
			@Override
			public void handle(MouseEvent event) {
				event.consume();
				if (event.getButton() == MouseButton.PRIMARY) {
					medocMenu.show(chooseMenuBtn, event.getScreenX(), event.getScreenY());
					event.consume();
				}
				if (event.getButton() == MouseButton.SECONDARY) {
					medocMenu.hide();
					event.consume();
				}
			}
		});

		timeInterval.addEventFilter(KeyEvent.ANY, new FilterKeyEvent(
				timeInterval, 1, 1, 999, Formatter.getFormatter(), new SimpleBooleanProperty(), timeInterval.focusedProperty()));

		timeStep.addEventFilter(KeyEvent.ANY, new FilterKeyEvent(
				timeStep, 1, 1, 999, Formatter.getFormatter(), new SimpleBooleanProperty(), timeStep.focusedProperty()));

		javaBtn.setOnMouseClicked(new EventHandler<Event>() {
			@Override
			public void handle(Event event) {
				callMedoc();
			}
		});

		httpBtn.setOnMouseClicked(new EventHandler<Event>() {
			@Override
			public void handle(Event event) {
				callMedocHttp();
			}
		});

		startTimeBtn.setOnMouseClicked(new EventHandler<Event>() {
			@Override
			public void handle(Event event) {
				datePicker.selectedDateProperty().set(startDate);
			}
		});
		endTimeBtn.setOnMouseClicked(new EventHandler<Event>() {
			@Override
			public void handle(Event event) {
				datePicker.selectedDateProperty().set(endDate);
			}
		});

	}

//	public void initComponentWith(Date date) {
//		initComponent(date);
//		dialog.show();
//	}

	public void initComponentWith(Date startDate, Date endDate) {
		this.startDate = startDate;
		this.endDate = endDate;
		initComponent();
		dialog.show();
	}

	//private void initComponent(Date date) {
	private void initComponent() {
		// set default values
		unitTimeInt.setValue(unitTimeInt.getItems().get(3));
		unitTimeStep.setValue(unitTimeStep.getItems().get(2));
//		// init start date
//		datePicker.selectedDateProperty().set(date);
		// init start date
		datePicker.selectedDateProperty().set(startDate);
		
	}

	@Override
	public void runChoose(Observer obs, Camera c, WaveLength wl) {
		this.obs = obs;
		observer.setText(obs.getName());
		instrument.setText(c.getInstrument());
		//detector.setText(c.getDetector());
		detector.setText(c.getName());
		measure.setText(wl.getShortName());
		// provisoire 
		//javaBtn.setDisable(true);
		javaBtn.setDisable(false);
		httpBtn.setDisable(false);
	}

	public void setDialog(DialogComponent dialog) {
		this.dialog = dialog;
	}

	public DialogComponent getDialog() {
		return dialog;
	}

	protected void addDatePicker() {
		ExternalLinks.setStyleDate(datePicker);
		startTimeGridPane.add(datePicker, 0, 0);
	}

	/**
	 * call Medoc interface API with selected arguments
	 */
	private void callMedoc() {
		try {
			ExternalLinks.callMedocApi(datePicker.selectedDateProperty().get(), getInterval(), getCadence(), obs.getName(), instrument.getText(), detector.getText(), measure.getText());
		}
		catch (Exception e) {
			e.printStackTrace();
		}
//
//		final Task<Object> callMedocWorker = callMedocWorker();
//
//		callMedocWorker.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) {
//							// thread is done with success
//							endCursor();
//
//						} else if (newState == Worker.State.FAILED || newState == Worker.State.CANCELLED) {
//							// thread is failed or cancelled
//							endCursor();
//							DialogBox.error(" Error while calling MEDOC interface.\n");
//							if (callMedocWorker.getException() != null) {
//								System.out.println(callMedocWorker.getException().getMessage());
//							}
//						}
//					}
//
//				});
//		new Thread(callMedocWorker).start();
//		waitCursor();
	}

	private Task<Object> callMedocWorker() {
		return new Task<Object>() {
			@Override
			protected Object call() throws Exception {
				ExternalLinks.callMedocApi(datePicker.selectedDateProperty().get(), getInterval(), getCadence(), obs.getName(), instrument.getText(), detector.getText(), measure.getText());
				return true;
			}
		};
	}

	/**
	 * call Medoc interface HTTP with selected arguments
	 */
	private void callMedocHttp() {
		final Task<Object> callMedocHttpWorker = callMedocHttpWorker();

		callMedocHttpWorker.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) {
							// thread is done with success
							endCursor();

						} else if (newState == Worker.State.FAILED || newState == Worker.State.CANCELLED) {
							// thread is failed or cancelled
							endCursor();
							DialogBox.error(" Error while calling MEDOC interface.\n");
							if (callMedocHttpWorker.getException() != null) {
								System.out.println(callMedocHttpWorker.getException().getMessage());
							}
						}
					}
				});
		new Thread(callMedocHttpWorker).start();
		waitCursor();
	}

	private Task<Object> callMedocHttpWorker() {
		return new Task<Object>() {
			@Override
			protected Object call() throws Exception {
				ExternalLinks.callMedocHttp(datePicker.selectedDateProperty().get(), obs.name(), instrument.getText(), detector.getText(), measure.getText());
				return true;
			}
		};
	}

	/**
	 * get cadence in seconds
	 * @return
	 */
	private long getCadence() {
		long ti = Formatter.toDouble(timeStep.getText()).longValue();
		return ExternalLinks.computeTimeInSeconds(ti, unitTimeStep.getValue());
	}

	/**
	 * get interval in seconds
	 * @return
	 */
	private long getInterval() {
		long ti = Formatter.toDouble(timeInterval.getText()).longValue();
		return ExternalLinks.computeTimeInSeconds(ti, unitTimeInt.getValue());
	}
	
	private void waitCursor() {
		this.setDisable(true);
		this.getScene().setCursor(Cursor.WAIT);
	}

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