/*
 * jQuery.searchableSelect
 *   (http://joernroeder.de/jquery/searchableSelect/)
 *
 * Created for @link{http://www.sma.de}
 * --------------------------------------
 *
 * Copyright (c) 2010 Jörn Röder <kontakt@joernroeder.de>
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 * 
 * $Version: 11/16/2010
 *
 * @option maxHeight int
 * @option position Object @link{http://jqueryui.com/demos/position/#options}
 *		NOTE: position.of is always set by the plugin to this.element
 * @option width int
 * @option ignoreOptgroups Boolean false
 *		group Menu by <optiongroup>
 * @option skipClass String 'default'
 *		skip <option> with this class
 * @option containerElement String 'div'
 * @option containerClass Sting 'searchableSelect'
 * @option invisibleClass String 'invisible'
 *		this class is toggled by click
 * @option inputClass Sting 'searchableInput'
 * @option menuClass String 'searchableMenu'
 * @option buttonClass String 'jq-button ui-icon-circle-close ui-button-icon-only'
 * 
 */
(function ($) {
	/**
	 * quick support to check several css properties
	 *
	 * @link http://net.tutsplus.com/tutorials/html-css-techniques/quick-tip-detect-css-support-in-browsers-with-javascript/
	 * @example if ($.supportCss('box-shadow')) { alert('browser supports box-shadow. Do what you need.'); }
	 */
	$.supportCss = (function() {
		var div = document.createElement('div'),
		  vendors = 'Khtml Ms O Moz Webkit'.split(' '),
		  len = vendors.length;
		
		return function(prop) {
		  if ( prop in div.style ) return true;
		
		  prop = prop.replace(/^[a-z]/, function(val) {
			 return val.toUpperCase();
		  });
		
		  while(len--) {
			 if ( vendors[len] + prop in div.style ) {
				// browser supports box-shadow. Do what you need.
				// Or use a bang (!) to test if the browser doesn't.
				return true;
			 }
		  }
		  return false;
		};
	})();
	
	/**
	 * categoryAutocomplete
	 *
	 */
	$.widget("custom.categoryAutocomplete", $.ui.autocomplete, {
		_renderMenu: function (ul, items) {
			var self = this,
				currentCategory = "";
			
			$.each(items, function (index, item) {
				if (!self.options.ignoreOptgroups) {
					if (item.category !== currentCategory) {
						ul.children(':last').addClass('ui-autocomplete-group-last-item');
						ul.append("<li class='ui-autocomplete-header'>" + item.category + "</li>");
						currentCategory = item.category;
					}
				}
				self._renderItem(ul, item);
			});
			
			ul.children(':last').addClass('ui-autocomplete-last-item');
			ul.children(':first').addClass('ui-autocomplete-first-item');
		},
		
		_suggest: function (items) {
			var ul = this.menu.element
					.empty()
					.zIndex(this.element.zIndex() + 1),
				menuWidth,
				textWidth,
				position;
			this._renderMenu(ul, items);
			// TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate
			this.menu.deactivate();
			this.menu.refresh();
			
			position = $.extend({}, {
				my: "left top",
				at: "left bottom",
				collision: "none"
			}, this.options.position, { of: this.element});
			
			this.menu.element.show().position(position);
	
			menuWidth = this.options.width ? this.options.width : ul.width("").width();
			textWidth = this.element.width();
			ul.width(Math.max(menuWidth, textWidth));
		},
		
		_response: function (content) {
			if (content.length) {
				content = this._normalize(content);
				this._suggest(content);
				this._trigger("open");
			} else {
				this._suggest("");
				this._trigger("open");
			}
			this.element.removeClass("ui-autocomplete-loading");
		}
	});

	
	$.fn.searchableSelect = function (options) {
		
		var defaults = {
			ignoreOptgroups		: false,
			skipClass			: 'default',
			maxHeight			: 0,
			elementClass		: 'searchableSelect-select',
			containerElement	: 'div',
			containerClass		: 'searchableSelect',
			invisibleClass		: 'invisible',
			inputClass			: 'searchableInput',
			menuClass			: 'searchableMenu',
			buttonClass			: 'jq-button close',
			setWidth			: true,
			autocomplete		: {}
		},
		opts = $.extend({}, defaults, options);
		
		if (!$.supportCss('boxShadow')) {
   			$('body').addClass('no-box-shadow');
		}
		
		return this.each(function () {
								  
			// kick all elements that are not selects
			if (!$(this).is('select')) {
				console.error('the current SearchableSelect selector is not a <select>');
				return this;
			}
			
			/**
			 * @description init vars
			 * 
			 * $this: the selectbox
			 * $input: input field
			 * $button: cross-button
			 * $container: wrapper
			 */
			var $this = $(this).addClass(opts.elementClass),
				
				$container = $('<' + opts.containerElement + '/>', {
					width		: $this.outerWidth(),
					className	: opts.containerClass + ' ' + opts.invisibleClass
				})
				.css({
					'position'	: 'relative'/*,
					'margin-top': -$this.outerHeight(true) + 'px'*/
				}),
				
				$input,
				$button,
				autocompleteOpts = opts.autocomplete || {},
				data = [];
				
			/**
			 * Check whether the Select is located within the grid and disable the automatic width,
			 * if no explicit width is specified.
			 */
			if ($this.closest('.hasGrid').length && opts.setWidth === true) {
				opts.setWidth = false;
			}
			
			if ($.fn.bgiframe) {
				$container.bgiframe();
			}
				
			$input = $('<input/>', {
				type		: 'text',
				className	: 'text ' + opts.inputClass,
				name		: $this.attr('name') + '-searchableInput',
				value		: $this.val().length ? $('option[value=' + $this.val() + ']', $this).text() : ''
			})
			.bind('keyup', function () {
				var valLength = $(this).val().length;
				
				if (valLength) {
					if (!$button.is(':visible')) {
						$button.stop(true, true).fadeIn('fast');
					}
				}
				else {
					$button.stop(true, true).fadeOut('fast');
				}
			})
			.blur(function () {
				var inputVal = $(this).val(),
					value = inputVal.length ? $('option:contains(' + inputVal + ')', $this).val() : '';
			
				//$input.val(ui.item.label);
				$this.val(value);
			});
			
			// set auto or specific width
			if (opts.setWidth !== false) {
			
				if (opts.setWidth === true) {
					$input.width($this.outerWidth());
			
				} else {
					$input.width(parseInt(opts.setWidth, 10));
				}
			}
			
			$button = $('<a />', {
				className	: opts.buttonClass
			})
			.hide()
			.click(function () {
				$button.hide();
				// reset select
				$this.val('');
				// reset input field and open autocomplete
				$input
					.val('')
					.focus()
					.categoryAutocomplete('search', '');
				return false;
			});
			
			$('option', $this).each(function () {
				var $option = $(this);
				
				// skip empty options
				if ($option.data('skip') || !$option[0].value.length || !$option.text().length || $option.hasClass(opts.skipClass)) {
					return true;
				}
						
				data.push({
					label		: $option.text(),
					category	: $option.closest('optgroup').length ? $option.closest('optgroup').attr('label') : ''
				});
			});
			
			if (!data.length) {
				return this;
			}
			
			$.extend(autocompleteOpts, {
				source		: data,
				minLength	: 0,
				change: function (event, ui) {
					console.log("change");
				},
				select: function (event, ui) {
					var value = $('option:contains(' + ui.item.label + ')', $this).val() || '';
					
					$input.val(ui.item.label);
					$this.val(value);
					
					return false;
				},
				open: function (event, ui) {
					if ($input.val().length) {
						$button.stop(true, true).show();
					}
					else {
						$button.stop(true, true).fadeOut('fast');
					}
				},
				close: function (event, ui) {
					$container.addClass(opts.invisibleClass);
				},
				ignoreOptgroups	: opts.ignoreOptgroups,
				position: {
					collision	: "flip",
					offset		: $('body').hasClass('no-box-shadow') ? "0 0" : "1 0"
				},
				width: $this.outerWidth() - 2
			});
			
			// init autocomplete
			$input
				.categoryAutocomplete(autocompleteOpts)
				.categoryAutocomplete('widget')
				.addClass(opts.menuClass)
				.css({
					'max-height': opts.maxHeight ? parseInt(opts.maxHeight, 10) : 'auto',
					'overflow-y': opts.maxHeight ? 'auto' : ''
				});
			
			$container
				.click(function () {
					if ($container.hasClass(opts.invisibleClass)) {
						$container.removeClass(opts.invisibleClass);
						$input
							.focus()
							.categoryAutocomplete('search', $input.val().length ? $input.val() : '');
					}
				})
				.append($input)
				.append($button);
			
			$this.after($container);
		});
	};

})(jQuery);
	
// jQuery Wrapper & onDomReady
(function ($) {
	$(function () {
		$("select.jq-searchable").searchableSelect({
			maxHeight: 400
		});
	});
})(jQuery);
