function dumps(arr,level) {
var dumped_text = "";
if(!level) level = 0;

//The padding given at the beginning of the line.
var level_padding = "";
for(var j=0;j<level+1;j++) level_padding += "    ";

if(typeof(arr) == 'object') { //Array/Hashes/Objects
 for(var item in arr) {
  var value = arr[item];

  if(typeof(value) == 'object') { //If it is an array,
   dumped_text += level_padding + "'" + item + "' ...<br />";
   dumped_text += dump(value,level+1);
  } else {
   dumped_text += level_padding + "'" + item + "' => \"" + value + "\"<br />";
  }
 }
} else { //Stings/Chars/Numbers etc.
 dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
}
return dumped_text;
}

var selectableChildren = new Class({

	/**
	 * Constructer.
	 * @params: el ELEMENT, params OBJECT
	 * @return: this OBJECT
	 */
	initialize : function(el, params){
		/************************ DEFAULT PROPERTIES ***********************/
		this.selectedChildren 	= [];
		this.el					= false;
		this.targetTagNames		= ['*'];
		this.validChildren		= false;
		this.cssClassSelected	= false;
		this.cssClassUnselected	= false;
		this.eventTriggers		= {
								'toggleSelect'	: ['click']
		};
		this.multiSelectKeys	= ['shiftKey', 'ctrlKey'];
		this.allowMultiSelect	= false;
		/************************* USER DEFINED PROPERTIES ************************/
		this.el = el;
		if(params){
			this.targetTagNames = ($defined(params.targetTagNames))? params.targetTagNames : this.targetTagNames;
			validChildren = ($defined(params.validChildren))? params.validChildren : false;
			this.cssClassSelected = ($defined(params.cssClassSelected))? params.cssClassSelected : this.cssClassSelected;
			this.cssClassUnselected = ($defined(params.cssClassUnselected))? params.cssClassUnselected : this.cssClassUnselected;
			this.eventTriggers = ($defined(params.eventTriggers))? params.eventTriggers : this.eventTriggers;
			this.allowMultiSelect = ($defined(params.allowMultiSelect))? params.allowMultiSelect : this.allowMultiSelect;
		}

		//since the eligible children are not specified, get the valid elements eligible for selection
		if(!validChildren)
		{
			for(var i=0; i<this.targetTagNames.length; i++){
				var validChildren = $$(this.el.getElementsByTagName(this.targetTagNames[i]));
			}
		}
		/*****************************************************************************/

		//this.el.getSelectedChildren = this.getSelectedChildren.bind(this);

		//set up events that will fire selectChild
		if(this.eventTriggers.toggleSelect)
		{
			for(var v=0; v<validChildren.length; v++){
				this.addSelectableChild(validChildren[v]);
			}
		}
	},

	/**
	 * Make a child element eligible for selection
	 *
	 */
	addSelectableChild : function(childEl){
		if(!this.validChildren)
		{
			this.validChildren = [];
		}

		this.validChildren.push(childEl);
		for(var i=0; i<this.eventTriggers.toggleSelect.length; i++){
			childEl.addEvent(this.eventTriggers.toggleSelect[i], this.toggleSelect.bind(this));
		}
		//add the css class if any
		if(this.cssClassUnselected){
			childEl.addClass(this.cssClassUnselected);
		}
	},

	/**
	 * Toggle selection. If selected, deselect, and vice versa
	 * @params: e EVENT OBJECT
	 * @return: BOOLEAN
	 */
	toggleSelect : function(e){
	    //alert('toggleSelect');
		//determine the target element of the event. Since "bind" is used to add this event, we cannot use this anymore here
		var targetEl = (e.srcElement)? e.srcElement : e.target;
		targetEl = $(targetEl);

		//because of event bubbling, we need to determine if the target is indeed the target we are looking for. if not, go up the tree to find it
		while(targetEl && this.validChildren.indexOf(targetEl) == -1){
			targetEl = targetEl.parentNode;
		}

		//if we cannot find any target we are looking for, abort
		if(!targetEl){
			return false;
		}

		//get the index of the target element
		var targetElIndex = this.validChildren.indexOf(targetEl);

		//determine if multiselect or single select
		var multiSelect = false;
		if(this.allowMultiSelect)
		{
			for(var i=0; i<this.multiSelectKeys.length; i++){
				if(eval('e.' + this.multiSelectKeys[i])){
					multiSelect = true;
				}
			}
		}
		//if not multi select, deselect the rest
		if(!multiSelect){
			for(var i=0; i<this.selectedChildren.length; i++){
				if(this.deselectChild(this.selectedChildren[i])){
					i--;
				}
			}
		}
		//if the multiselect key is pressed, allow for multi select.
		//determine if it is already selected
		var is_selected = (this.selectedChildren.indexOf(targetElIndex) != -1);
		if(!is_selected){
			var result = this.selectChild(targetElIndex);
		}
		else{
			var result = this.deselectChild(targetElIndex);
		}

		return result;
	},

	/**
	 * Select child element
	 * @params: targetElIndex INT
	 * @return: NULL
	 */
	selectChild : function(targetElIndex){
	    //alert('selectChild '+targetElIndex);
		var childEl = this.validChildren[targetElIndex];
		//alert('A');
		if(!childEl){
			return false;
		}
		//alert('B');
		if(this.cssClassSelected){
			childEl.addClass(this.cssClassSelected);
		}
		//alert('C');
		if(this.cssClassUnselected){
			childEl.removeClass(this.cssClassUnselected);
		}
		this.selectedChildren.extend([targetElIndex]);
		//alert('D');
        //alert(this.selectedChildren.length);
		return true;
	},

	/**
	 * Deslect child element
	 * @params: targetElIndex INT
	 * @return: BOOLEAN
	 */
	deselectChild : function(targetElIndex){
	    //alert('deselectChild');
		var childEl = this.validChildren[targetElIndex];
		this.selectedChildren.remove(targetElIndex);
		if(!childEl){
			return false;
		}
		if(this.cssClassSelected){
			childEl.removeClass(this.cssClassSelected);
		}

		if(this.cssClassUnselected){
			childEl.addClass(this.cssClassUnselected);
		}
		this.selectedChildren.remove(targetElIndex);
		return true;
	},

	/**
	 * Deslect all element
	 * @params: targetElIndex INT
	 * @return: BOOLEAN
	 */
	deselectAll : function(){
	    //alert('selectAll');
		for(var i=0; i<this.selectedChildren.length; i++){
			this.deselectChild(this.selectedChildren[i]);
		}
	},

	/**
	 * Gets selected children
	 * @params:
	 * @return: Array of Elements
	 */
	getSelectedChildren : function(){
	    //$('divStatus').innerHTML += '-=-=-=-';
		var result = [];
		for(var i=0; i<this.selectedChildren.length; i++){
			result.extend([this.validChildren[this.selectedChildren[i]]]);
		}
		return result;
	}
});

Element.extend({
	makeChildrenSelectable : function(params){
		this.selectableChildrenObj = new selectableChildren(this, params);
		return this.selectableChildrenObj;
	},
	addSelectableChild : function(el){
		this.selectableChildrenObj.addSelectableChild(el);
	},
	getSelectedChildren : function(){
		return this.selectableChildrenObj.getSelectedChildren();
	},
	deselectAll : function(){
		this.selectableChildrenObj.deselectAll();
	}
});
