(function($) {

	$.fn.selectbox = function(settings) {
		if(!settings) {
			settings = {};
		}
				
		var config = {
			'className' : settings.className || 'select',
			'selectedClassName' : settings.selectedClassName || 'selected'
		};

		this.each(function() {		
			var $_this = $(this);
			var id = this.id;
			
			var maxIndex = $_this.children('option').size() - 1;
			var $selectedElement = $_this.children('option:selected');

			var selectedIndex = $_this[0].selectedIndex;
			var originalSelectedIndex = selectedIndex;
			var selectedText = $selectedElement.text();
			var selectedVal = $selectedElement.val();
			
			var $box;
			var $options;
			var $text;
			var $arrow;
			
			var found = false;
			var hoverOptions = false;
			var eventsBound = false;
			var tabPressed = false;
			var textFocus = false;
			
			var options = [];
			
			$_this.children('option').each(function(i) {
				var $self = $(this);
				
				var text = $self.text();
				
				if(i == selectedIndex) {
					$self.addClass(config.selectedClassName);
				}
				
				if(text === '') {
					text = '&nbsp;';
				}
				
				options.push('<li class="' + $self.attr('class') + '" val="' + $self.val() + '" id="' + id + '_' + $self.val() + '">' + text + '</li>');
			});
			
			$_this.hide().before('<div id="' + id + '_select" class="'+config.className+'"><span tabIndex="0" id="' + id + '_text" class="'+config.className+'_text" val="'+selectedVal+'">'+selectedText+'</span><div id="' + id + '_options" class="'+config.className+'_options"><ul>'+options.join("\n")+'</ul></div></div>');
			
			$box = $('#' + id + '_select');
			$options = $('#' + id + '_options');
			$text = $('#' + id + '_text');
			//$arrow = $('#' + id + '_arrow');
			
			/*$arrow.click(function() {
				var size = $options.children('ul').children().size();
				$options.children('ul').height(size * 22);
			});*/
			//$text[0].focus = function() {};
			//console.log(document.getElementById('logo').prototype.focus);
			
			var $selectedElementLi = $options.children('ul').children('li.'+config.selectedClassName);
			
			var width = parseInt($options.outerWidth(), 10) - parseInt($options.width(), 10);
			
			$options.css('min-width', $box.width() - width + 'px');
			
			function open() {
				//console.log('open');
				// 1. Bind events
				//bindEvents();
				// 2. Show select box
				$options.show();
				//$arrow.show();
			}
			
			function close() {
				//console.log('close');
				// TODO: all this function
				// 1. Hide select box
				// 2. Check if current value is the same as value when it was open. If not, call the change event
				// 3. Remove bound keypress and document click (close when click elsewhere) events
				
				//unbindEvents();
				$options.hide();
				//$arrow.hide();
			}
			
			function select($this) {
				//console.log('select');
				// 1. Set new Text
				// 2. Set all new values (index, val, etc)
				//console.log(selectedIndex);
				//console.log($this.attr('val'));
				$selectedElementLi = $this.addClass(config.selectedClassName).siblings().removeClass(config.selectedClassName).end();
				selectedText = $selectedElementLi.text();
				selectedIndex = $this.parent().children().index($this);
				$text.text(selectedText).attr('val', $selectedElementLi.attr('val'));
			}
			
			function moveUp() {
				//console.log('moveUp');
				// 1. Move highlighted up one if possible
				if(selectedIndex > 0) {
					selectedIndex--;
					select($selectedElementLi.prev());
				}
			}
			
			function moveDown() {
				//console.log('moveDown');
				// 1. Move highlighted down if possible
				if(selectedIndex < maxIndex) {
					selectedIndex++;
					select($selectedElementLi.next());
				}
			}
			
			function highlightHover($this) {
				//console.log('highlightHover');
				$selectedElementLi.removeClass(config.selectedClassName);
				$selectedElementLi = $this.addClass(config.selectedClassName);
				selectedIndex = $this.parent().children().index($this);
			}
			
			function bindEvents() {
				//console.log('bindEvents');
				// 1. Bind keypress (up, down, left, right, enter, ABC123) and document click (close when click elsewhere) events
				$(document).bind('keydown.select', function(e1) {
					var code = (e1.keyCode ? e1.keyCode : e1.which);

					if(code === 38 || code === 37) {
						// up, left
						moveUp();
						
						e1.preventDefault();
					}
					else if(code === 40 || code === 39) {
						// down, right
						moveDown();
						
						e1.preventDefault();
					}
					else if(code === 13) {
						// enter
						var $self = $options.children('ul').children('li:eq('+selectedIndex+')');
						select($self);
						close();
						callChangeEvent();
						e1.preventDefault();
					}
					else if((code > 47 && code < 58) || (code > 96 && code < 123) || (code > 64 && code < 91)) {
						var $findByChar = $selectedElementLi.nextAll('li');
						found = false;
						$findByChar.each(function() {
							
							if($(this).text().charAt(0).toLowerCase() === String.fromCharCode(code).toLowerCase()) {
								select($(this));
								found = true;
								return false;
							}
						});
						
						// if not found, start from beginnning
						if(found === false) {
							//console.log('not found');
							$findByChar = $selectedElementLi.parent().children('li');
							
							$findByChar.each(function(i) {
								//console.log(i);
								//console.log(selectedIndex);
								if(i === selectedIndex) {
									return false;
								}
								
								if($(this).text().charAt(0).toLowerCase() === String.fromCharCode(code).toLowerCase()) {
									select($(this));
									found = true;
									return false;
								}
							});
						}
					}
					else if(code == 9) {
						tabPressed = true;
					}

				}).bind('click.select', function(e1) {
					if($options.is(':visible')) {
						close();
					}
				}); // No longer necessary because of the blur implementation
				
				$options.children('ul').bind('mouseenter.select', function() {
					//console.log('ul mouseenter');
					hoverOptions = true;
				}).bind('mouseleave.select', function() {
					//console.log('ul mouseleave');
					hoverOptions = false;
				}).children('li').bind('mouseenter.select', function() {
					//console.log('li mouseenter');
					highlightHover($(this));
				}).bind('click.select', function(e1) {
					var $self = $(this);
					selectedIndex = $self.parent().children().index($self);
					
					select($self);
					close();
					//console.log('option click callChangeEvent');
					callChangeEvent();
					e1.stopPropagation();
				});
			}
			
			function unbindEvents() {
				//console.log('unbindEvents');
				$(document).unbind('keydown.select').unbind('click.select');
				$options.children('ul').unbind('mouseenter.select').unbind('mouseleave.select').children('li').unbind('mouseenter.select').unbind('click.select');
			}
			
			function callChangeEvent() {
				//console.log('originalSelectedIndex: '+ originalSelectedIndex + ' selectedIndex: ' + selectedIndex + ' textval: ' + $text.attr('val') + ' selectedVal' + $selectedElementLi.attr('val'));
				if(originalSelectedIndex !== selectedIndex && $text.attr('val') == $selectedElementLi.attr('val')) {
					//$_this.val($selectedElementLi.attr('val'));
					//console.log('change');
					originalSelectedIndex = selectedIndex;
					
					$_this.val($selectedElementLi.attr('val')).change();
				}
				
				selectedIndex = originalSelectedIndex;
				
				$selectedElement = $_this.children('option:selected');
				$selectedElementLi = $options.children('ul').children('li:eq('+selectedIndex+')').addClass(config.selectedClassName).siblings().removeClass(config.selectedClassName).end();
			}
			
			$box.bind('click.select', function(e) {
				//console.log('box click');
				if($options.is(':visible')) {
					// hide it
					close();
					if(eventsBound) {
						unbindEvents();
						eventsBound = false;
					}
					//console.log('box click close callChangeEvent');
					callChangeEvent();
				}
				else {
					//$(this).focus();
					open();
					if(!eventsBound) {
						bindEvents();
						eventsBound = true;
					}
				}
				
				e.stopPropagation();
			});
			
			$text.bind('focus.select', function(e) {
				//console.log('box focus');
				//alert('focus');
				$box.addClass('focused');
				if(!eventsBound) {
					bindEvents();
					eventsBound = true;
				}
			}).bind('blur.select', function(e) {
				//console.log('box blur');
				//alert('blur');
				if(!hoverOptions || tabPressed === true) {
					$box.removeClass('focused');
					if(eventsBound) {
						unbindEvents();
						eventsBound = false;
					}
					//console.log('blur callChangeEvent');
					close();
					callChangeEvent();
					tabPressed = false;
				}
			
			});
			
			/*$text.bind('focus', function(e) {
				console.log('text focus');
				$box.focus();
			});*/
			
		});

		return this;
	};
	
	$.fn.selectbox.refresh = function() {
		//alert('sdf');
	};

})(jQuery);