/** @package eFocus js lib */

/**
 * numberControl Class - adds plus/min buttons and arrowkey-control to text-inputs with some validation
 *
 * @author Klaas Dieleman <klaas[AT]efocus.nl>
 * @since 1.0, 12 jan, 2010
 * @copyright eFocus
 * @uses MooTools 1.2.4 Core <http://www.mootools.net>
 *
 * @param element or [elements]
 * @param {options}
 *
 */

var numberControl = new Class({
	
	Implements: Options,
	
	options: { 
		minValue		: null,
		maxValue		: null,
		strictBoundaries: true,
		allowEmpty		: true,
		onChange		: null
	},
	
	initialize: function(options) {
		var params = Array.link(arguments, {options: Object.type, elements: $defined});
		this.setOptions(params.options);
		
		/** @var integer minimum allowed value */
		if(this.options.minValue) this.minValue = this.options.minValue.toInt();
		
		/** @var integer maximum allowed value */
		if(this.options.maxValue) this.maxValue = this.options.maxValue.toInt();
		
		/** @var boolean disallow value to go out of optional max- and min-values */
		this.strictBoundaries = this.options.strictBoundaries;
		
		/** @var boolean let empty input be valid */
		this.allowEmpty = this.options.allowEmpty;
		
		/** @var function fired when input changed */
		this.onChange = this.options.onChange;
		
		/** @var boolean property is input valid according to minValue, maxValue and allowEmpty options */
		this.isValid = true;


		// always put input argument(s) in an array, if provided
		this.inputElements = new Array;
		if(params.elements && params.elements.length > 0) {
			this.inputElements = params.elements;
		} else if (params.elements && (typeof params.elements.length == 'undefined')) {
			this.inputElements[0] = params.elements;
		} else {
			return false;
		}
		
		// check for correct DOM elements and prepare them
		this.inputElements.each(function(el) {
			if(!el.match('input[type=text')) return false
			
			el.isValid = true;
			this.injectControls(el);
			this.attachEvents(el);
		}.bind(this));
	
	},
	
	/**
	 * inject plus/min buttons after input elements
	 *
	 * @author Klaas <klaas[AT]efocus.nl>
	 * @since 1.0, 12 jan 2010
	 *
	 * @param element el
	 * @return void
	 */
	injectControls: function(el) {
		var buttonHolder = new Element('span', {
			'class':	'numbercontroller'
		});
		
		this.incrementButton = new Element('input', {
			'type':		'button',
			'class':	'increment',
			'value':	'+'
		});
		
		this.decrementButton = new Element('input', {
			'type':		'button',
			'class':	'decrement',
			'value':	'-'
		});
		
		buttonHolder.inject(el, 'after');
		this.incrementButton.inject(buttonHolder, 'top');
		this.decrementButton.inject(buttonHolder, 'bottom');
	},
	
	/**
	 * attach key and mouse events
	 *
	 * @author Klaas <klaas[AT]efocus.nl>
	 * @since 1.0, 12 jan 2010
	 *
	 * @param element el
	 * @return void
	 */
	attachEvents: function(el) {
		
		this.incrementButton.addEvent('click', function(event) {
			event.preventDefault();
			event.stop();
			if(!isNaN(el.get('value').toInt())) this.incrementValue(el)
			el.isValid = this.validateInput(el);
			if(this.onChange) this.onChangeFunction(el)
		}.bind(this));
		
		this.decrementButton.addEvent('click', function(event) {
			event.preventDefault();
			event.stop();
			if(!isNaN(el.get('value').toInt())) this.decrementValue(el)
			el.isValid = this.validateInput(el);
			if(this.onChange) this.onChangeFunction(el)
		}.bind(this));
		
		/*el.addEvent('keydown', function(event) {
			if(!isNaN(el.get('value').toInt())) {
				if(event.key == 'up') {
					this.incrementValue(el);
					if(this.onChange) this.onChangeFunction(el)	
				} else if(event.key == 'down') {
					this.decrementValue(el);
					if(this.onChange) this.onChangeFunction(el)	
				}
			}
		}.bind(this));*/
		
		el.addEvent('blur', function(event) {
			el.isValid = this.validateInput(el);
			if(this.onChange) this.onChangeFunction(el)		
		}.bind(this));
	},
	
	/**
	 * increment input value by 1 if allowed
	 *
	 * @author Klaas <klaas[AT]efocus.nl>
	 * @since 1.0, 12 jan 2010
	 *
	 * @param element el
	 * @return void
	 */
	incrementValue: function(el) {
		if(this.maxValue && el.get('value').toInt() < this.maxValue) {
			el.set('value', el.get('value').toInt() + 1);
		} else if (this.strictBoundaries == false || !this.maxValue) {
			el.set('value', el.get('value').toInt() + 1);
		}
	},

	/**
	 * decrement input value by 1 if allowed
	 *
	 * @author Klaas <klaas[AT]efocus.nl>
	 * @since 1.0, 12 jan 2010
	 *
	 * @param element el
	 * @return void
	 */
	decrementValue: function(el) {
		if(this.minValue && el.get('value').toInt() > this.minValue) {
			el.set('value', el.get('value').toInt() - 1);
		} else if (this.strictBoundaries == false || !this.minValue) {
			el.set('value', el.get('value').toInt() - 1);
		}
	},
	
	/**
	 * disable button clicks
	 *
	 * @author Mirjam <mirjam[AT]efocus.nl>
	 * @since 1.0, 23 apr 2010
	 *
	 * @return void
	 */
	disableButtons: function() {
		this.incrementButton.removeEvent('click');
		this.decrementButton.removeEvent('click');
	},
	
	/**
	 * fire optional onChange hook function
	 *
	 * @author Klaas <klaas[AT]efocus.nl>
	 * @since 1.0, 12 jan 2010
	 *
	 * @param element el
	 * @return void
	 */
	onChangeFunction: function(el) {
		this.onChange(el);
	},
	
	/**
	 * validate input value
	 *
	 * @author Klaas <klaas[AT]efocus.nl>
	 * @since 1.0, 12 jan 2010
	 *
	 * @param element el
	 * @return boolean el.isValid
	 */
	validateInput: function(el) {
		if(this.allowEmpty && el.get('value') == '') {
			el.isValid = true;
		} else if(isNaN(el.get('value').toInt())) {
			el.isValid = false;
		} else if(this.maxValue && el.get('value').toInt() > this.maxValue) {
			el.isValid = false;
		} else if(this.minValue && el.get('value').toInt() < this.minValue) {
			el.isValid = false;
		} else {
			el.set('value', el.get('value').toInt());
			el.isValid = true;
		}
		
		return el.isValid;
	}
});
