/**
 * jQuery Tree Control
 *
 * @author Maxim Vasiliev
 */

//This prototype is provided by the Mozilla foundation and
//is distributed under the MIT license.
//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license

if (!Array.prototype.indexOf)
{
  Array.prototype.indexOf = function(elt /*, from*/)
  {
    var len = this.length;

    var from = Number(arguments[1]) || 0;
    from = (from < 0)
         ? Math.ceil(from)
         : Math.floor(from);
    if (from < 0)
      from += len;

    for (; from < len; from++)
    {
      if (from in this &&
          this[from] === elt)
        return from;
    }
    return -1;
  };
}

(function($){

	var CLASS_JQUERY_TREE = 'jquery-tree';
	var CLASS_JQUERY_TREE_CONTROLS = 'jquery-tree-controls';
	var CLASS_JQUERY_TREE_COLLAPSE_ALL = 'jquery-tree-collapseall';
	var CLASS_JQUERY_TREE_EXPAND_ALL = 'jquery-tree-expandall';
	var CLASS_JQUERY_TREE_COLLAPSED = 'jquery-tree-collapsed';
	var CLASS_JQUERY_TREE_HANDLE = 'jquery-tree-handle';
	var CLASS_JQUERY_TREE_TITLE = 'jquery-tree-title';
	var CLASS_JQUERY_TREE_NODE = 'jquery-tree-node';
	var CLASS_JQUERY_TREE_LEAF = 'jquery-tree-leaf';
	var CLASS_JQUERY_TREE_CHECKED = 'jquery-tree-checked';
	var CLASS_JQUERY_TREE_UNCHECKED = 'jquery-tree-unchecked';
	var CLASS_JQUERY_TREE_CHECKED_PARTIAL = 'jquery-tree-checked-partial';

	var COLLAPSE_ALL_CODE = '<span class="' + CLASS_JQUERY_TREE_COLLAPSE_ALL + '">Collapse all</span>';
	var EXPAND_ALL_CODE = '<span class="' + CLASS_JQUERY_TREE_EXPAND_ALL + '">Expand all</span>';
	var TREE_CONTROLS_CODE = '<div class="' + CLASS_JQUERY_TREE_CONTROLS + '">' +
	COLLAPSE_ALL_CODE +
	EXPAND_ALL_CODE +
	'</div>';

	var TREE_NODE_HANDLE_CODE = '<span class="' + CLASS_JQUERY_TREE_HANDLE + '">+</span>';
	var TREE_NODE_HANDLE_COLLAPSED = "+";
	var TREE_NODE_HANDLE_EXPANDED = "&minus;";

	var current_config = {};

	var modified = {
		checked: [],
		unchecked: []
	};

	$.fn.extend({

		/**
		 * <ul>
		 *   <li><label><input type="checkbox" />Item1</label></li>
		 *   <li>
		 *     <label><input type="checkbox" />ItemWithSubitems</label>
		 *     <ul>
		 *       <li><label><input type="checkbox" />Subitem1</label></li>
		 *     </ul>
		 *   </li>
		 * </ul>
		 */
		Tree: function(config){
			
			current_config = config;
			
			// 
			$(this)
				.addClass(CLASS_JQUERY_TREE)
//				.before(TREE_CONTROLS_CODE)
				.prev('.' + CLASS_JQUERY_TREE_CONTROLS)
				.find('.' + CLASS_JQUERY_TREE_COLLAPSE_ALL).click(function(){
					$(this).parent().next('.' + CLASS_JQUERY_TREE)
						.find('li:has(ul)')
						.addClass(CLASS_JQUERY_TREE_COLLAPSED)
						.find('.' + CLASS_JQUERY_TREE_HANDLE)
						.html(TREE_NODE_HANDLE_COLLAPSED);
				})

				.parent('.' + CLASS_JQUERY_TREE_CONTROLS).find('.' + CLASS_JQUERY_TREE_EXPAND_ALL)
					.click(function(){
						$(this).parent().next('.' + CLASS_JQUERY_TREE)
							.find('li:has(ul)')
								.removeClass(CLASS_JQUERY_TREE_COLLAPSED)
							.find('.' + CLASS_JQUERY_TREE_HANDLE)
								.html(TREE_NODE_HANDLE_EXPANDED);
					});

			$('li', this).find(':first').addClass(CLASS_JQUERY_TREE_TITLE)
				.closest('li').addClass(CLASS_JQUERY_TREE_LEAF);

			// 
			$('li:has(ul:has(li))', this).find(':first')
				// 
				.before(TREE_NODE_HANDLE_CODE)
				// 
				.closest('li')
					.addClass(CLASS_JQUERY_TREE_NODE)
					.addClass(CLASS_JQUERY_TREE_COLLAPSED)
					.removeClass(CLASS_JQUERY_TREE_LEAF);

			$('li input:checkbox', this).before('<span class="sbh-pijl" alt="Uitklappen"></span>');

			//
			$('.' + CLASS_JQUERY_TREE_HANDLE, this).bind('click', function(){
				var leafContainer = $(this).parent('li');
				var leafHandle = leafContainer.find('>.' + CLASS_JQUERY_TREE_HANDLE);

				leafContainer.toggleClass(CLASS_JQUERY_TREE_COLLAPSED);

				if (leafContainer.hasClass(CLASS_JQUERY_TREE_COLLAPSED)) {
					leafHandle.html(TREE_NODE_HANDLE_COLLAPSED);
				}
				else {
					leafHandle.html(TREE_NODE_HANDLE_EXPANDED);
				}
			});

			$('input:checkbox', this).click(function() {				
				setLabelClass(this);
				checkCheckbox(this);				
			})
			//
			.each(function(){
				setLabelClass(this);
				
				if (this.checked)
					checkParentCheckboxes(this);
			})
			//
			.closest('label').click(function(event){
				modified = {checked: [], unchecked: []};
				
				/*
				 * Als je op een half-actieve checkbox klikt dan gebeurd er niks
				 */
				if ($(this).hasClass(CLASS_JQUERY_TREE_CHECKED_PARTIAL)) {
					return false;
				}
				

				labelClick(this);
				checkCheckbox($('input:checkbox', this));
				
				/*
				 * Toon the sublaag
				 */
				$(this).parent('li').removeClass(CLASS_JQUERY_TREE_COLLAPSED);
				$(this).parent().find('.' + CLASS_JQUERY_TREE_HANDLE).html(TREE_NODE_HANDLE_EXPANDED);
				
				if (config.callback) {
					config.callback.call(this, modified);				
				}
				
				return false;
			});
			
			/*
			 * Toon the sublaag
			 */
			$('.categ_label').click(function(event){
				var parent_li = $(this).parent('li');
				
				if (parent_li.hasClass(CLASS_JQUERY_TREE_COLLAPSED)) {
					parent_li.removeClass(CLASS_JQUERY_TREE_COLLAPSED);
					$(this).parent().children('.' + CLASS_JQUERY_TREE_HANDLE).html(TREE_NODE_HANDLE_EXPANDED);
					
				} else {
					parent_li.addClass(CLASS_JQUERY_TREE_COLLAPSED);
					$(this).parent().children('.' + CLASS_JQUERY_TREE_HANDLE).html(TREE_NODE_HANDLE_COLLAPSED);					
				}
			});
		}
	});

	/**
	 * 
	 * @param {Object} checkboxElement
	 */
	function checkParentCheckboxes(checkboxElement){
		if (typeof checkboxElement == 'undefined' || !checkboxElement)
			return;

		// 
		var closestNode = $(checkboxElement).closest('ul');
		var allCheckboxes = closestNode.find('input:checkbox');
		var checkedCheckboxes = closestNode.find('input:checkbox:checked');

		var allChecked = allCheckboxes.length == checkedCheckboxes.length;

		var parentCheckbox = closestNode.closest('li').find('>.' + CLASS_JQUERY_TREE_TITLE + ' input:checkbox');

		if (parentCheckbox.length > 0) {
			parentCheckbox.get(0).checked = allChecked;

			if (!allChecked && checkedCheckboxes.length > 0) {
				if (modified.unchecked.indexOf(parentCheckbox.get(0).value) == -1) {
					//modified.unchecked.push( parseInt(parentCheckbox.get(0).value, 10) ); 
				}
				
				parentCheckbox.closest('label')
				.addClass(CLASS_JQUERY_TREE_CHECKED_PARTIAL)
				.removeClass(CLASS_JQUERY_TREE_CHECKED)
				.removeClass(CLASS_JQUERY_TREE_UNCHECKED);
			}
			else {
				if (allChecked) {
					if (modified.checked.indexOf(parentCheckbox.get(0).value) == -1) {
						modified.checked.push( parseInt(parentCheckbox.get(0).value, 10) ); 
					}

					parentCheckbox.closest('label')
					.removeClass(CLASS_JQUERY_TREE_CHECKED_PARTIAL)
					.removeClass(CLASS_JQUERY_TREE_UNCHECKED)
					.addClass(CLASS_JQUERY_TREE_CHECKED);
				} else {
										
					parentCheckbox.closest('label')
					.removeClass(CLASS_JQUERY_TREE_CHECKED_PARTIAL)
					.removeClass(CLASS_JQUERY_TREE_CHECKED)
					.addClass(CLASS_JQUERY_TREE_UNCHECKED);
				}
			}
			
			checkParentCheckboxes(parentCheckbox.get(0));
		}
	}
	/**
	 * 
	 */
	function checkCheckbox(checkboxElement){
		
		// 
		$(checkboxElement).closest('li').find('input:checkbox').each(function(){
			this.checked = $(checkboxElement).attr('checked');
			setLabelClass(this);			
		});
		checkParentCheckboxes(checkboxElement);		
	};

	/**
	 * 
	 */
	function setLabelClass(checkboxElement){
		isChecked = $(checkboxElement).attr('checked');
		
		if (isChecked) {
			$(checkboxElement).closest('label')
				.addClass(CLASS_JQUERY_TREE_CHECKED)
				.removeClass(CLASS_JQUERY_TREE_UNCHECKED)
				.removeClass(CLASS_JQUERY_TREE_CHECKED_PARTIAL);
		}
		else {
			$(checkboxElement).closest('label')
				.addClass(CLASS_JQUERY_TREE_UNCHECKED)
				.removeClass(CLASS_JQUERY_TREE_CHECKED)
				.removeClass(CLASS_JQUERY_TREE_CHECKED_PARTIAL);
		}
	};

	/**
	 * 
	 */
	function labelClick(labelElement){		
		var checkbox = $('input:checkbox', labelElement);	
		var checked = checkbox.attr('checked');

		checkbox.attr('checked', !checked);
		
		if (!checked && modified.checked.indexOf(checkbox.attr('value')) == -1) {
			modified.checked.push( parseInt(checkbox.attr('value'), 10) ); 
		} else if (checked && modified.unchecked.indexOf(checkbox.attr('value')) == -1) {
			modified.unchecked.push( parseInt(checkbox.attr('value'), 10) ); 
		}
		
		setLabelClass(checkbox, 'labelClick');	
	}

})(jQuery);