$(function() {
	DoubleList.init();
});

var DoubleList = {
	
	/**
	 * register every double list present in the document
	 */
	init: function()
	{
		$('.double_list').each(function() {
			DoubleList.register(this);
		});
	},
	
	/**
	 * register the click events for the buttons
	 */
	register: function(container)
	{
		var form = this.get_form_holder(container);
		
		if (form) {
			// register the add_selected action
			$(container).find('.double_list_add_button').click(function() {
				DoubleList.add_selected(container);
			});
			
			// register the remove_selected action
			$(container).find('.double_list_remove_button').click(function() {
				DoubleList.remove_selected(container);
			});

			// moves every UNSELECTED option from the SELECTED list 
			$(container).find('.double_list_selected OPTION:not(:selected)').each(function() {
				DoubleList.move_option(this, $(container).find('.double_list_unselected'));
			});
			// deselects every selected option from the SELECTED list
			$(container).find('.double_list_selected OPTION:selected').each(function() {
				$(this).attr('selected', false);
			});
			// marks every option in the SELECTED list as selected
			$(form).submit(function() {
				$(container).find('.double_list_selected OPTION').each(function() {
					$(this).attr('selected', true);
				});
			});
		}
	},

	
	/**
	 * moves an option to another destination
	 * 
	 * @param	DOMObject			option		An option
	 * @param	jQueryDOMReference	destination	Reference for the select input where the option will be moved
	 */
	move_option: function(option, destination)
	{
		var optgroup = DoubleList.get_optgroup_for_option(option, destination);
		$(optgroup).append($(option));
		DoubleList.sort_options(optgroup);
	},
	

	/**
	 * moves all selected entries from the .double_list_unselected SELECT into the .double_list_selected SELECT
	 * 
 	 * @param  jQueryDOMReference	container	main identifier for the fieldset which contains the double select
	 */
	add_selected: function(container) 
	{
		var selected = $(container).find('.double_list_unselected OPTION:selected');
		var destination = $(container).find('.double_list_selected');
		
		$(selected).each(function(index) {
			DoubleList.move_option(this, destination);
		});
	},


	/**
 	 * moves all selected entries from the .double_list_selected SELECT into the .double_list_unselected SELECT
 	 * 
 	 * @param  jQueryDOMReference	container	main identifier for the fieldset which contains the double select
	 */	
	remove_selected: function(container) 
	{
		var selected = $(container).find('.double_list_selected OPTION:selected');
		var destination = $(container).find('.double_list_unselected');
		
		$(selected).each(function(index) {
			DoubleList.move_option(this, destination);
		});
	},
	
	
	/**
	 * defines if an option belongs to an OPTGROUP and checks if said group exits in the
	 * 
	 * @param	DOMObject			option		An option
	 * @param	jQueryDOMReference	destination	Reference for the select input where the option will be moved
	 */
	get_optgroup_for_option: function(option, destination) 
	{
		var parent = $(option).parent();
		
		// se o parent for um SELECT, a option pode ser movida diretamente para destination
		if ($(parent).get(0).nodeName.toUpperCase() == 'SELECT')
			return destination;
		
		// se o parent for um OPTGROUP, verificar se ele existe no destino e cria-lo se necessário
		var name = $(parent).attr('label');
		
		var group = $(destination).find('OPTGROUP[label="'+ name +'"]');
		
		if (group.html()) {
			return group;
		}
		else {
			var clone = $(parent).clone();
			$(clone).empty();
			$(destination).append(clone);
			
			return clone;
		}
	},
	
	
	/**
	 * sort alphabetically the options inside a select/optgroup
	 * 
	 * @param	jQueryDOMReference	optgroup	Reference for select|optgroup whose options must be sorted
	 */
	sort_options: function(optgroup)
	{
		$(optgroup).find('OPTION').sortElements(function(a, b){
			return $(a).text() > $(b).text() ? 1 : -1;
		});
	},
	
	
	/**
	 * tries to identify the form container which stores the double list
	 * 
	 * @param	jQueryDOMObject 	children
	 */
	get_form_holder: function(children)
	{
		var parent_node = $(children).parent();
		
		var node = $(parent_node).get(0).nodeName.toUpperCase();
		
		if (node == 'BODY' || node == 'HTML') {
			// Unable to register double list to a form due poorly formatted HTML
			parent_node = false;
		}
		else if (node != 'FORM')
			parent_node = this.get_form_holder(parent);
			
		return parent_node;
	}
	
};
