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

import java.text.DecimalFormat;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;

public class FilterKeyEvent implements EventHandler<KeyEvent> {

	protected BooleanProperty hasChanged;
	protected TextField txtField;
	
	protected Double defaultValue;
	protected double minValue;
	protected double maxValue;
	protected String format = "1D";

	private static final String NAN = "[a-zA-Z]";
	private static final String NUMERICO = "(\\d{0,3})([.]{0,1})\\d+";
	private DecimalFormat formatter;
	
	/**
	 * Complete constructor
	 * @param txtField
	 * @param defaultValue
	 * @param minValue
	 * @param maxValue
	 * @param hasChanged
	 * @param hasFocusChanged
	 */
	public FilterKeyEvent(TextField txtField, double defaultValue, double minValue, double maxValue, DecimalFormat formatter, BooleanProperty hasChanged, ReadOnlyBooleanProperty hasFocusChanged) {
		this.txtField = txtField;
		this.defaultValue = defaultValue;
		this.minValue = minValue;
		this.maxValue = maxValue;
		this.hasChanged = hasChanged;
		this.formatter = formatter;

		hasFocusChanged.addListener(
				new ChangeListener<Boolean>() {
					@Override
					public void changed(ObservableValue<? extends Boolean> observedBoolean, Boolean oldValue, Boolean newValue) {
						if (!newValue) {
							validateField();
						}
					}

				});
	}

	/**
	 * @param txtField
	 * @param minValue
	 * @param maxValue
	 * @param formatter
	 * @param hasChanged
	 * @param hasFocusChanged
	 */
	public FilterKeyEvent(TextField txtField, double minValue, double maxValue, DecimalFormat formatter, BooleanProperty hasChanged, ReadOnlyBooleanProperty hasFocusChanged) {
		this(txtField, minValue, minValue, maxValue, formatter, hasChanged, hasFocusChanged);		
	}

	/**
	 * @param txtField
	 * @param defaultValue
	 * @param minValue
	 * @param maxValue
	 * @param hasChanged
	 * @param hasFocusChanged
	 */
	public FilterKeyEvent(TextField txtField, double defaultValue, double minValue, double maxValue, BooleanProperty hasChanged, ReadOnlyBooleanProperty hasFocusChanged) {
		this(txtField, defaultValue, minValue, maxValue, Formatter.getFormatter1D(), hasChanged, hasFocusChanged);		
	}

	/**
	 * Default constructor
	 * @param txtField
	 * @param minValue
	 * @param maxValue
	 * @param hasChanged
	 * @param hasFocusChanged
	 */
	public FilterKeyEvent(TextField txtField, double minValue, double maxValue, BooleanProperty hasChanged, ReadOnlyBooleanProperty hasFocusChanged) {
		this(txtField, minValue, minValue, maxValue, hasChanged, hasFocusChanged);		
	}

	@Override
	public void handle(KeyEvent keyEvent) {
		// passing any character except [a-z]
		// if the character is enter so it notifies the change
		if (keyEvent.getCharacter().matches(NAN)) {
			keyEvent.consume();
		}
		else if (keyEvent.getCharacter().matches(NUMERICO)) {
			// notify the change
			//System.out.println("===========> FilterKeyEvent has changed");
			this.hasChanged.set(true);
		} 
		else if (keyEvent.getCode().equals(KeyCode.DELETE) || keyEvent.getCode().equals(KeyCode.BACK_SPACE)) {
			// notify the change
			//System.out.println("===========> FilterKeyEvent has changed");
			this.hasChanged.set(true);
		}
		else if (keyEvent.getCode().equals(KeyCode.TAB) || keyEvent.getCode().equals(KeyCode.ENTER)) {
			validateField();
		}

		// if it doesn't matches with the regular expression it changes the style (VALIDATION_ERROR)
		if (txtField.getText() != null) {
			Style.setOnError(txtField, !txtField.getText().matches(NUMERICO));
		}
	}

	/**
	 * Field validation 
	 */
	protected void validateField() {
		if (hasChanged.get()) {
			//System.out.println("==============> FilterKeyEvent has changed => validate the field");
			Double result = defaultValue;
			try {
				result = Formatter.toDouble(txtField.getText(), (double) defaultValue);
				if (result < minValue) {
					result = minValue;
				}
				else if (result > maxValue) {
					result = maxValue;
				}
			}
			catch(Exception e) {
			}
			txtField.setText(Formatter.toDecimal(result, formatter));
			hasChanged.set(false);
		}
	}

	public double getMinValue() {
		return minValue;
	}

	public double getMaxValue() {
		return maxValue;
	}

}

