/*
 *	Requires rico.js
 */

function treeview ( wrapper, treeARR )
{
	this._init = function ( wrapper, treeARR )
	{
		if ( wrapper )
		{
			if ( document.getElementById(wrapper) )
			{
				this.wrapper = document.getElementById(wrapper);
			}
			else
			{
				this.wrapper = wrapper;
			}
		}
		this.imageResize = '100%';
		this.categoryUpdater = function ( parentId, itemId ) { window.alert ( 'UPDATER: category; ITEMID: ' + itemId + '; PARENTID: ' + parentId + ';' ); };
		this.itemUpdater = function ( parentId, itemId ) { window.alert ( 'UPDATER: item; ITEMID: ' + itemId + '; PARENTID: ' + parentId + ';' ); };
		this.categoryOpenedImg = null;
		this.categoryClosedImg = null;
		this.itemImg = null;
		this.itemConnectorL = null;
		this.itemConnectorT = null;
		this.itemFunction = function () { window.alert ('No itemFunction was defined.') }
		this.categoryFunction = function () { window.alert ('No categoryFunction was defined.') }
		this.treeARR = treeARR;
		this.treeOBJ = document.createElement ( 'UL' );
		this.treeMgr = new CustomDragAndDrop();
		this.treeMgr.initializeEventHandlers();	
	}
	
	this.getParentId = function ( obj, firstMatch )
	{
		if ( !obj ) return ( 0 );
		if ( !obj.parentNode ) return ( 0 );
		parent = obj.parentNode;
		while ( parent )
		{
			//window.alert ( 'Is category: ' + parent.category + '; ItemId: ' + parent.itemId );
			if ( parent.category == true && parent.itemId )
			{
				if ( firstMatch )
				{
					return ( parent.itemId );
				}
				else
				{
					firstMatch = true;	
				}
			}
			if ( !parent.parentNode ) return ( 0 );
			parent = parent.parentNode;
		}
		return ( 0 );
	}
	
	this.getParentObj = function ( obj, firstMatch )
	{
		if ( !obj ) { return ( 0 ); };
		if ( !obj.parentNode ) { return ( 0 ); }
		parent = obj.parentNode;
		while ( parent )
		{
			if ( parent.category == true && parent.itemId )
			{
				if ( firstMatch )
				{
					return ( parent );
				}
				else
				{
					firstMatch = true;	
				}
			}
			if ( !parent.parentNode ) return ( 0 );
			parent = parent.parentNode;
		}
		return ( 0 );
	}
	
	this._fetch_tree = function ( treepieceARR )
	{
		var ul = document.createElement ( 'UL' );
		for ( var i = 0; i < treepieceARR.length; i++ )
		{
			var li = document.createElement ( 'LI' );
			li.itemName = treepieceARR[i]['name'];
			if ( treepieceARR[i]['type'].toString().toUpperCase() == 'CATEGORY' )
			{
				li.itemId = treepieceARR[i]['id'];
				li.innerHTML = "<table><tr style='vertical-align: middle;'><td style='text-align: right;'><img class='categoryCollection' src='" + this.categoryClosedImg + "' /></td><td style='padding-bottom: 8px;'>" + treepieceARR[i]['name'] + "</td></tr></table>";
				li.category = true;
				li.getElementsByTagName('TD')[1].itemId = treepieceARR[i]['id'];
				li.getElementsByTagName('TD')[1].onclick = this.categoryFunction;
			}
			else
			{
				if ( i == treepieceARR.length - 1 )
				{
					var imgConnector = '';
					//var imgConnector = "<img src='" + this.itemConnectorL + "' />";
				}
				else
				{
					var imgConnector = '';
					//var imgConnector = "<img src='" + this.itemConnectorT + "' />";
				}
				li.innerHTML = "<table><tr style='vertical-align: middle;'><td>" + imgConnector + "</td><td style='text-align: right;'><img src='" + this.itemImg + "' /></td><td style='padding-bottom: 5px;'>" + treepieceARR[i]['name'] + "</td></tr></table>";
				li.isItem = true;
				li.itemId = treepieceARR[i]['id'];
				li.getElementsByTagName('TD')[2].itemId = treepieceARR[i]['id'];
				li.getElementsByTagName('TD')[2].onclick = this.itemFunction;
			}
			if ( treepieceARR[i]['sub'] )
			{
					li.appendChild ( this._fetch_tree ( treepieceARR[i]['sub'] ) );
			}
			else
			{
				li.appendChild(document.createElement('UL'));
			}
			ul.appendChild ( li );
		}
		return ( ul );
	}
	
	this.collapseAll = function ()
	{
		var thisObj = this;
		var imgs = this.wrapper.getElementsByTagName('IMG');
		for ( var i = 0; i < imgs.length; i++ )
		{
			if ( imgs[i].className == 'categoryCollection' )
			{
				imgs[i].ondblclick = function () { thisObj.collapse ( this ); }
				this.collapse ( imgs[i] );
			}
		}
	}
	
	this.collapse = function ( obj )
	{
		var thisObj = this;
		interestedOBJ = obj.parentNode.parentNode.parentNode.parentNode.parentNode;
		if ( interestedOBJ.getElementsByTagName('UL')[0] )
		{
			interestedOBJ.getElementsByTagName('UL')[0].style.display = 'none';
			obj.src = this.categoryClosedImg;
			obj.ondblclick = function () { thisObj.expand ( this ); }
		}
	}
	
	this.expandAll = function ()
	{
		var thisObj = this;
		var imgs = this.wrapper.getElementsByTagName('IMG');
		for ( var i = 0; i < imgs.length; i++ )
		{
			if ( imgs[i].className == 'categoryCollection' )
			{
				imgs[i].ondblclick = function () { thisObj.expand ( this ); }
				this.expand ( imgs[i] );
			}
		}
	}
	
	this.expand = function ( obj )
	{
		var thisObj = this;
		interestedOBJ = obj.parentNode.parentNode.parentNode.parentNode.parentNode;
		if ( interestedOBJ.getElementsByTagName('UL')[0] )
		{
			interestedOBJ.getElementsByTagName('UL')[0].style.display = 'block';
			obj.src = this.categoryOpenedImg;
			obj.ondblclick = function () { thisObj.collapse ( this ); }
		}
	}
	
	this._initDnD = function ()
	{
		var lis = this.wrapper.getElementsByTagName('LI');
		for ( var i = 0; i < lis.length; i++ )
		{
			//treeMgr.registerDraggable( new CustomDraggable(lis[i], "<div style='background: #000; color: #FFF; weight: 800; border: 2px solid #345234; padding: 5px;'>Dragging some items...</div>") );
			this.treeMgr.registerDraggable( new CustomDraggable(lis[i], "<img src='/images/admin/person.png' />" ) );  
		}
		for ( i = 0; i < lis.length; i++ )
		{
			if ( lis[i].category )
			{
				var drop = new CustomDropzone( lis[i] );
				drop.updateCategory = this.categoryUpdater;
				drop.updateItem = this.itemUpdater;
				this.treeMgr.registerDropZone( drop );
				//window.alert ( drop );
			}
		}
	}
	
	this.display = function ( ignoreDnD )
	{
		this.wrapper.appendChild ( this._fetch_tree ( this.treeARR ) );
		if ( !ignoreDnD ) this._initDnD ();
		this.collapseAll();
	}
	
	this.addItem = function ( parentId, itemId, itemName )
	{
		var lis = this.wrapper.getElementsByTagName('LI');
		for ( var i = 0; i < lis.length; i++ )
		{
			if ( lis[i].category && lis[i].itemId == parentId )
			{
				if ( lis[i].getElementsByTagName('UL')[0] )
				{
					var ul = lis[i].getElementsByTagName('UL')[0];
				}
				else
				{
					var ul = document.createElement('UL');
					lis[i].appendChild(ul);
				}
				var li = document.createElement ( 'LI' );
				li.innerHTML = "<table><tr style='vertical-align: middle;'><td></td><td style='text-align: right;'><img src='" + this.itemImg + "' /></td><td style='padding-bottom: 5px;'>" + itemName + "</td></tr></table>";
				li.itemName = itemName;
				li.isItem = true;
				li.itemId = itemId;
				li.getElementsByTagName('TD')[2].itemId = itemId;
				li.getElementsByTagName('TD')[2].onclick = this.itemFunction;
				this.treeMgr.registerDraggable( new CustomDraggable(li, "<img src='/images/admin/person.png' />" ) );
				ul.appendChild(li);
				parentObj = this.getParentObj ( li, true );
				this.sortCategory ( parentObj );
			}
		}
	}
	
	this.addCategory = function ( parentId, itemId, itemName )
	{
		var thisObj = this;
		var lis = this.wrapper.getElementsByTagName('LI');
		for ( var i = 0; i < lis.length; i++ )
		{
			if ( lis[i].category && lis[i].itemId == parentId )
			{
				if ( lis[i].getElementsByTagName('UL')[0] )
				{
					var ul = lis[i].getElementsByTagName('UL')[0];
				}
				else
				{
					var ul = document.createElement('UL');
					lis[i].appendChild(ul);
				}
				var li = document.createElement ( 'LI' );
				li.innerHTML = "<table><tr style='vertical-align: middle;'><td style='text-align: right;'><img class='categoryCollection' src='" + this.categoryClosedImg + "' /></td><td style='padding-bottom: 8px;'>" + itemName + "</td></tr></table>";
				li.category = true;
				li.itemId = itemId;
				li.itemName = itemName;
				li.getElementsByTagName('TD')[1].itemId = itemId;
				li.getElementsByTagName('TD')[1].onclick = thisObj.categoryFunction;
				this.treeMgr.registerDraggable( new CustomDraggable(li, "<img src='/images/admin/person.png' />" ) );
				li.getElementsByTagName('IMG')[0].ondblclick = function () { thisObj.expand ( this ); }
				this.expand ( li.getElementsByTagName('IMG')[0] );
				li.appendChild(document.createElement('UL'));
				ul.appendChild(li);
				var drop = new CustomDropzone( li );
				drop.updateCategory = function () { thisObj.categoryUpdater; }
				drop.updateItem = function () { thisObj.itemUpdater; }
				this.treeMgr.registerDropZone( drop );
				parentObj = this.getParentObj ( li, true );
				this.sortCategory ( parentObj );
			}
		}
	}
	
	this.updateItem = function ( itemId, newValue )
	{
		var items = this.wrapper.getElementsByTagName('LI');
		for ( var i = 0; i < items.length; i++ )
		{
			if ( items[i].isItem && items[i].itemId == itemId )
			{
				items[i].getElementsByTagName('TD')[2].innerHTML = newValue;
			}
		}
	}
	
	this.updateCategory = function ( itemId, newValue )
	{
		var items = this.wrapper.getElementsByTagName('LI');
		for ( var i = 0; i < items.length; i++ )
		{
			if ( items[i].category && items[i].itemId == itemId )
			{
				items[i].getElementsByTagName('TD')[1].innerHTML = newValue;
			}
		}
	}
	
	this.delItem = function ( itemId )
	{
		var lis = this.wrapper.getElementsByTagName('LI');
		if ( lis.length )
		{
			for ( var i = 0; i < lis.length; i++ )
			{
				if ( lis[i].isItem && lis[i].itemId == itemId )
				{
					lis[i].parentNode.removeChild(lis[i]);
					return ( true );
				}
			}
		}
	}
	
	this.delCategory = function ( itemId )
	{
		var lis = this.wrapper.getElementsByTagName('LI');
		if ( lis.length )
		{
			for ( var i = 0; i < lis.length; i++ )
			{
				if ( lis[i].category && lis[i].itemId == itemId )
				{
					lis[i].parentNode.removeChild(lis[i]);
					return ( true );
				}
			}
		}
	}
	
	this.sortCategory = function ( obj )
   { 
		if ( !obj.getElementsByTagName('UL')[0] ) { return; }
		obj = obj.getElementsByTagName('UL')[0];
		//Get objects into associative array
		var childItems = new Array ();
		var childItemCollector = new Array ();
		var childCategories = new Array ();
		var childCategoryCollector = new Array ();
		for ( var i = 0; i < obj.childNodes.length; i++ )
		{
			if ( obj.childNodes[i].isItem )
			{
				childItems[obj.childNodes[i].itemName] = obj.childNodes[i];
				childItemCollector[i] = obj.childNodes[i].itemName;
			}
			if ( obj.childNodes[i].category )
			{
				childCategories[obj.childNodes[i].itemName] = obj.childNodes[i];
				childCategoryCollector[i] = obj.childNodes[i].itemName;
			}
		}
		//Create an array to hold the sorted arrays
		var sortedARR = new Array ();
		//Sort the arrays
		for ( var i = 0; i < childCategoryCollector.length; i++ )
		{
			sortedARR[sortedARR.length] = childCategories[childCategoryCollector.sort()[i]];
		}
		for ( var i = 0; i < childItemCollector.length; i++ )
		{
			sortedARR[sortedARR.length] = childItems[childItemCollector.sort()[i]];
		}
		//Clear the UL object;
		obj.innerHTML = '';
		//Insert the previously collected objects sorted
		//window.alert ( sortedARR.length );
		for ( var i = 0; i < sortedARR.length; i++ )
		{
			//window.alert ( sortedARR[i] );
			if ( sortedARR[i] )
			{
				obj.appendChild(sortedARR[i]);
			}
		}
	}
	
	this._init ( wrapper, treeARR );
}


/*
 *	RICO Extensions to make
 *  treeview work properly
 *
 *  use treeMgr to handle the tree created with make_tree();
 */

var CustomDraggable = Class.create();
CustomDraggable.removeOnDrop = true; 
CustomDraggable.prototype = (new Rico.Draggable()).extend( {

   initialize: function( htmlElement, name ) {
      this.type        = 'Custom';
      this.htmlElement = $(htmlElement);
      this.name        = name;
   },

   log: function(str) {
      new Insertion.Bottom( $('logger'), "<span class='logMsg'>" + str + "</span>" );
      $('logger').scrollTop = $('logger').lastChild.offsetTop;

   },

   select: function() {
      this.selected = true;
      var el = this.htmlElement;

      // show the item selected.....
      el.style.opacity = ".75";
   },

   deselect: function() {
      this.selected = false;
      var el = this.htmlElement;
      el.style.opacity = "1";
   },

   startDrag: function() {
      var el = this.htmlElement;
    },

   cancelDrag: function() {
      var el = this.htmlElement;
      this.deselect();
   },

   endDrag: function() {
      var el = this.htmlElement;
      this.deselect();
   },

   getSingleObjectDragGUI: function() {
      var el = this.htmlElement;

      var div = document.createElement("div");
      div.className = 'customDraggable';
      div.style.width = this.htmlElement.offsetWidth - 10;
      new Insertion.Top( div, this.name );
      return div;
   },

   getMultiObjectDragGUI: function( draggables ) {
      var el = this.htmlElement;

      var names = "1";
      /*for ( var i = 0 ; i < draggables.length ; i++ ) {
         names += draggables[i].name;
         if ( i != (draggables.length - 1) )
            names += ",<br/>";
      }*/

      var div = document.createElement("div");
      div.className = 'customDraggable';
      div.style.width = this.htmlElement.offsetWidth - 10;
      new Insertion.Top( div, names );
      return div;
   },

   getDroppedGUI: function() {
      var el = this.htmlElement;
	  //window.alert ( el.innerHTML );
      //el.parentNode.removeChild(el);
      return el;
   }

} );






var CustomDropzone = Class.create();

CustomDropzone.prototype = (new Rico.Dropzone()).extend( {

   initialize: function( htmlElement ) {
      this.htmlElement  = $(htmlElement);
      this.absoluteRect = null;
	  return ( this );
   },

   getHTMLElement: function() {
      return this.htmlElement;
   },

   clearPositionCache: function() {
      this.absoluteRect = null;
   },

   getAbsoluteRect: function() {
      if ( this.absoluteRect == null ) {
         var htmlElement = this.getHTMLElement();
         var pos = RicoUtil.toViewportPosition(htmlElement);

         this.absoluteRect = {
            top:    pos.y,
            left:   pos.x,
            bottom: pos.y + htmlElement.offsetHeight,
            right:  pos.x + htmlElement.offsetWidth
         };
      }
      return this.absoluteRect;
   },

   activate: function() {
      var htmlElement = this.getHTMLElement();
      if (htmlElement == null  || this.showingActive)
         return;

      this.showingActive = true;
      //this.saveBackgroundColor = htmlElement.style.backgroundColor;

      var fallbackColor = "#ffea84";
      var currentColor = Rico.Color.createColorFromBackground(htmlElement);
      if ( currentColor == null )
      {
         //htmlElement.style.backgroundColor = fallbackColor;
      }
      else {
         currentColor.isBright() ? currentColor.darken(0.2) : currentColor.brighten(0.2);
         //htmlElement.style.backgroundColor = currentColor.asHex();
      }
   },

   deactivate: function() {
      var htmlElement = this.getHTMLElement();
      if (htmlElement == null || !this.showingActive)
         return;

      //htmlElement.style.backgroundColor = this.saveBackgroundColor;
      this.showingActive = false;
      this.saveBackgroundColor = null;
   },

   showHover: function() {
      var htmlElement = this.getHTMLElement();
      //if ( htmlElement == null || this.showingHover )
      //   return;

      //this.saveBorderWidth = htmlElement.style.borderWidth;
      //this.saveBorderStyle = htmlElement.style.borderStyle;
      //this.saveBorderColor = htmlElement.style.borderColor;
      this.showingHover = true;
      htmlElement.style.textDecoration = 'underline';
      htmlElement.style.borderWidth = '2px';
      htmlElement.style.borderStyle = "dashed";
      //htmlElement.style.borderColor = "#ff9900";
      htmlElement.style.borderColor = "#000";
   },

   hideHover: function() {
      var htmlElement = this.getHTMLElement();
      if ( htmlElement == null || !this.showingHover )
         return;

      htmlElement.style.borderWidth = '';
      htmlElement.style.borderStyle = '';
      htmlElement.style.borderColor = '';
      this.showingHover = false;
   },

   canAccept: function(draggableObjects) {
      return true;
   },

   accept: function(draggableObjects) {
      var htmlElement = this.getHTMLElement();
      if ( htmlElement == null )
         return;

      n = draggableObjects.length;
      for ( var i = 0 ; i < n ; i++ )
      {
         var theGUI = draggableObjects[i].getDroppedGUI();
         if ( RicoUtil.getElementsComputedStyle( theGUI, "position" ) == "absolute" )
         {
            theGUI.style.position = "static";
            theGUI.style.top = "";
            theGUI.style.top = "";
         }
		 if ( theGUI.isItem )
		 {
		 	this.updateItem ( htmlElement.itemId, theGUI.itemId );
		 }
		 if ( theGUI.category )
		 {
		 	this.updateCategory ( htmlElement.itemId, theGUI.itemId );
		 }
		 var uls = htmlElement.getElementsByTagName ( 'UL' );
		 if ( !uls.length ) 
		 {
			 var ul = document.createElement ( 'UL' );
			 ul.appendChild(theGUI);
		 }
		 else
		 {
			var ul = uls[0];
			ul.appendChild(theGUI);
		 }
		 htmlElement.appendChild(ul);
      }
   },
   
   updateItem: function ( parentId, itemId )
   {
   	
   },
   
   updateCategory: function ( parentId, itemId )
   {
   
   }
} );






var CustomDragAndDrop = Class.create();

CustomDragAndDrop.prototype = (new Rico.DragAndDrop()).extend( {

   initialize: function() {
      this.dropZones                = new Array();
      this.draggables               = new Array();
      this.currentDragObjects       = new Array();
      this.dragElement              = null;
      this.lastSelectedDraggable    = null;
      this.currentDragObjectVisible = false;
      this.interestedInMotionEvents = false;
      this._mouseDown = this._mouseDownHandler.bindAsEventListener(this);
      this._mouseMove = this._mouseMoveHandler.bindAsEventListener(this);
      this._mouseUp = this._mouseUpHandler.bindAsEventListener(this);
   },

   registerDropZone: function(aDropZone) {
      this.dropZones[ this.dropZones.length ] = aDropZone;
   },

   deregisterDropZone: function(aDropZone) {
      var newDropZones = new Array();
      var j = 0;
      for ( var i = 0 ; i < this.dropZones.length ; i++ ) {
         if ( this.dropZones[i] != aDropZone )
            newDropZones[j++] = this.dropZones[i];
      }

      this.dropZones = newDropZones;
   },

   clearDropZones: function() {
      this.dropZones = new Array();
   },

   registerDraggable: function( aDraggable ) {
      this.draggables[ this.draggables.length ] = aDraggable;
      this._addMouseDownHandler( aDraggable );
   },

   clearSelection: function() {
      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
         this.currentDragObjects[i].deselect();
      this.currentDragObjects = new Array();
      this.lastSelectedDraggable = null;
   },

   hasSelection: function() {
      return this.currentDragObjects.length > 0;
   },

   setStartDragFromElement: function( e, mouseDownElement ) {
      this.origPos = RicoUtil.toDocumentPosition(mouseDownElement);
      this.startx = e.screenX - this.origPos.x
      this.starty = e.screenY - this.origPos.y
      //this.startComponentX = e.layerX ? e.layerX : e.offsetX;
      //this.startComponentY = e.layerY ? e.layerY : e.offsetY;
      //this.adjustedForDraggableSize = false;

      this.interestedInMotionEvents = this.hasSelection();
      this._terminateEvent(e);
   },

   updateSelection: function( draggable, extendSelection ) {
      if ( ! extendSelection )
         this.clearSelection();

      if ( draggable.isSelected() ) {
         this.currentDragObjects.removeItem(draggable);
         draggable.deselect();
         if ( draggable == this.lastSelectedDraggable )
            this.lastSelectedDraggable = null;
      }
      else {
         this.currentDragObjects[ this.currentDragObjects.length ] = draggable;
         draggable.select();
         this.lastSelectedDraggable = draggable;
      }
   },

   _mouseDownHandler: function(e) {
      if ( arguments.length == 0 )
         e = event;

      // if not button 1 ignore it...
      var nsEvent = e.which != undefined;
      if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
         return;

      var eventTarget      = e.target ? e.target : e.srcElement;
      var draggableObject  = eventTarget.draggable;

      var candidate = eventTarget;
      while (draggableObject == null && candidate.parentNode) {
         candidate = candidate.parentNode;
         draggableObject = candidate.draggable;
      }
   
      if ( draggableObject == null )
         return;

      this.updateSelection( draggableObject, e.ctrlKey );

      // clear the drop zones postion cache...
      if ( this.hasSelection() )
         for ( var i = 0 ; i < this.dropZones.length ; i++ )
            this.dropZones[i].clearPositionCache();

      this.setStartDragFromElement( e, draggableObject.getMouseDownHTMLElement() );
   },


   _mouseMoveHandler: function(e) {
      var nsEvent = e.which != undefined;
      if ( !this.interestedInMotionEvents ) {
         //this._terminateEvent(e);
         return;
      }

      if ( ! this.hasSelection() )
         return;

      if ( ! this.currentDragObjectVisible )
         this._startDrag(e);


      if ( !this.activatedDropZones )
         this._activateRegisteredDropZones();

      //if ( !this.adjustedForDraggableSize )
      //   this._adjustForDraggableSize(e);

      this._updateDraggableLocation(e);
      this._updateDropZonesHover(e);

      this._terminateEvent(e);
   },

   _makeDraggableObjectVisible: function(e)
   {
      if ( !this.hasSelection() )
         return;

      var dragElement;
      if ( this.currentDragObjects.length > 1 )
         dragElement = this.currentDragObjects[0].getMultiObjectDragGUI(this.currentDragObjects);
      else
         dragElement = this.currentDragObjects[0].getSingleObjectDragGUI();

      // go ahead and absolute position it...
      if ( RicoUtil.getElementsComputedStyle(dragElement, "position")  != "absolute" )
         dragElement.style.position = "absolute";

      // need to parent him into the document...
      if ( dragElement.parentNode == null || dragElement.parentNode.nodeType == 11 )
         document.body.appendChild(dragElement);

      this.dragElement = dragElement;
      this._updateDraggableLocation(e);

      this.currentDragObjectVisible = true;
   },

   /**
   _adjustForDraggableSize: function(e) {
      var dragElementWidth  = this.dragElement.offsetWidth;
      var dragElementHeight = this.dragElement.offsetHeight;
      if ( this.startComponentX > dragElementWidth )
         this.startx -= this.startComponentX - dragElementWidth + 2;
      if ( e.offsetY ) {
         if ( this.startComponentY > dragElementHeight )
            this.starty -= this.startComponentY - dragElementHeight + 2;
      }
      this.adjustedForDraggableSize = true;
   },
   **/

   _leftOffset: function(e) {
	   return e.offsetX ? document.body.scrollLeft : 0
	},

   _topOffset: function(e) {
	   return e.offsetY ? document.body.scrollTop:0
	},

		
   _updateDraggableLocation: function(e) {
      var dragObjectStyle = this.dragElement.style;
      dragObjectStyle.left = (e.screenX + this._leftOffset(e) - this.startx) + "px"
      dragObjectStyle.top  = (e.screenY + this._topOffset(e) - this.starty) + "px";
   },

   _updateDropZonesHover: function(e) {
      var n = this.dropZones.length;
      for ( var i = 0 ; i < n ; i++ ) {
         if ( ! this._mousePointInDropZone( e, this.dropZones[i] ) )
            this.dropZones[i].hideHover();
      }

      for ( var i = 0 ; i < n ; i++ ) {
         if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
            if ( this.dropZones[i].canAccept(this.currentDragObjects) )
               this.dropZones[i].showHover();
         }
      }
   },

   _startDrag: function(e) {
      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
         this.currentDragObjects[i].startDrag();

      this._makeDraggableObjectVisible(e);
   },

   _mouseUpHandler: function(e) {
      if ( ! this.hasSelection() )
         return;

      var nsEvent = e.which != undefined;
      if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
         return;

      this.interestedInMotionEvents = false;

      if ( this.dragElement == null ) {
         this._terminateEvent(e);
         return;
      }

      if ( this._placeDraggableInDropZone(e) )
         this._completeDropOperation(e);
      else {
         this._terminateEvent(e);
         new Rico.Effect.Position( this.dragElement,
                              this.origPos.x,
                              this.origPos.y,
                              200,
                              20,
                              { complete : this._doCancelDragProcessing.bind(this) } );
      }

     Event.stopObserving(document.body, "mousemove", this._mouseMove);
     Event.stopObserving(document.body, "mouseup",  this._mouseUp);
   },

   _retTrue: function () {
      return true;
   },
	
   sort: function ( obj )
   { 
		if ( !obj.getElementsByTagName('UL')[0] ) return;
		obj = obj.getElementsByTagName('UL')[0];
		//Get objects into associative array
		var childItems = new Array ();
		var childItemCollector = new Array ();
		var childCategories = new Array ();
		var childCategoryCollector = new Array ();
		for ( var i = 0; i < obj.childNodes.length; i++ )
		{
			if ( obj.childNodes[i].isItem )
			{
				childItems[obj.childNodes[i].itemName] = obj.childNodes[i];
				childItemCollector[i] = obj.childNodes[i].itemName;
			}
			if ( obj.childNodes[i].category )
			{
				childCategories[obj.childNodes[i].itemName] = obj.childNodes[i];
				childCategoryCollector[i] = obj.childNodes[i].itemName;
			}
		}
		//Create an array to hold the sorted arrays
		var sortedARR = new Array ();
		//Sort the arrays
		for ( var i = 0; i < childCategoryCollector.length; i++ )
		{
			sortedARR[sortedARR.length] = childCategories[childCategoryCollector.sort()[i]];
		}
		for ( var i = 0; i < childItemCollector.length; i++ )
		{
			sortedARR[sortedARR.length] = childItems[childItemCollector.sort()[i]];
		}
		//Clear the UL object;
		obj.innerHTML = '';
		//Insert the previously collected objects sorted
		//window.alert ( sortedARR.length );
		for ( var i = 0; i < sortedARR.length; i++ )
		{
			//window.alert ( sortedARR[i] );
			if ( sortedARR[i] )
			{
				obj.appendChild(sortedARR[i]);
			}
		}
	},
	
   _completeDropOperation: function(e) {
      if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) {
         if ( this.dragElement.parentNode != null )
            this.dragElement.parentNode.removeChild(this.dragElement);
      }

      this._deactivateRegisteredDropZones();
      this._endDrag();
      this.clearSelection();
      this.dragElement = null;
      this.currentDragObjectVisible = false;
      this._terminateEvent(e);
      this.sort(this.dropZones[this._deepestDropZone(e)].getHTMLElement());
   },

   _doCancelDragProcessing: function() {
      this._cancelDrag();

        if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() && this.dragElement)
           if ( this.dragElement.parentNode != null )
              this.dragElement.parentNode.removeChild(this.dragElement);


      this._deactivateRegisteredDropZones();
      this.dragElement = null;
      this.currentDragObjectVisible = false;
   },

	_isNested: function ( dragObj, dropObj )
	{
		parent = dropObj.htmlElement;
		while ( ! ( parent.tagName == 'BODY' || parent.tagName == null ) )
		{
			if ( parent == dragObj[0].htmlElement )
			{
				for ( j = 0; j < this.dropZones.length; j++ )
				{
					this.dropZones[j].hideHover();
				}
				return ( true );
			}
			parent = parent.parentNode;
		}
		return ( false );
	},
	
	_isNestedElement: function ( possibleParentElement, possibleNestedElement )
	{
		var parent = possibleNestedElement;
		while ( ! ( parent.tagName == 'BODY' || parent.tagName == null ) )
		{
			//window.alert ( 'PARENT: ' + parent.itemName + "\n" + 'CHECKED: ' + possibleParentElement.itemName );
			if ( parent == possibleParentElement )
			{
				return ( true );
			}
			parent = parent.parentNode;
		}
		return ( false );
	},

   _deepestDropZone: function (e)
   {
	   var deepestId = -1;
	    for ( var i = 0; i < this.dropZones.length; i++ )
		{
			if ( this._mousePointInDropZone( e, this.dropZones[i] ) )
		    {
			   if ( this.dropZones[i].canAccept(this.currentDragObjects ) )
			   {
			   		if ( deepestId == -1 ) deepestId = i;
					if ( previousId >= 0 )
					{
						if ( deepestId != i )
						{
							if ( this._isNestedElement ( this.dropZones[deepestId].htmlElement, this.dropZones[i].htmlElement ) ) deepestId = i;
							previousId = i;
						}
					}
					else
					{
						var previousId = i;
					} 
			   }
			}
		}
		return ( deepestId );
   },
   
   _placeDraggableInDropZone: function(e) {
      var foundDropZone = false;
      var dropZoneId = this._deepestDropZone (e);
	  if ( dropZoneId > -1 )
	  {
		 if ( this._isNested ( this.currentDragObjects, this.dropZones[dropZoneId] ) )
		 {
				foundDropZone = false;
		 }
		 else
		 {
		 	for ( var j = 0; j < this.dropZones.length; j++ )
		 	{
         		this.dropZones[j].hideHover();
         	}
         	this.dropZones[dropZoneId].accept(this.currentDragObjects);
         	foundDropZone = true;
		 }
	  }
      return foundDropZone;
   },

   _cancelDrag: function() {
      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
         this.currentDragObjects[i].cancelDrag();
   },

   _endDrag: function() {
      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
         this.currentDragObjects[i].endDrag();
   },

   _mousePointInDropZone: function( e, dropZone ) {

      var absoluteRect = dropZone.getAbsoluteRect();

      return e.clientX  > absoluteRect.left + this._leftOffset(e) &&
             e.clientX  < absoluteRect.right + this._leftOffset(e) &&
             e.clientY  > absoluteRect.top + this._topOffset(e)   &&
             e.clientY  < absoluteRect.bottom + this._topOffset(e);
   },

   _addMouseDownHandler: function( aDraggable )
   {
       htmlElement  = aDraggable.getMouseDownHTMLElement();
      if ( htmlElement  != null ) { 
         htmlElement.draggable = aDraggable;
         Event.observe(htmlElement , "mousedown", this._onmousedown.bindAsEventListener(this));
         Event.observe(htmlElement, "mousedown", this._mouseDown);
      }
   },

   _activateRegisteredDropZones: function() {
      var n = this.dropZones.length;
      for ( var i = 0 ; i < n ; i++ ) {
         var dropZone = this.dropZones[i];
         if ( dropZone.canAccept(this.currentDragObjects) )
            dropZone.activate();
      }

      this.activatedDropZones = true;
   },

   _deactivateRegisteredDropZones: function() {
      var n = this.dropZones.length;
      for ( var i = 0 ; i < n ; i++ )
      {
         this.dropZones[i].deactivate();
      }
      this.activatedDropZones = false;
   },

   _onmousedown: function () {
     Event.observe(document.body, "mousemove", this._mouseMove);
     Event.observe(document.body, "mouseup",  this._mouseUp);
   },

   _terminateEvent: function(e) {
      if ( e.stopPropagation != undefined )
         e.stopPropagation();
      else if ( e.cancelBubble != undefined )
         e.cancelBubble = true;

      if ( e.preventDefault != undefined )
         e.preventDefault();
      else
         e.returnValue = false;
   },


	   initializeEventHandlers: function() {
	      if ( typeof document.implementation != "undefined" &&
	         document.implementation.hasFeature("HTML",   "1.0") &&
	         document.implementation.hasFeature("Events", "2.0") &&
	         document.implementation.hasFeature("CSS",    "2.0") ) {
	         document.addEventListener("mouseup",   this._mouseUpHandler.bindAsEventListener(this),  false);
	         document.addEventListener("mousemove", this._mouseMoveHandler.bindAsEventListener(this), false);
	      }
	      else {
	         document.attachEvent( "onmouseup",   this._mouseUpHandler.bindAsEventListener(this) );
	         document.attachEvent( "onmousemove", this._mouseMoveHandler.bindAsEventListener(this) );
	      }
	   }
	}
);