(function($) {
	/*
		TODO: Max number before scroll
		TODO: API functions
	*/
	
	var api = {
		'refresh' : function(elements, data) {
			return elements.each(function() {
				//console.log('refresh ' + this.id);
				$('#'+this.id+'_select').remove();
				$(this).selectbox();
			});
		},
		'addOption' : function(elements, data) {
			return elements.each(function() {
				//console.log('addOption ' + this.id);
			});
		},
		'setOptions' : function(elements, data) {
			return elements.each(function() {
				//console.log('setOptions ' + this.id);
			});
		}
	};
	
	var methods = {
		'open' : function($optionsDiv) {
			//console.log('open ' + $optionsDiv[0].id);
			return $optionsDiv.show();
		},
		'close' : function($optionsDiv) {
			return $optionsDiv.hide();
		},
		'select' : function($option, $text, selectedClassName) {
			//console.log('select');
			
			$option.addClass(selectedClassName).siblings().removeClass(selectedClassName);
			$text.text($option.text());
			return $option.attr('index');
		},
		'moveUp' : function(selectedIndex, $ulOptions, $text, selectedClassName) {
			//console.log('moveUp');
			
			if(selectedIndex > 0) {
				return this.select($ulOptions.children('li.'+selectedClassName).prev(), $text, selectedClassName);
			}
			
			return selectedIndex;
		},
		'moveDown' : function(selectedIndex, maxIndex, $ulOptions, $text, selectedClassName) {
			//console.log('moveDown');
			
			if(selectedIndex < maxIndex) {
				return this.select($ulOptions.children('li.'+selectedClassName).next(), $text, selectedClassName);
			}
			return selectedIndex;
		},
		'highlightHover' : function($option, selectedClassName) {
			//console.log('highlightHover');
			
			$option.addClass(selectedClassName).siblings().removeClass(selectedClassName);
		},
		'unbindEvents' : function() {
			//console.log('unbindEvents');
			
			$(document).unbind('keydown.select').unbind('click.select');
		},
		'callChangeEvent' : function($select, indexWhenOpen, currentIndex) {
			//console.log('callChangeEvent');
			
			if(indexWhenOpen !== currentIndex) {
				$select[0].selectedIndex = currentIndex;
				$select.change();
			}
			
			return currentIndex;
		}
	};

	$.fn.selectbox = function(options, data) {
		if(typeof(options) === 'string') {
			// Accessing API function
			if(!data) {
				data = {};
			}
			
			if(typeof(api[options]) !== 'function') {
				return this;
			}
			return api[options](this, data);
		}
	
		var opts = $.extend({}, $.fn.selectbox.defaults, options);
		var selectList = [];
	
		return this.each(function() {
			var $this = $(this);
			var id = this.id || this.name + 'FakeID';
			
			var $selectOptions = $this.children('option');
			var selectedIndex = this.selectedIndex;
			var selectedIndexWhenOpen = selectedIndex;
			var maxIndex = $selectOptions.size() - 1;
			
			var selectedText;
			
			var eventsBound = false;
			var docCloseEventBound = false;
			var textFocused = false;
			var tabPressed = false;
			var hoverOptions = false;
			var hoverBox = false;
			
			var options = [];
			
			// Creating LI list of options
			$selectOptions.each(function(i) {
				var $self = $(this);
				var text = $self.text();
				
				if(i === selectedIndex) {
					$self.addClass(opts.selectedClassName);
					selectedText = text;
				}
				if(i === maxIndex) {
					$self.addClass('last');
				}
				
				if(text === '') {
					text = '&nbsp;';
				}
				
				options.push('<li index="'+i+'" class="' + $self.attr('class') + '">' + text + '</li>');
			});
			
			$this.hide().before('<div id="' + id + '_select" class="'+opts.className+'"><div tabIndex="0" id="' + id + '_text" class="'+opts.className+'_text">'+selectedText+'</div><div id="' + id + '_options" class="'+opts.className+'_options"><ul id="' + id + '_list_options">'+options.join("\n")+'</ul></div></div>');
			
			var $box = $('#' + id + '_select');
			var $options = $('#' + id + '_options');
			var $ulOptions = $('#' + id + '_list_options');
			var $text = $('#' + id + '_text');
			var $document = $(document);
			
			selectList.push('#' + id + '_text');
			
			var width = parseInt($options.outerWidth(), 10) - parseInt($options.width(), 10);
			//$options.css('min-width', $box.width() - width + 'px');
			
			$box.bind('click.select', function(e) {
				$.each(selectList, function(i, v) {
					if(v !== '#' + id + '_text') {
						$(v).blur();
						//console.log(v);
					}
				});
			
				if($options.is(':visible')) {
					methods.close($options);
					selectedIndexWhenOpen = methods.callChangeEvent($this, selectedIndexWhenOpen, selectedIndex);
				}
				else {
					
					if(!eventsBound) {
						$box.addClass('focused');
						//console.log('binding ' + id);
						bindEvents();
						eventsBound = true;
					}
					methods.open($options);
				}
				
				//if(e.target.id == $box[0].id) {
					if(!docCloseEventBound) {
						bindDocCloseEvent();
						docCloseEventBound = true;
					}
				//}
				
				e.stopPropagation();
			}).bind('mouseenter', function(e) {
				hoverBox = true;
			}).bind('mouseleave', function(e) {
				hoverBox = false;
			});
			
			$text.bind('focus.select', function(e) {
				textFocused = true;
				if(!eventsBound) {
					$box.addClass('focused');
					//console.log('binding ' + id);
					bindEvents();
					eventsBound = true;
				}
			}).bind('blur.select', function(e) {
				//console.log('blur ' + id + ' eventsbound? ' + eventsBound + ' hoverOptions? ' + hoverOptions);
			
				textFocused = false;
				//console.log((!hoverOptions && !hoverBox) || tabPressed === true);
				if((!hoverOptions && !hoverBox) || tabPressed === true) {
					
					if(eventsBound) {
						$box.removeClass('focused');
						methods.unbindEvents();
						docCloseEventBound = false;
						eventsBound = false;
					}
					methods.close($options);
					selectedIndexWhenOpen = methods.callChangeEvent($this, selectedIndexWhenOpen, selectedIndex);
					tabPressed = false;
				}
			});
			
			$ulOptions.bind('mouseenter.select', function() {
				hoverOptions = true;
			}).bind('mouseleave.select', function() {
				hoverOptions = false;
			}).children('li').bind('mouseenter.select', function() {
				methods.highlightHover($(this), opts.selectedClassName);
			}).bind('click.select', function(e) {
			
				selectedIndex = methods.select($(this), $text, opts.selectedClassName);
				methods.close($options);
				selectedIndexWhenOpen = methods.callChangeEvent($this, selectedIndexWhenOpen, selectedIndex);
				
				e.stopPropagation();
			});
			
			function bindDocCloseEvent() {
				//console.log('bind doc close');
				$document.bind('click.select', function(e) {
					//console.log(e);
					//console.log('document click');
					/*if(eventsBound) {
						$box.removeClass('focused');
						methods.unbindEvents();
						docCloseEventBound = false;
						eventsBound = false;
					}
					
					methods.close($options);
					selectedIndexWhenOpen = methods.callChangeEvent($this, selectedIndexWhenOpen, selectedIndex);*/
					
					$text.blur();
					
				});
			}
			
			function bindEvents() {
				$document.bind('keydown.select', function(e1) {
					var code = (e1.keyCode ? e1.keyCode : e1.which);

					if(code === 38 || code === 37) {
						selectedIndex = methods.moveUp(selectedIndex, $ulOptions, $text, opts.selectedClassName);
						
						e1.preventDefault();
					}
					else if(code === 40 || code === 39) {
						selectedIndex = methods.moveDown(selectedIndex, maxIndex, $ulOptions, $text, opts.selectedClassName);
						e1.preventDefault();
					}
					else if(code === 13) {
						var $self = $ulOptions.children('li:eq('+selectedIndex+')');
						selectedIndex = methods.select($self, $text, opts.selectedClassName);
						methods.close($ulOptions.parent());
						selectedIndexWhenOpen = methods.callChangeEvent($this, selectedIndexWhenOpen, selectedIndex);
						e1.preventDefault();
					}
					else if((code > 47 && code < 58) || (code > 96 && code < 123) || (code > 64 && code < 91)) {
						var $findByChar = $ulOptions.children('li:eq('+selectedIndex+')').nextAll('li');
						var found = false;
						$findByChar.each(function() {
							
							if($(this).text().charAt(0).toLowerCase() === String.fromCharCode(code).toLowerCase()) {
								selectedIndex = methods.select($(this), $text, opts.selectedClassName);
								found = true;
								return false;
							}
						});
						
						if(found === false) {
							$findByChar = $ulOptions.children('li');
							
							$findByChar.each(function(i) {
								if(i === selectedIndex) {
									return false;
								}
								
								if($(this).text().charAt(0).toLowerCase() === String.fromCharCode(code).toLowerCase()) {
									selectedIndex = methods.select($(this), $text, opts.selectedClassName);
									found = true;
									return false;
								}
							});
						}
					}
					else if(code == 9) {
						tabPressed = true;
						//console.log(textFocused + ' ' +id);
						if(textFocused == false) {
							$text.blur();
						}
					}

				});
			}

		});
	};
	
	$.fn.selectbox.defaults = {
		'className': 'select',
		'selectedClassName': 'selected'
	};

})(jQuery);