/*
 *	sweetDropdowns by keyg
 *  v.1.0 / 2010-05-05
 *  v.1.1 / 2010-05-24 - opcja usuwania juz wybranej pozycji z listy. (poprzez klase dropdownSelected - mozna ukryc wybrany element)
 *  v.1.2 / 2010-06-30 - clicking outside of dropdown will close open one.
 *  v.1.3 / 2010-08-27 - added optional container object that helps positioning dropdown with css
 *                     - animation speed parameter added
 *                     - added option maxPosition which adds scrollbar when the list is longer than maxPosition positions
 *                     - changed "close list" event handling to work with scrollbar
 *
 *	TODO:
 *      - zbadac czemu w Mozilli czasem miga obraz przy zamykaniu listy przy odpalonym maxPosition
 *        (dzieje sie tak tylko gdy scrollbar jest przesuniety gdzies w dol)
 *		- poprawniej liczyc wysokosc listy do pokazania przy opcji maxPosition / nie dziala w Operze
 *		- moze sie przydac opcja otwierania w gore i w dol w zaleznosci ile jeszcze zostalo miejsca na ekranie.
 *		- zaznacza sie tekst jak sie klika / css(?)
 *		- przy tabie sa pomijane (podobnie jak checkboxy)
 */

jQuery.fn.sweetDropdowns = function(config) {
	var config = jQuery.extend({
		containerClass: 'sweetDropdown',	// no container at the moment. doesn't seem to be necessery at the moment
		useContainer: true,
//		hiddenDropdown: 'hiddenDropdown',	// not used - to prevent sending field css is set to: display:none;
											// not setting display to none will cause that two elements with the same name
											// will exist in form and may be sent to server
		maxPositions: 0,
		animationSpeed: 175,
		openListClass: 'open',
		labelClass: 'dropdownLabel',
		listClass: 'dropdownList',
		selectedClass: 'dropdownSelected',
		hiddenClass: 'dropdownHidden'
	}, config);

	$(this).each(function(){
		var selectTag = $(this);
		selectTag.css({display:'none'});

		// get all necessary data from select
		var name = selectTag.attr('name');
		var val = selectTag.val();
		var classes = selectTag.attr('class');	// copy classes from select to dropdown label and dropdown list
		var values = {};
		selectTag.children('option').each(function() {
			values[$(this).attr('value')] = this.innerHTML;
		});

		// create hidden input to send dropdown's value
		var hiddenInput = $('<input/>');
		hiddenInput.attr({
			'type': 'hidden',
			'name': name,
			'value': val,
			'class': classes ? classes+' '+config.hiddenClass : config.hiddenClass
		});

		// create dropdown label
		var label = $('<a />');
		label.attr({'class': classes});
		label.addClass(config.labelClass);
		label.html(values[val]);

		// create dropdown list
		var list = $('<ul />');
		list.attr({'class': classes});
		list.addClass(config.listClass);
		list.css({display:'none'});

		var selected_element = false;
		jQuery.each(values, function(value, description) {
			// add option to list
			var option = $('<li>'+description+'</li>');
			//console.log(option);
			option.bind('click', function() {
				// attach selectedClass to element and remove from other elements
				$(this).parent().children().removeClass(config.selectedClass);
				$(this).addClass(config.selectedClass);
				// set label to selected element's value
				hiddenInput.val(value).trigger('change');

				label.html(description).click();
			});
			list.append(option);

			// select first or already selected value
			if (!selected_element || value == val) {
				selected_element = {'tag': option, 'value': value, 'description': description};
			}
		});
		// if no value was selected - select first from the list
		if (selected_element) {
			selected_element.tag.addClass( config.selectedClass );
			hiddenInput.val( selected_element.value );
			label.html( selected_element.description );
		}

		var listCloser = function() {
			label.removeClass(config.openListClass);
			if (jQuery.browser.mozilla) {	// performed to avoid flickering in FF
				list.scrollTop(0);
			}
			list.slideUp(config.animationSpeed);
		};

		var listOpener = function() {
			label.addClass(config.openListClass);
			if (config.maxPositions) {
				// TODO: change this - bad temporary solution
				var visible_height = Number( list.children().first().css('height').replace('px','') ); //.outerHeight();
				list.css({height:'0px'}); // prevents from flickering
				list.animate({height: (visible_height*config.maxPositions) + 'px'},config.animationSpeed);
			}
			else {
				list.slideDown(config.animationSpeed, function(){list.jScrollPane();});
			}
			$(document).bind('mousedown', documentClose);
		}

		var documentClose = function(e) {
			// no action if scrollbar is in use - keep event handler
			if (e.target == list[0]) {
				return;
			}
			// detach event handler if label or list item has been clicked
			// event is going to be handled by target element (list will be closed at that level).
			$(document).unbind('mousedown', documentClose);
			if (e.target == label[0] || $(e.target).parents('.'+config.listClass)[0] == list[0]) {
				return;
			}
			listCloser();
		}

		// open/close dropdown function
		label.bind('click', function() {
			if ($(this).hasClass(config.openListClass)) {
				listCloser();
			}
			else {
				listOpener();
			}
		});

		// insert new elements :)
		if (config.useContainer) {
			var container = $('<div />');
			container.attr({'class': classes});
			container.addClass(config.containerClass);
			container.append(hiddenInput);
			container.append(label);
			container.append(list);
			selectTag.after(container);
		}
		else {

			selectTag.after(list);
			selectTag.after(label);
			selectTag.after(hiddenInput);
		}
	});
};
