/* =================================================================================================================================================================== 
* 	Sony Style jcCustomSelect Custom Select box Class
* 	AUTHOR: Jonathan Cheung
* 
*	PRECONDITION:
*		- Prototype.js, Scriptaculous.js (including effects.js)
*		- ss_custom_select.css
* 	OPTIONAL:
*		- Really easy field validation (http://tetlaw.id.au/view/javascript/really-easy-field-validation)
*	
* 	NOTES:
*		- Custom select box done the right way. 	
* 		- This custom select box generates the list from existing Select input and parses it into an UL list
* 		- Custom styles can be applied. (Basic styles are in ss_custom_select'
*	USAGE:
*		- On page load instantiate the custom lise by ID name
* 		new jcCustomSelect(IDNAME, OPTIONS)
*		IDNAME - the ID name of the Selectbox
*		OPTIONS - A JSON Object of the parameters 
*				(currently you can only pass 'formValidation' - the instance of the 'Really easy field validation')
*		e.g. var stateSelect = new jcCustomSelect('state', {formValidation:registrationFormValidation});
* 			
* ===================================================================================================================================================================
*/

var jcCustomSelect = Class.create();

jcCustomSelect.prototype = {
	
	//Class Constructor
	initialize: function(idName, options){
		this.options = Object.extend({
			formValidation: false
		
		}, options || {});
		
		
		this.idName = idName;
		var element = $(idName);
		var newDiv = document.createElement('A');
		
		var newInput  = document.createElement('INPUT');
		var newSelect = document.createElement('UL');
		
		newSelect.id = element.id+"-jcCustomSelectList";
							
		//Function to transfer all Attirbute to the new UL list
		var elementAttributes = $A($(element).attributes);

		this.parseAttributeTo(element, newDiv);
	
		var selectedText = element.options[element.selectedIndex].innerHTML;
		var selectedValue = element.options[element.selectedIndex].value;
		
		for (var i in element.childNodes){
			var thisElement = element.childNodes[i];
			if (thisElement.nodeType == 1){
				
				var newOption = document.createElement('LI');
				
				var newHREF = document.createElement('A');
				newHREF.href = "#";
				newHREF.innerHTML = thisElement.innerHTML
				$(newHREF).writeAttribute("tabIndex",-1);
				
				newOption.appendChild(newHREF);
				$(newOption).writeAttribute("tabIndex",0)

				//Function to transfer all Attirbute to the new LI list
				this.parseAttributeTo(thisElement, newOption);
				
				//Appending click/rollover/rollout action
				Event.observe($(newOption), 'keydown', this.onKeyDownOption.bind(this));
				Event.observe($(newHREF), 'click', this.onClickOptionHREF.bind(this));
				Event.observe($(newHREF), 'mouseover', this.onOverOptionLink.bind(this));
				Event.observe($(newHREF), 'mouseout', this.onOutOptionLink.bind(this));
				Event.observe($(newOption), 'mouseover', this.onOverOptionHREF.bind(this));
				Event.observe($(newOption), 'focus', this.onOverOptionHREF.bind(this));
				Event.observe($(newOption), 'mouseout', this.onOutOptionHREF.bind(this))
				Event.observe($(newOption), 'blur', this.onOutOptionHREF.bind(this))

				$(newSelect).addClassName('NotActive')
				$(newSelect).addClassName('jcCustomSelectList');
				$(newSelect).writeAttribute("tabIndex", 0);
				newSelect.appendChild(newOption);	
			}
		}
		
		// Select the input the selected value
		$(newDiv).innerHTML =selectedText;
		$(newDiv).value = selectedValue;
		
		
		$(newDiv).addClassName('jcCustom');
		$(newSelect).addClassName('jcCustom');	
		
		//Initialize the input value
		newInput.id = newDiv.id+"-jcCustom";
		newInput.name = newDiv.id;
		newInput.value = newDiv.value;
		newInput.type="hidden";
		if (element.hasClassName('required-custom') || element.hasClassName('required')) $(newInput).addClassName('required');
		//Used in Validation.js to do special styling
		$(newInput).addClassName('jcCustom');
		
		element.parentNode.insertBefore(newInput,element);
		element.parentNode.insertBefore(newSelect,newInput);
		element.parentNode.insertBefore(newDiv,newSelect);
		
		
		//Tab Index Fixes
		$($(newDiv).parentNode).writeAttribute("tabIndex", 0);
		$(newDiv).writeAttribute("tabIndex", 0);
		
		Event.observe($(newDiv).parentNode, 'keydown', this.onKeyDownSelect.bind(this));
		
		//Remove the element.
		element.parentNode.removeChild(element);
		
		//append the select box
		Event.observe($(newDiv), 'click', this.onClickSelect.bind(this));
		Event.observe($(newDiv), 'mouseover', this.onOverSelect.bind(this));
		Event.observe($(newDiv), 'mouseout', this.onOutSelect.bind(this));
		//Taking this out for MQC 1322
		//Event.observe($(newSelect), 'mouseout', this.onOutList.bind(this));
		
		Event.observe(document.body,'click',this.detectBodyClick.bind(this));
	},

	detectBodyClick: function(e) {
		//if the body is clicked and the event did not occur on an element with class==jcCustom
		if(!(Event.findElement(e)).hasClassName('jcCustom')) {
			//hide all unexpanded select boxes to avoid overlapping.
			$$('a.jcCustom').invoke('up').invoke("setStyle", {zIndex:0});
			$$('ul.jcCustom').invoke("addClassName", 'NotActive');
		}
	},
	// DOM Level 2 events for the new Select 
	
	onClickSelect: function(e){
		$(this.idName).next().toggleClassName('NotActive');
		this.hideOtherSelectBoxes();
		Event.stop(e);
	},
	
	onKeyDownSelect: function(e){
		if (e.keyCode == 13) {
			 $(this.idName).next().toggleClassName('NotActive');
			 this.hideOtherSelectBoxes();
		}else{
			//If we are not pressing "Enter" We try to select the values in the dropdown
			
			//If the selectedc value has the same starting character on the pressed key, we try to get the next available element
			if($(this.idName).innerHTML.substring(0,1).toUpperCase() == String.fromCharCode(e.keyCode).toUpperCase()){
				
				//Find the first selected value;			
				var elementVar = this.findTheStateByAlpha(String.fromCharCode(e.keyCode));
				
				if (elementVar!=null){
					// e
					while (elementVar!=null && elementVar.parentNode.next().readAttribute('value') != elementVar.readAttribute('value')){
						elementVar = elementVar.next();
					}
					
					if(this.firstCharOfValue(elementVar.next()) == String.fromCharCode(e.keyCode).toUpperCase()){
						elementVar = elementVar.next();
					}else{
						elementVar = this.findTheStateByAlpha(String.fromCharCode(e.keyCode));						
					}
					//Select the element
					if (elementVar){
						this.optionSelected(elementVar);
						if (!$(this.idName).next().hasClassName('NotActive')) elementVar.focus();
					}else{
						$(this.idName).focus();
					}
				}
			}else{
					// Else We will have to select the first available matching select option.
					var elementVar = this.findTheStateByAlpha(String.fromCharCode(e.keyCode));
					if (elementVar) {
							this.optionSelected(elementVar);
							if (!$(this.idName).next().hasClassName('NotActive')) elementVar.focus();
					}else{
						$(this.idName).focus();
					}
			}
			
		}
	},
	//Returns the uppercase of the first character of the specified prototype element
	firstCharOfValue: function(element){ 
		if ($(element) != null){
			var currentelement = $(element).readAttribute('value') || null;
			if (currentelement) {
				return currentelement.substring(0,1).toUpperCase();
			}else {
				return false;
			}
		}
	},
	findTheStateByAlpha: function(alphaChar){
		var inputArray = $$('#'+this.idName+'-jcCustomSelectList li');
		var debugOutput = ''
		for (var i =1; i < inputArray.length; i++){
			try{
				
				var inputName = inputArray[i].select('a')[0].innerHTML;
				if(inputName != null){
					debugOutput +=inputName.substring(0,1) + "\n";
					if (inputName.substring(0,1).toLowerCase() == alphaChar.toLowerCase())
						return inputArray[i];
				}
			}catch(e){
				alert("error "+i)
			}
		}
		return null;
		
	
	},
	
	onOverSelect: function (e){
		var thisElement = Event.element(e);
	},
	onOutSelect: function (e){
		var thisElement = Event.element(e);
	},
	
	// DOM Level 2 events for the new List
	onOutList: function(e){
		var thisElement = Event.element(e).parentNode;
		if (Position.within(thisElement, Event.pointerX(e), Event.pointerY(e))  == false && $(thisElement).hasClassName('jcCustomSelectList')){
			$(thisElement).addClassName('NotActive');
		}
	},

	// DOM Level 2 events for the new list items 
	onKeyDownOption: function(e){
		if (e.keyCode == 13){
			var thisElement = Event.element(e);
			// Toggle the UL "NotActive" class
			thisElement.toggleClassName('NotActive');
			this.optionSelected(thisElement);
			thisElement.parentNode.parentNode.focus();
		}
	},
	onClickOptionHREF: function(e){
		var thisElement = Event.element(e).parentNode;
		// Toggle the UL "NotActive" class
		thisElement.parentNode.toggleClassName('NotActive');
		this.optionSelected(thisElement);
		Event.stop(e);
	},
	onOverOptionLink: function (e){
		var thisElement = Event.element(e);
		//alert(thisElement)
		$(thisElement.parentNode).addClassName('rollOver');
	},
	onOutOptionLink: function (e){
		var thisElement = Event.element(e);
		//alert(thisElement)
		$(thisElement.parentNode).removeClassName('rollOver');
	},	
	onOverOptionHREF: function (e){
		var thisElement = Event.element(e);
		//alert(thisElement)
		$(thisElement).addClassName('rollOver');
	},
	onOutOptionHREF: function (e){
		var thisElement = Event.element(e);
		$(thisElement).removeClassName('rollOver');
	},
	
	optionSelected: function (thisElement){
		thisElement.parentNode.previous().innerHTML = thisElement.getElementsBySelector('a')[0].innerHTML;
		
		var newValue = (!$(thisElement).getAttribute('value') )? '':thisElement.getAttribute('value');
		//thisElement.parentNode.previous().writeAttribute('value', newValue);
		thisElement.parentNode.previous().value = newValue;
		$(thisElement.parentNode.previous().id+"-jcCustom").value = newValue;
		thisElement.parentNode.previous().focus();

		
		if (
		(this.options.formValidation !=false && this.options.formValidation != undefined) && 
		((this.options.formValidation.options.immediate) || (this.options.formValidation.options.onSubmitImmediate && this.options.formValidation.calledOnce))
		){
			//Bridging to use Validation.js Prototype
			var useTitles = this.options.formValidation.options.useTitles;
			var callback = this.options.formValidation.options.onElementValidate;
			this.options.formValidation.validate($(thisElement.parentNode.previous().id+"-jcCustom"),{useTitle : useTitles, onElementValidate : callback});
		}

	},
	
	parseAttributeTo: function(element, newElement){
		var attributeList =  $(element).attributes;
		if ($(element).id) $(newElement).id= $(element).id;
		if ($(element).className) $(newElement).className= $(element).className;
		if ($(element).name) $(newElement).name= $(element).name;
		if ($(element).rel) $(newElement).setAttribute('rel', $(element).getAttribute('rel'));
		if ($(element).value) $(newElement).setAttribute('value', $(element).value.toString());
	},
	
	
	// Hide other select boxes so they don't overlap
	
	hideOtherSelectBoxes: function(){
			if (!$(this.idName).next().hasClassName('NotActive')){
				//hide all unexpanded select boxes to avoid overlapping.
				$$('a.jcCustom').invoke('up').invoke("setStyle", {zIndex:0});
				$$('ul.jcCustom').invoke("addClassName", 'NotActive');
				$(this.idName).up().setStyle({zIndex:1});
				$(this.idName+'-jcCustomSelectList').removeClassName('NotActive');
			}else{
				$$('a.jcCustom').invoke('up').invoke("setStyle", {zIndex:0});
				$$('ul.jcCustom').invoke("addClassName", 'NotActive');
			}
	}
	
	
	
}