/**
* @file elSelect.js
* @inspired by  http://www.cult-f.net/2007/12/14/elselect/
* @author Mark Reilly
* @site  http://www.rindstudios.com/
* @date July 2010
* 
*/

var elSelectZindex = 500;
var elSelect = new Class({
	options: {
		container: false,
		baseClass : 'elSelect',
		selectOptions : [],
		selectInput : false,
		selectedOption : false,
		selectProperties : false,
		swap : false,
		hover : false,
		max : 10
	},
	hiddenInput : false,
	optionsWrap : false,
	SelectWrap  : false,
	currrentInput : false,
	focusInput : false,
	selectedOpt : false,
	inputEntered : false,
	container : false,
	/*
	pass the options,
	create html and inject into container
	*/
	initialize: function(options){		
		this.setOptions(options);
		this.pullOptions();
	},
	
	pullOptions: function() {
		if($$('#'+this.options.container+' select')) {
			/*
			 * Get all Options
			 */
			enOptions = [];
			this.container = $$('#'+this.options.container+' select');
			/*
			 * Get the selected Option
			 */
			if(!this.options.selectedOption) {
				this.options.selectedOption = $$('#'+this.options.container+' select').get('value');
			}
			
			$$('#'+this.options.container+' option').each(function(selOption) {
				toptions = selOption.getProperties('id', 'name', 'class', 'text');
				toptions.optionValue = selOption.get('value');
				enOptions.push(toptions);
			});
			this.options.selectOptions = enOptions;
		
			/*
			 * Get Select Attributes
			 */
			 this.options.selectProperties = $$('#'+this.options.container+' select').getProperties('id', 'class','value');
			 this.options.selectInput = $$('#'+this.options.container+' select').get('name');
			 
			/*
			 * Destroy the select box
			 */
			$$('#'+this.options.container+' select').destroy();
		}
		
		/*
		 * Build Options
		 */
		this.buildInput();
	},
	
	buildInput: function() {
		this.SelectWrap = new Element('div', {'class': this.options.baseClass, 'style': 'z-index: '+elSelectZindex});
		elSelectZindex--;
		
		this.SelectWrap.inject($(this.options.container));
		
		this.hiddenInput = this.buildHiddenInput();
		//Filter options input
		this.focusInput = this.hiddenFocus();
				//Prevent Closing in IE if the user is just scrolling
		this.SelectWrap.addEvents({
				'mouseenter' : function() {
					this.focusInput.removeEvents('blur');
					this.log('removed blur');
				}.bind(this),
				'mouseleave' : function() {
					this.focusInput.addEvents({'blur': function() {  del = function() {   this.startFunctions(); }.bind(this).delay(300); }.bind(this) });
					this.log('readded blur');
				}.bind(this)
		});
		//The tab landing input redirects to focusInput
		this.falseSelect = this.inlineInput();
		this.optionsWrap = new Element('div', {'class': this.options.baseClass+'-options', 'style' : 'z-index: '+elSelectZindex});
		elSelectZindex--;
		
		this.buildOptions();
		this.optionsWrap.inject(this.SelectWrap);
		
		this.hiddenInput.inject(this.SelectWrap);
		this.falseSelect.inject(this.SelectWrap);
		this.focusInput.inject(document.body);
		/*
		 * Inject the Input
		 */
		this.SelectWrap.addEvent('click', function() {
			if(!this.SelectWrap.hasClass(this.options.baseClass+'-open')) {
				classname = this.options.baseClass+'-open';
				this.SelectWrap.addClass(classname);
				this.focusInput.set('value', '');
				this.focusInput.focus();
				if(this.options.selectOptions.length > this.options.max) {
					
					var fulhe = this.optionsWrap.measure(function(){
					    return this.getSize();
					}).y;
					var toh = fulhe/this.options.selectOptions.length*this.options.max;
					this.optionsWrap.setStyles({'overflow-y': 'scroll', 'height': toh});
					this.options.max = this.options.selectOptions.length;
				}
			} else {
				this.focusInput.blur();
			}
		}.bind(this));
		var cord = this.SelectWrap.getCoordinates();
		this.focusInput.setStyles({'left': cord.left, 'top': cord.top, 'position': 'absolute'});
		this.startFunctions();
	},
	
	/*
	 * That hidden input that holds the value
	 */
	buildHiddenInput: function() {
		var inputName = this.options.selectInput;
		var opts = this.options.selectProperties[0];
		opts.type = 'hidden';
		opts.name = inputName;
		var inputElement = new Element('input', opts);
		return inputElement;
	},
	/*
	 * Take the options 
	 * and build a div around them 
	 */
	buildOptions: function() {
		/*
		 * Options wrap
		 */
		
		var optArray = [];
		
		this.options.selectOptions.each(function(existingOption, ind) {
			var newOption = new Element('div');
			newOption.store('optionValue', existingOption.optionValue);
			newOption.store('orderIndex', ind);
			//unset vaule so it won't be adopted into the HTML tag
			existingOption.optionValue = null;
			
			newOption.setProperties(existingOption);
			newOption.addClass(this.options.baseClass+'-option');
			var setOption = this.setOption.bind(this);
			
			var optfx = new Fx.Morph(newOption, {'link': 'cancel'});
			newOption.store('mouseFx', optfx);
			var opthover = this.options.hover;
			newOption.addEvents({
				'click': function() { 
					this.setOption(newOption);
				}.bind(this),
				'mouseenter': function() {
					this.options.selectOptions.each(function(existingOption, ind) {
						var mfx = existingOption.retrieve('mouseFx');
						mfx.start(opthover.mouseleave);
					});
					optfx.start(opthover.mouseenter);
					this.selectedOpt = newOption; 
				}.bind(this)
			});
			optfx.set(opthover.mouseleave);
			
			newOption.inject(this.optionsWrap);
			optArray.push(newOption);
			if(newOption.retrieve('optionValue') == this.options.selectedOption) {
				this.setOption(newOption);
			}
			
		}, this);
		this.options.selectOptions = optArray;
	},
	
	/*
	 * Change option around
	 */
	setOption: function(inputEl) {
		if(this.currrentInput !== false) {
			if(this.options.swap) {
				ind = this.currrentInput;
				this.options.selectOptions[ind].show();
			}
			this.SelectWrap.getFirst().destroy();
		}
		
		this.hiddenInput.set('value', inputEl.retrieve('optionValue'));
		this.hiddenInput.fireEvent('change');
		
		this.currrentInput = inputEl.retrieve('orderIndex');
		inputEl.clone().setStyle('background-color', 'transparent').inject(this.SelectWrap, 'top');
		if(this.options.swap) {
			inputEl.hide();
		}
		this.focusInput.set('value', inputEl.get('text'));
		del = function() {   this.startFunctions(); this.log('hide'); }.bind(this).delay(20);
	},
	
	startFunctions : function() {
		this.optionsWrap.hide();
		this.SelectWrap.removeClass(this.options.baseClass+'-open');
		
		this.inputEntered = false;
	},
	
	hiddenFocus : function() {
		var h = new Element('input', {'name': 'elselect-hiddenfocus', 'type': 'text', 'styles': {'margin-left': '-99999px'}});
		var optE = (Browser.Engine.trident || Browser.Engine.webkit) ? 'keydown' : 'keypress';
		var del;
		h.addEvents({
			'blur' : function() { del = function() {   this.startFunctions(); }.bind(this).delay(300); }.bind(this),
			'focus' : function() { $clear(del); this.optionsWrap.show();  }.bind(this),
			'keyup' : this.onCommand.bind(this)
		});

		return h;
	},
	
	inlineInput : function() {
		var ih = new Element('input', {'name': 'elselect-inline', 'type': 'text', 'styles': {'margin-left': '-99999px'}});
		
		ih.addEvents({
			//'blur' : function() { this.focusInput. }.bind(this),
			'focus' : function() { if(!this.inputEntered) { this.focusInput.focus(); this.inputEntered = true; } }.bind(this)
		});
		
		return ih;
	},
	
	onCommand : function(e) {
	
		//if (!e && this.focussed) return this.prefetch();
		if (e && e.key && !e.shift) {
			switch (e.key) {
				case 'enter':
					if(this.selectedOpt) {
						
						this.selectedOpt.fireEvent('click');
						this.falseSelect.focus();
					}
					return false;
				break;
				case 'up': 
					if(this.selectedOpt) {
						if(this.selectedOpt.getPrevious()) {
							var ele = this.selectedOpt.getPrevious();
						} else {
							var ele = this.options.selectOptions.getLast();
						}
					} else {
						var ele = this.options.selectOptions.getLast();
					}
					this.focusInput.set('value', ele.get('text'));
					this.highlightOption();
					return false;
				break;
				case 'down':
					if(this.selectedOpt) {
						if(this.selectedOpt.getNext()) {
							var ele = this.selectedOpt.getNext();
						} else {
							var ele = this.options.selectOptions[0];
						}
					} else {
						var ele = this.options.selectOptions[0];
					}
					this.focusInput.set('value', ele.get('text'));
					this.highlightOption();
					return false;
				case 'esc':
					this.optionsWrap.hide();
				break;
				default:
					this.highlightOption();
			}
		}
		return false;		
	},
	
	highlightOption : function() {
		/*
		 * Loop through each option till its found
		 */
		var optValue = this.focusInput.get('value');
		this.log(optValue);
		
		this.selectedOpt = false;
			this.options.selectOptions.each(function(existingOption, ind) {
			
				var strlen = optValue.length;
				if(existingOption.get('text').toLowerCase().substr(0, strlen) == optValue.toLowerCase() && strlen != 0) {
					 if(!this.selectedOpt) {
						existingOption.fireEvent('mouseenter'); 
						this.selectedOpt = existingOption; 
					}
				}
			}, this);
			if(!this.selectedOpt) { this.focusInput.set('value', '');  }
	},
	log: function() {
		if (window.console && console.info) console.info.apply(console, arguments);
	}
});
elSelect.implement(new Events);
elSelect.implement(new Options);

