// custom select support
$.fn.customSelect = function() {
	
	// methods
	if (arguments.length) {
		
		if (typeof(arguments[0]) == 'object') {
			var event = arguments[0];
			var select = $(arguments[0].data.select);
			var placeholder = select.data('placeholder');
			if (!placeholder) {
				$(document).unbind('mousedown', select.customSelect).unbind('keydown', select.customSelect);
				return;
			}
			
			if (event.type == 'mousedown') {
				if (!$.browser.opera || event.target.tagName != 'OPTION') {
					var p = $(event.target).closest('.custom-select-placeholder');
					if (!p.length || p[0] != placeholder[0])
						select.customSelect('blur');
				}
			}
			else {
				switch (event.keyCode) {
					case 13:
						select.customSelect(placeholder.data('optionsShown') ? 'hideOptions' : 'showOptions');
						break;
					case 9:
						select.customSelect('hideOptions', true);
						if (!$.browser.msie)
							select.focus();
						select.customSelect('blur');
						break;
					default:
						if (event.target != select[0]) {
							select.focus();
							return false;
						}
				}
			}
			
			return select;
		}
		
		var args = arguments;
		return this.each(function() {
			var select = $(this);
			var placeholder = select.data('placeholder');
			var optionsUl = placeholder.find('ul');
			
			switch (args[0]) {
				
				case 'focus':
					if (!placeholder.hasClass('focused')) {
						placeholder.addClass('focused');
						$(document).bind('mousedown', { select: select[0] }, select.customSelect).bind('keydown', { select: select[0] }, select.customSelect);
					}
					break;
					
				case 'blur':
					placeholder.removeClass('focused');
					if (placeholder.data('optionsShown'))
						select.customSelect('hideOptions');
					$(document).unbind('mousedown', select.customSelect).unbind('keydown', select.customSelect);
					break;
				
				case 'showOptions':
					placeholder.data('optionsShown', true);
					optionsUl.stop().css({ opacity: 1, display: 'block' }).scrollTop(placeholder.data('scrollTop'));
					select.customSelect('focusCurrOption');
					break;
					
				case 'hideOptions':
					placeholder.data('optionsShown', false).data('scrollTop', optionsUl.scrollTop());
					if (args.length == 1)
						optionsUl.animate({ opacity: 0 }, 'fast', function() { $(this).css('display', 'none'); });
					else
						optionsUl.css({ opacity: 0, display: 'none' });
					break;
					
				case 'update':
					if (args.length == 2)
						select.val(args[1]);
						
					var li = placeholder.find('li[val=' + select.val() + ']');
					if (!li.hasClass('selected')) {
						placeholder.find('li').removeClass('selected');
						li.addClass('selected');
						placeholder.find('span')
							.text(li.text())
							.clearQueue()
							.stop()
							.css('opacity', 1)
							.animate({ opacity: 1 }, 250)
							.animate({ opacity: 0 }, 'fast')
							.animate({ opacity: 1 }, 'fast')
							.animate({ opacity: 0 }, 'fast')
							.animate({ opacity: 1 }, 'fast');
							
						select.customSelect('focusCurrOption');
					}
					break;
	
				case 'focusCurrOption':
					if (placeholder.data('optionsShown') && placeholder.data('scrollPresent')) {
						var li = placeholder.find('li[val=' + select.val() + ']');
						
						var height = li.outerHeight();
						var top = height * li.prevAll('li').length;
						// check bottom
						var boundaryBottom = top + height - optionsUl.height();
						if (boundaryBottom > optionsUl.scrollTop())
							optionsUl.scrollTop(boundaryBottom);
						else if (top >= 0 && top < optionsUl.scrollTop())
							optionsUl.scrollTop(top);
					}
					break;
					
			}
		});
	}

	// init
	return this.each(function() {
		var select = $(this);
		if (select.data('placeholder'))
			return;
		
		// hide select
		var width = select.hasClass('fixed-width') ? select.width() - 2 : 'auto';
		var hidden = $('<div>').css({ overflow: 'hidden', position: 'absolute', width: 0, height: 0, padding: 0 });
		select.replaceWith(hidden).appendTo(hidden);
			
		// create placeholder
		var placeholder = $('<div>').insertAfter(hidden);
		placeholder.addClass('custom-select-placeholder').append('<span></span><ul></ul>').data('optionsShown', false);
		
		// import select classes, if any
		var classes = select.attr('class').split(' ');
		for (var i = 0; i < classes.length; i++)
			if (!classes[i].match(/^custom-select/) && classes[i] != 'fixed-width')
				placeholder.addClass(classes[i]);
		
		// populate options
		var optionsUl = placeholder.find('ul'),
			valueSpan = placeholder.find('span').css({ float: 'left', visibility: 'hidden' }),
			selectedText;
		for (var i = 0; i < select[0].options.length; i++) {
			var li = $('<li></li>').appendTo(optionsUl).attr('val', select[0].options[i].value).text(select[0].options[i].text);
			if (select[0].options[i].selected) {
				li.addClass('selected');
				selectedText = select[0].options[i].text;
			}
			if (width == 'auto')
				valueSpan.append(select[0].options[i].text + '<br>');
		}
		
		// set width
		var placeholderWidth = width == 'auto' ? valueSpan.width() + parseInt(placeholder.css('paddingLeft')) + parseInt(placeholder.css('paddingRight')) : width;
		valueSpan.html(selectedText).css({ float: 'none', visibility: 'visible' });
		optionsUl.css('marginLeft', -1 * parseInt(placeholder.css('paddingLeft'), 10) - 1);
		
		// adjust placeholder and options ul widt if necessary
		if (optionsUl.height() > 250) {
			optionsUl.height(250);
			placeholder.data('scrollPresent', true);
		}
		
		if (($.browser.msie && $.browser.version == '7.0'))
			optionsUl.width(optionsUl.width());
		if (($.browser.mozilla || $.browser.webkit || ($.browser.msie && $.browser.version == '7.0')) && placeholder.data('scrollPresent'))
			optionsUl.width(optionsUl.width() + 17);
		if (optionsUl.width() < placeholderWidth)
			optionsUl.width(placeholderWidth);
			
		placeholder.width(placeholderWidth - parseInt(placeholder.css('paddingLeft')) - parseInt(placeholder.css('paddingRight')));
		placeholder.find('span').width(placeholder.width());
			
		// link placeholder and select to each other
		select.data('placeholder', placeholder);
		placeholder.data('select', select);
			
		// handle focus and blur events
		select
			.focus(function() {
				$(this).customSelect('focus');
			})
			.keypress(function(event) {
				if (event.keyCode == 32)
					return false;
				$(this).customSelect('update');
			})
			.keyup(function() {
				$(this).customSelect('update');
			})
			.change(function() {
				$(this).customSelect('update');
			});
			
		// handle click on placeholder
		placeholder
			.click(function(event) {
				var placeholder = $(this);
				var select = placeholder.data('select');
				
				select.customSelect('focus');
				
				if (event.target.tagName == 'LI') {
					var li = $(event.target);
					select.val(li.attr('val')).customSelect('hideOptions', true).change();
				}
				else if (event.target.tagName != 'UL')
					select.customSelect(placeholder.data('optionsShown') ? 'hideOptions' : 'showOptions');
			});
			
		// handle hover on lis
		placeholder.find('li').hover(
			function() { $(this).addClass('hover'); },
			function() { $(this).removeClass('hover'); }
		);
	});
	
};
