/*
Stylish Select 0.3 - $jooo plugin to replace a select drop down box with a stylable unordered list
http://scottdarby.com/

Copyright (c) 2009 Scott Darby

Requires: $jooo 1.3

Licensed under the GPL license:
http://www.gnu.org/licenses/gpl.html
*/

var $jooo = jQuery.noConflict();
	

$jooo(document).ready(function($jooo){

	//add class of js to html tag
	$jooo('html').addClass('js');

	//create cross-browser indexOf
	Array.prototype.indexOf = function (obj, start) {
		for (var i = (start || 0); i < this.length; i++) {
			if (this[i] == obj) {
				return i;
			}
		}
	}
	
	//utility methods
	$jooo.fn.extend({
		getSetSSValue: function(value){
						if (value){
							//set value and trigger change event
							$jooo(this).val(value).change();
							return this;
						} else {
							return selText = $jooo(this).find(':selected').text();
						}
					},
		resetSS: function(){
						$jooothis = $jooo(this);
						$jooothis.next().remove();
						//unbind all events and redraw
						$jooothis.unbind().sSelect();
					}
	});

	$jooo.fn.sSelect = function(options) {
	
		return this.each(function(){
			
			var defaults = {
				defaultText: 'Please select',
				animationSpeed: 0, //set speed of dropdown
				ddMaxHeight: '' //set css max-height value of dropdown
			};

			//initial variables
			var opts = $jooo.extend(defaults, options),
				$joooinput = $jooo(this),
				$jooocontainerDivText = $jooo('<div class="selectedTxt"></div>'),
				$jooocontainerDiv = $jooo('<div class="newListSelected" tabindex="0"></div>'),
				$jooonewUl = $jooo('<ul class="newList"></ul>'),
				itemIndex = -1,
				currentIndex = -1,
				keys = [],
				prevKey = false,
				newListItems = '',
				prevented = false;
				
			//build new list
			$jooocontainerDiv.insertAfter($joooinput);
			$jooocontainerDivText.prependTo($jooocontainerDiv);
			$jooonewUl.appendTo($jooocontainerDiv);
			$joooinput.hide();
		
			//test for optgroup
			if ($joooinput.children('optgroup').length == 0){
				$joooinput.children().each(function(i){
					var option = $jooo(this).text();
					//add first letter of each word to array
					keys.push(option.charAt(0).toLowerCase());
					if ($jooo(this).attr('selected') == true){
						opts.defaultText = option;
						currentIndex = i;
					}
					newListItems += '<li>'+option+'</li>';
				});
				//add new list items to ul
				$jooonewUl.html(newListItems);
				newListItems = '';
				//cache list items object
				var $jooonewLi = $jooonewUl.children();
								
			} else { //optgroup
				$joooinput.children('optgroup').each(function(i){
				
					var optionTitle = $jooo(this).attr('label'),
						$jooooptGroup = $jooo('<li class="newListOptionTitle">'+optionTitle+'</li>');
						
					$jooooptGroup.appendTo($jooonewUl);

					var $jooooptGroupList = $jooo('<ul></ul>');

					$jooooptGroupList.appendTo($jooooptGroup);

					$jooo(this).children().each(function(){
						++itemIndex;
						var option = $jooo(this).text();
						//add first letter of each word to array
						keys.push(option.charAt(0).toLowerCase());
						if ($jooo(this).attr('selected') == true){
							opts.defaultText = option;
							currentIndex = itemIndex;
						}
						newListItems += '<li>'+option+'</li>';
					})
					//add new list items to ul
					$jooooptGroupList.html(newListItems);
					newListItems = '';
				});
				//cache list items object
				var $jooonewLi = $jooonewUl.find('ul li');
			
			}
			
			//get heights of new elements for use later
			var newUlHeight = $jooonewUl.height()+3,
				containerHeight = $jooocontainerDiv.height()+3,
				newLiLength = $jooonewLi.length;
		
			//check if a value is selected
			if (currentIndex != -1){
				navigateList(currentIndex, true);
			} else {
				//set placeholder text
				$jooocontainerDivText.text(opts.defaultText);
			}

			//decide if to place the new list above or below the drop-down
			function newUlPos(){
				var containerPosY = $jooocontainerDiv.offset().top,
					docHeight = jQuery(window).height(),
					scrollTop = jQuery(window).scrollTop();

					//if height of list is greater then max height, set list height to max height value
					if (newUlHeight > parseInt(opts.ddMaxHeight)) {
						newUlHeight = parseInt(opts.ddMaxHeight);
					}	

				containerPosY = containerPosY-scrollTop;
				if (containerPosY+newUlHeight >= docHeight){
					$jooonewUl.css({top: '-'+newUlHeight+'px', height: newUlHeight});
					$joooinput.onTop = true;
				} else {
					$jooonewUl.css({top: containerHeight+'px', height: newUlHeight});
					$joooinput.onTop = false;
				}
			}

			//run function on page load
			newUlPos();
			
			//run function on browser window resize
			$jooo(window).resize(function(){
				newUlPos();
			});
			
			$jooo(window).scroll(function(){
				newUlPos();
			});

			//positioning
			function positionFix(){
				$jooocontainerDiv.css('position','relative');
			}

			function positionHideFix(){
				$jooocontainerDiv.css('position','static');
			}
			
			$jooocontainerDivText.click(function(){
			
				if ($jooonewUl.is(':visible')){
					$jooonewUl.hide();
					positionHideFix()
					return false;
				}

				$jooocontainerDiv.focus();

				//show list
				$jooonewUl.slideDown(opts.animationSpeed);
				positionFix();
				//scroll list to selected item
				$jooonewUl.scrollTop($joooinput.liOffsetTop);

			});
			
			$jooonewLi.hover(
			  function (e) {
				var $jooohoveredLi = $jooo(e.target);
				$jooohoveredLi.addClass('newListHover');
			  },
			  function (e) {
				var $jooohoveredLi = $jooo(e.target);
				$jooohoveredLi.removeClass('newListHover');
			  }
			);

			$jooonewLi.click(function(e){
				var $joooclickedLi = $jooo(e.target);
				//update counter
				currentIndex = $jooonewLi.index($joooclickedLi);
				//remove all hilites, then add hilite to selected item
				prevented = true;
				navigateList(currentIndex);
				$jooonewUl.hide();
				$jooocontainerDiv.css('position','static');//ie
			});

			function navigateList(currentIndex, init){

				//get offsets
				var containerOffsetTop = $jooocontainerDiv.offset().top,
					liOffsetTop = $jooonewLi.eq(currentIndex).offset().top,
					ulScrollTop = $jooonewUl.scrollTop();
				
				//get distance of current li from top of list				
				if ($joooinput.onTop == true){
					//if list is above select box, add max height value
					$joooinput.liOffsetTop = (((liOffsetTop-containerOffsetTop)-containerHeight)+ulScrollTop)+parseInt(opts.ddMaxHeight);
				} else {
					$joooinput.liOffsetTop = ((liOffsetTop-containerOffsetTop)-containerHeight)+ulScrollTop;
				}
				
				//scroll list to focus on current item
				$jooonewUl.scrollTop($joooinput.liOffsetTop);
				
				$jooonewLi.removeClass('hiLite')
					.eq(currentIndex)
					.addClass('hiLite');
				var text = $jooonewLi.eq(currentIndex).text();
				//page load
				if (init == true){
					$joooinput.val(text);
					$jooocontainerDivText.text(text);
					return false;
				}
				$joooinput.val(text).change();
				$jooocontainerDivText.text(text);

			};

			$joooinput.change(function(event){
					$joootargetInput = $jooo(event.target);
					//stop change function from firing 
					if (prevented == true){
						prevented = false;
						return false;
					}
					$jooocurrentOpt = $joootargetInput.find(':selected');
					currentIndex = $joootargetInput.find('option').index($jooocurrentOpt);
					navigateList(currentIndex, true);
				}
			);
			
			//handle up and down keys
			function keyPress(element) {
				//when keys are pressed
				element.onkeydown = function(e){
					if (e == null) { //ie
						var keycode = event.keyCode;
					} else { //everything else
						var keycode = e.which;
					}
					
					//prevent change function from firing
					prevented = true;

					switch(keycode)
					{
					case 40: //down
					case 39: //right
						incrementList();
						return false;
						break;
					case 38: //up
					case 37: //left
						decrementList();
						return false;
						break;
					case 33: //page up
					case 36: //home
						gotoFirst();
						return false;
						break;
					case 34: //page down
					case 35: //end
						gotoLast();
						return false;
						break;
					case 13:
					case 27:
						$jooonewUl.hide();
						positionHideFix();
						return false;
						break;
					}

					//check for keyboard shortcuts
					keyPressed = String.fromCharCode(keycode).toLowerCase();
					var currentKeyIndex = keys.indexOf(keyPressed);
					if (typeof currentKeyIndex != 'undefined') { //if key code found in array
						++currentIndex;
						currentIndex = keys.indexOf(keyPressed, currentIndex); //search array from current index
						if (currentIndex == -1 || currentIndex == null || prevKey != keyPressed) currentIndex = keys.indexOf(keyPressed); //if no entry was found or new key pressed search from start of array
						navigateList(currentIndex);
						//store last key pressed
						prevKey = keyPressed;
						return false;
					}
				}
			}

			function incrementList(){
				if (currentIndex < (newLiLength-1)) {
					++currentIndex;
					navigateList(currentIndex);
				}
			}

			function decrementList(){
				if (currentIndex > 0) {
					--currentIndex;
					navigateList(currentIndex);
				}
			}

			function gotoFirst(){
				currentIndex = 0;
				navigateList(currentIndex);
			}
			
			function gotoLast(){
				currentIndex = newLiLength-1;
				navigateList(currentIndex);
			}

			$jooocontainerDiv.click(function(){
				keyPress(this);
			});

			$jooocontainerDiv.focus(function(){
				$jooo(this).addClass('newListSelFocus');
				keyPress(this);
			});
			
			//hide list on blur
			$jooocontainerDiv.blur(function(){
			   $jooo(this).removeClass('newListSelFocus');
			   $jooonewUl.hide();
			   positionHideFix();
			});

			//add classes on hover
			$jooocontainerDivText.hover(function(e) {
				var $jooohoveredTxt = $jooo(e.target);
				$jooohoveredTxt.parent().addClass('newListSelHover');
			  }, 
			  function(e) {
				var $jooohoveredTxt = $jooo(e.target);
				$jooohoveredTxt.parent().removeClass('newListSelHover');
			  }
			);

			//reset left property and hide
			$jooonewUl.css('left','0').hide();
			
		});
	  
	};

})(jQuery);