(function($) {
	$.widget("ui.dz_selectmenu", {
		eventPrefix: "dz_selectmenu",
		options: {
			element: null,			// Options-Elemente
			base_class_suffix: '',
			width: 0,				// Breite der Selectbox
			dropdown_width: 0,		// Breite der Dropdown-Liste
			menu_click_action: '',
			select_click_action: 'click',
			tabindex: 1
		},

		_create: function() {
			var self = this;
			var o = this.options;

			if (this.element[0].tagName == "SELECT") {
				self._init_from_selectbox(this.element);
			}
			
			if (o.base_class_suffix) {
				this.widgetBaseClass += '_' + o.base_class_suffix;
			}

			if (typeof(o.element.status) == 'undefined') {
				this.options.element.status = self._getSelectedStatus(o.element);
			}

			// Wenn dropdown Breite nicht angegeben wird diese auf Elementbreite gesetzt
			if (o.dropdown_width <= 0) {
				self.setDropdownWidth(o.width);
			}

			// Die Werte des Hidden-Feldes speichern
			self._saveHiddenFieldValues();		

			this.init(o.element);

			if (o.base_class_suffix == 'filter') {
				filter_row_sum_width = filter_row_sum_width + $('#'+o.element.id).width();

				if (filter_row_sum_width >= $('#filter_row').width()) {
					$('#filter_row').height('32');
				}
			}

			$('body').click(function() {
				self._closeMenu($('#'+ o.element.id +' ul'));
			});

			return this;
		},

		getHiddenInput: function() {
			var o		= this.options;
			var input	= $('#'+o.element.name);
			if (input.length > 0) {
				return input;
			}
			return null;
		},

		init: function(element) {
			var self = this;
			self.options.element = element;

			self._restoreHiddenFieldValues();

			var input = $('<input />', {
				id:	element.name,
				name: element.name,
				type: 'hidden',
				value: element.status.key
			});

			// alten Inhalt entfernen
			if ($('#'+element.id).length > 0 && ($('#'+element.id).html() != '')) {
				// Tabindex speichern bevor das Element gelöscht wird
				this.option('tabindex', $('#'+element.id + ' div.'+this.widgetBaseClass).attr('tabindex'));                              
				$('#'+element.id).html('');
			}

			$('#'+element.id).css('display', 'block')
				.append(self._buildSelectField(self))
				.append(self._buildSelectMenu(self))
				.append(input)
				.unbind('keydown')
				.keydown(self._toggleVisibility(self, element.id))
				.width(self._calcButtonWidth(element.id));
			
			self._calcMenuWidth(element.id, this.widgetBaseClass, this.options.dropdown_width);
		},
		
		_getSelectedStatus: function(element) {

			var status			= new Object();
			var options			= new Array();
			var status_isset	= false;

			jQuery.each(element.options, function(key, value){
				options.push(value);

				if (value.selected) {
					status = jQuery.extend({}, value);

					status_isset = true;

					return true;
				}
			});

			if (!status_isset) {
				status = jQuery.extend({}, options.shift());
			}

			return status;
		},
		
		setDropdownWidth: function(width) {
			this.options.dropdown_width = width;
			return this;
		},


		_init_from_selectbox: function(selectbox) {
			var self = this;
			var dd_width= 0;
			var options = new Array();
			var option_elem, value;
			var status = new Array();
			var id = $(selectbox).attr('id');
			var name = $(selectbox).attr('name');
			var string_length;

			selectbox.children().each(function() {
				// TODO: Überprüfen, ob sich dieser
				// Abschnitt zusammenfassen lässt.
				if ($(this).is('optgroup')) {
					string_length = textWidth($(this).attr('label'));
					if (string_length > dd_width) {
						dd_width = string_length;
					}

					value = '<span class="top-cat-title">'
							+ $(this).attr('label')
							+ "</span>";

					option_elem = {
						key : $(this).attr('value'),
						selected : $(this).attr('selected') == 'true',
						value : value
					};

					options.push(option_elem);

					if ($(this).attr('selected') == 'true') {
						
						status = {
							key: $(this).attr('value'),
							selected : true,
							value : $(this).attr('label')
						};
					}
					$(this).children().each(function() {
						string_length = textWidth($(this).text());
						if (string_length > dd_width) {
							dd_width = string_length;
						}

						value = '<span class="sub-cat-title">'
							+ $(this).text()
							+ "</span>";

						option_elem = {
							key : $(this).val(),
							selected : $(this).is(":selected"),
							value : value
						};

						options.push(option_elem);

						if ($(this).is(":selected")) {
							status = {
								key : $(this).val(),
								selected : true,
								value : $(this).text()
							};
						}
					});
				} else {
					string_length = textWidth($(this).text());
					if (string_length > dd_width) {
						dd_width = string_length;
					}

					if ($(this).val() == 0 ) {
						value = '<span class="default-option">'+$(this).text()+"</span>";
					} else {
						value = $(this).text();
					}

					option_elem = {
						key : $(this).val(),
						selected : $(this).is(":selected"),
						value : value
					};

					options.push(option_elem);

					if ($(this).is(":selected")) {
						status = {
							key : $(this).val(),
							selected : true,
							value : $(this).text()
						};
					}
				}
			});
			
			this.setDropdownWidth(dd_width); 

			// Widgetvariable setzen
			if (!self.options.width) {
				self.options.width  = $(selectbox).outerWidth();
			}

			if (!self.options.tabindex) {
				self.options.tabindex   = $(selectbox).attr('tabindex');
			}

			self.options.element	= new Object({
				id		: id,
				name	: name,
				options : options,
				status	: status
			});

			$(selectbox).parent().html($("<div id='"+id+"'></div>")); // Ersetze <select> durch <div>
			return;
		},

		_saveHiddenFieldValues: function() {
			this.option('hidden_id', this.options.element.id);
			this.option('hidden_name', this.options.element.name);
			this.option('hidden_value', this.options.element.status.key);
		},

		_restoreHiddenFieldValues: function() {
			var e		= this.options.element;
			e.id		= this.options.hidden_id;
			e.name		= this.options.hidden_name;
			e.status.key	= this.options.hidden_value;
		},

		_buildSelectField: function(self) {
			var element = this.options.element;
			var base_class = this.widgetBaseClass;

			var status_width = {};
			var select_width = {};

			if (this.options.width > 0) {
				status_width = {width: this.options.width-16};
				select_width = {width: this.options.width};
				if ($.browser.msie) {			
					status_width = {width: this.options.width-17};					
				}
			}

			var title	= $('<div />', {id: element.id+'_select', className: base_class + '_status', css: status_width, innerHTML: element.status.value});
			var icon	= $('<div />', {id: element.id+'_select_icon', className: base_class + '_icon'});

			if (this.options.base_class_suffix == 'filter' && element.status.key != 'default') {
				icon.addClass(base_class+'_icon_selected')
					.click(function(event) {
						event.stopPropagation();
						self._closeMenu($('#'+element.id+' ul'));
						$('#'+element.id+' input').val('default');
						$('#begin_at').val(0);
						getArticle('browse', search_name);
					});
			}

			var toggle_visibility = self._toggleVisibility(self, element.id);

			var select_field = $('<div />', {className: base_class,	css: select_width, tabindex: self.option('tabindex')})
				.append(title)
				.append(icon)
				.bind(this.options.select_click_action, toggle_visibility)
				.bind('mouseover mouseout', function() {
					$(this).toggleClass(base_class + '_status_hover');
				});

			return select_field;
		},

		_toggleVisibility: function(self, id) {

			var base_class = this.widgetBaseClass;
			var click_action = this.options.menu_click_action;

			return function(event) {

				var element = $('#'+ id +' ul');

				if (event.type == 'mouseover') {
					self._openMenu(element);
				} else if (event.type == 'mouseout') {
					var position = $('#'+id+' div').position();

					if (event.pageY > position.top + $('#'+id+' div').height() - 5) {
						self._openMenu(element);
					} else {
						self._closeMenu(element);
					}
				} else if (event.type == 'blur') {
					self.option('lastEvent','');
				} else if (event.type == 'focus') {
					event.stopPropagation();
					// wenn nicht 2x kurz hintereinander focus event bekommen
					if(self.option('lastEvent')!= 'focus'){
						if (self._isMenuClosed(element)) {
							self._openMenu(element);
						}
					}
				} else if (event.type == 'click') {
					event.stopPropagation();

					// wenn nicht kurz vorher focus bekommen hat
					if (self.option('lastEvent') != 'focus') {
						if (self._isMenuClosed(element)) {
							self._openMenu(element);
						} else {
							self._closeMenu(element);
						}
					}
				} else if (event.type == 'keydown') {
					switch (event.which) {
						case $.ui.keyCode.ENTER:
							if (self._isMenuClosed(element)) {
								self._openMenu(element);
								break;
							}
						case $.ui.keyCode.TAB:

							if (!self._isMenuClosed(element)) {
								self._actionHandler(self, click_action, id, base_class);
							}

							break;
						case $.ui.keyCode.DOWN:
						case $.ui.keyCode.RIGHT:
							event.preventDefault();

							var count_li = $('#'+ id +' li').length-1;
								
							if (self._isMenuClosed(element)) {
								self._openMenu(element);
							}

							var next_entry	= self._getNextEntry('menu_hover', id, count_li);
							var offset		= 0;
							var current_index        = self._getCurrentPosition('menu_hover', id);
							self._markMenuEntry('menu_hover', id, next_entry);

							if (next_entry.position().top + next_entry.height() > element.height()) {
								offset = (next_entry.height() * (current_index +2));
								if (!$.browser.msie) {
									offset -= next_entry.position().top;
								} else {
									offset -= (element.height() - current_index);
								}
								element.scrollTop(offset);
							}

							if ((next_entry.position().top  < 0)) {
								element.scrollTop(0);
							}

							break;
						case $.ui.keyCode.UP:
						case $.ui.keyCode.LEFT:
							event.preventDefault();
															
							if (self._isMenuClosed(element)) {
								self._openMenu(element);
							}
							
							var prev_entry      = self._getPrevEntry('menu_hover', id);
							var offset          = 0;
							var current_index   = self._getCurrentPosition('menu_hover', id);
							self._markMenuEntry('menu_hover', id, prev_entry);
							if ((prev_entry.position().top  < 0)) {
								if (!$.browser.msie) {
									offset = (prev_entry.height() * (current_index)) + prev_entry.position().top;
								} else {
									offset = (prev_entry.height()+1) * (current_index-1);
								}
								element.scrollTop(offset);
							}

							break;
						case $.ui.keyCode.ESCAPE:
							self._closeMenu(element);
							break;
						default:
							if (self._isMenuClosed(element)) {
								self._openMenu(element);
							}

							self._setInputInterval();

							var old_string 	= self.option('search_string') ? self.option('search_string') : '';
							var character	= String.fromCharCode(event.keyCode).toLowerCase();
							
							self._searchInputString(id, element, old_string, character);
							break;
					}
				}

				// Letztes Event setzen, nach 200ms verwerfen damit nach tab->focus mit klick geschlossen werden kann
				self.option('lastEvent', event.type);
				setTimeout(function(){self.option('lastEvent','');}, 200);
			};
		},

		_setInputInterval : function() {
			// Initialisiert selbstbeendendes Interval
			var self = this;

			if (self.option('interval_id')) {
				clearInterval(self.option('interval_id'));
			}

			var i_id = setInterval(function() {
					clearInterval(self.option('interval_id'));
					self.option('interval_id','')
						.option('search_index',0)
						.option('search_string', '');
				}, 1000);
			self.option('interval_id', i_id);
		},

		_searchInputString : function(id, element, old_string, character) {

			// Einträge geben lassen
			var options = this.option('option_list');
			if (!(options)) {
				options = $('div #'+id+' ul li').map(function() {return $(this).text().toLowerCase()}).get();
				this.option('option_list', options);
			}

			// Nur Einträge welche mit dem Suchstring beginnen herausfiltern
			var search_string = old_string + character;
			var found = false;
			var matches = new Array();

			for (var i=0; i < options.length; i++) {
				if (options[i].indexOf(search_string) == 0) {
					found = true;
					matches.push({
						elem 	: $('div #'+id+' ul li:nth-child('+(i+1)+')'),
						index	: (i+1)						
					});
				}
			}

			var index = 0;
			// Suchergebnis speichern oder vorheriges abrufen
			if (!found) {
				// die Ergebnisse nur wiederholen wenn der eingegebene Buchstabe dem vorherigen entspricht
				if (old_string.charAt(old_string.length-1) == character) {
					index 	= this.option('search_index') + 1;
					matches = this.option('previous_search');
					if (index >= matches.length) {
						index = 0;
					}

					this.option('search_index', index);
				}
			} else {
				this.option('previous_search', matches);
				this.option('search_index', 0);
				this.option('search_string', search_string);
			}

			// Eintrag markieren und scrollen
			if (matches[this.option('search_index')]) {
				var selected = matches[this.option('search_index')].elem;
				var index	 = matches[this.option('search_index')].index;

				this._markMenuEntry('menu_hover', id, selected);

				if (selected.position().top + selected.height() > element.height()) {
					offset = (selected.height() * (index +2));
					element.scrollTop(offset);
				}

				if ((selected.position().top  < 0)) {
					offset = (selected.height() * (index -2)) ;
					element.scrollTop(offset);
				}
			}
		},

		_openMenu: function(element) {
			$('ul[class^="ui-dz_selectmenu"]').css('display', 'none');
			element.css('display', 'block');
			return this;
		},

		_isMenuClosed: function(element) {
			return element.css('display') == 'none';
		},

		_closeMenu: function(element) {
			element.css('display', 'none');
			return this;
		},

		_setInputValueAndShowEntry: function(select_id, entry) {
			$('#'+ select_id +' input').val(entry.attr('name'));
			$('#'+ select_id +'_select').html(
				entry.text()
			);

			return this;
		},

		_getCurrentEntry: function(type, select_id) {
			return $('#'+ select_id +' .'+ this.widgetBaseClass +'_'+ type);
		},

		_getCurrentPosition: function(type, select_id) {
			return $('#'+ select_id+ ' li').index(this._getCurrentEntry(type, select_id));
		},

		_getNextEntry: function(type, select_id) {
			var n = this._getCurrentEntry(type, select_id).next();
			if (n.length) {
				return n;
			}

			return $('#'+ select_id +' li:first-child');
		},

		_getPrevEntry: function(type, select_id) {
			var p = this._getCurrentEntry(type, select_id).prev();
			if (p.length) {
				return p;
			}

			return $('#'+ select_id +' li:first-child');
		},

		_markMenuEntry: function(type, select_id, next_entry) {
			this._deleteMenuMarker(type, select_id);
			next_entry.addClass(this.widgetBaseClass +'_'+ type);

			return this;
		},

		_deleteMenuMarker: function(type, select_id) {
			$('#'+ select_id +' .'+ this.widgetBaseClass +'_'+ type).removeClass(this.widgetBaseClass +'_'+ type);

			return this;
		},

		_calcButtonWidth: function(id) {
			var select = $('#'+ id +'_select');
			var select_icon = $('#'+ id +'_select_icon');

			if (!$.browser.msie) {
				select.width(function(){
					return select.width()
						- parseInt(select.css('padding-left'))
						- parseInt(select.css('padding-right'));
				});
			}

			return select.outerWidth()
				+ select_icon.width()
				+ parseInt(select.css('margin-right'))
				+ parseInt(select_icon.css('margin-right'))
				+ parseInt(select.css('margin-left'))
				+ parseInt(select_icon.css('margin-left'))
				+ parseInt($('#'+ id).css('margin-right'))
				+ parseInt($('#'+ id).css('margin-left'));
		},
		
		_calcMenuWidth: function(id, base_class, dropdown_width) {

			if (dropdown_width > 0) {
				var width = dropdown_width;
			} else {
				var add_width = 26;
				if ($.browser.msie) {
					add_width = 34;
				}

				var width = $('#'+id+' ul').outerWidth() + add_width;

				if (width < $('#'+id+' .'+base_class).width()) {
					width = $('#'+id+' .'+base_class).width();
				}
			}

			$('#'+id+' ul').width(width);
		},

		_buildSelectMenu: function(self) {

			var element = this.options.element;
			var base_class = this.widgetBaseClass;
			var action = self._setMenuClickAction(self, this.options.menu_click_action, element.id, base_class);

			var ul = $('<ul />', {className: base_class + '_menu', css: {clear: 'both'}});

			if (this.options.base_class_suffix == 'filter') {
				ul.mouseleave(function() {
					self._closeMenu($(this));
				});
			}

			var index = 0;

			for (var option in element.options) {

				var bold = (element.options[option].key == 'default') ? {'font-weight': 'bold'} : {};

				var a = $('<a />', {innerHTML: element.options[option].value, css: bold});
				
				var icon = null;
				if (typeof(element.options[option].icon_class) !== 'undefined' && element.options[option].icon_class !== '') {
					icon = $('<div />', {'class': 'housecolor-icon hci-'+ element.options[option].icon_class});
				}

				var selected = (element.options[option].selected) ? base_class + '_item_selected ' + base_class + '_menu_hover' : '';

				var li = $('<li />', {className: selected, id: element.id+'_'+index, name: element.options[option].key })
						.bind('mouseover mouseout', function() {
							self._markMenuEntry('menu_hover', element.id, $(this));
						})
						.html(a)
						.bind('click keydown', function(event){
							// ursprünglichem Element den Fokus wieder geben
							$('#'+self.options.element.id + " ."+ self.widgetBaseClass).focus()
						})
						.bind('click keydown', action);

				if (icon) {
					li.prepend(icon);
				}
				
				ul.append(li);

				index++;
			}

			return ul;
		},

		_setMenuClickAction: function(self, click_action, id, base_class) {
			return function(event) {
				event.stopPropagation();
				self._actionHandler(self, click_action, id, base_class);
			};
		},

		_actionHandler: function (self, action, id, base_class) {
			var entry = $('#'+ id +' .'+ base_class +'_menu_hover');
			
			if (typeof(entry.attr('id')) != 'undefined' && $('#'+ id +' input').val() != entry.attr('id')) {		
				self._markMenuEntry('item_selected', id, entry)
					._setInputValueAndShowEntry(id, entry);

				if (typeof(action) == 'function') {
					var index = self._getCurrentPosition('menu_hover', id);
					action(id, entry, index);
				}
			}

			self._closeMenu($('#'+ id +' ul'));

		}
	});
})(jQuery);
