//**************************************************************************************************************
//
//	dragdrop.js supports the javascript based dragging and dropping of elements.
//
//		INPUTS
//			DragDropSources : 					Array of element IDs that are legitimate drag sources
//			DragDropTarget : 					Array of element IDs that are legitimate drag targets
//			DragDropProcess(Source, Target) :	Function that is called when a legitimate source is dragged to
//												a legitimate target. Source and Target are the elements.
//												
//		STYLES
//			DragHelper	:						Defines the look of the element as it is being dragged.
//			DragDropSource :					Defines the look of all legitimate Sources
//			DragDropSourceHover :				Defines the look of all legitimate Sources for mouse hovers
//			DragDropTarget :					Defines the look of all legitimate Targets
//			DragDropTargetHover :				Defines the look of all legitimate Targets for mouse hovers
//
//
//	Copyright: 	Tuross Technologies Australia.
//	Author:		David Horne
//	Date:		29th Jan 2009
//
//**************************************************************************************************************


		var DragDropSources = "[]";
		var DragDropTargets = "[]";
		var Targets = new Array();

		var DragDropHelper;
		var MouseOffsets;
		
		var CurrentSource;
		var CurrentTarget;
		
var Views;
	
//*****************************************************************************************
//	Returns an object that represents the current mouse coordinates
//*****************************************************************************************
		function MouseCoords(TheEvent) {   

			if (TheEvent.pageX || TheEvent.pageY)
				return { X:TheEvent.pageX, Y:TheEvent.pageY };
			else 
				return 	{ 
							X: TheEvent.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft), 
							Y: TheEvent.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop)
						};   
		}
		
//*****************************************************************************************
//	Returns an object that represents the coordinates of TheElement box and a test to see
//	if the MousePos is within the bounding box
//*****************************************************************************************
		function ElementCoords(TheElement) {
			var ThePos = { Top: 0, Left: 0, Bottom: TheElement.offsetHeight, Right: TheElement.offsetWidth }
			
			while (TheElement != null) {
				ThePos.Top += TheElement.offsetTop;
				ThePos.Left += TheElement.offsetLeft;
				TheElement = (TheElement.offsetParent != null ? TheElement.offsetParent : null);
			}

			ThePos.Bottom += ThePos.Top;
			ThePos.Right += ThePos.Left;
			
			ThePos["Within"] = new Function("MousePos", "return ((this.Left <= MousePos.X) && (this.Right >= MousePos.X) && (this.Top <= MousePos.Y) && (this.Bottom >= MousePos.Y));");
			
			return ThePos;
		}
		
//*****************************************************************************************
//	Sets or resets the class of the Element
//*****************************************************************************************
		function SetClass(TargetElement, Set, TargetClass) {
			if (Set) {
				if (TargetElement.className.indexOf(TargetClass) < 0)
					TargetElement.className += " " + TargetClass;
			} else {
				TargetElement.className = TargetElement.className.replace(" " + TargetClass, "");
			}
		}

//*****************************************************************************************
//	Adds/Removes events for Element
//*****************************************************************************************
		function AddEvent(TheElement, TheEvent, TheFunction) {
		    if (TheElement.addEventListener) {
		        TheElement.addEventListener(TheEvent.toLowerCase(), TheFunction, false);
			} else if (TheElement.attachEvent) {
				TheElement.attachEvent("on" + TheEvent.toLowerCase(), TheFunction);
			} else {
				TheElement["on" + TheEvent.toLowerCase()] = TheFunction;
			}
		}

		function RemoveEvent(TheElement, TheEvent, TheFunction) {
		    if (TheElement.removeEventListener) {
		        TheElement.removeEventListener(TheEvent.toLowerCase(), TheFunction, false);
			} else if (TheElement.detachEvent) {
				TheElement.detachEvent("on" + TheEvent.toLowerCase(), TheFunction);
			} else {
				TheElement["on" + TheEvent.toLowerCase()] = null;
			}
		}

//*****************************************************************************************
//	Initialises the DragDrop objects based on Source and Target arrays
//*****************************************************************************************
		function DragDropInit() {
			DragDropHelper = document.createElement('DIV');   
			DragDropHelper.className = "DragHelper"; 
			document.body.appendChild(DragDropHelper);   
			
			var Elements = eval(DragDropSources);
			var Element;
			for (var i = 0; i < Elements.length; i++)
			{
				Element = document.getElementById(Elements[i]);
				if (Element != null) {
					Element.setAttribute("DragDropSource", "true", 0);
					SetClass(Element, true, "DragDropSource");
				}
			}
				
			Targets = new Array();
			Elements = eval(DragDropTargets);
			for (var i = 0; i < Elements.length; i++)
			{
				Element = document.getElementById(Elements[i]);
				if (Element != null) {
					Element.setAttribute("DragDropTarget", "true", 0);
					SetClass(Element, true, "DragDropTarget");
					Targets.push({ Obj: Element, Coords: ElementCoords(Element) });
				}
			}
				
			AddEvent(document, "MouseOver", MouseOver);
			AddEvent(document, "MouseOut", MouseOut);
			AddEvent(document, "MouseDown", MouseDown);
			AddEvent(document, "MouseUp", MouseUp);
		}
		
		function RefreshTargetElement(TheTarget) {
			for (var i = 0; i < Targets.length; i++) {
				if (Targets[i].Obj.id == TheTarget.id) {
					Targets[i] = { Obj: TheTarget, Coords: ElementCoords(TheTarget) };
					return;
				}
			}
		}
		
		function RefreshTargets() {
			for (var i = 0; i < Targets.length; i++)
				Targets[i].Coords = ElementCoords(Targets[i].Obj);
		}

//*****************************************************************************************
//	Sets TheElement up for dragging. Called when a Source element is clicked.
//*****************************************************************************************
		function SetDragDropElement(Element) {
			CurrentSource = { Obj: Element, Coords: ElementCoords(Element) };

			DragDropHelper.appendChild(Element.cloneNode(true));   
			DragDropHelper.style.top = DragDropSourcePos.Top + "px";
			DragDropHelper.style.left = DragDropSourcePos.Left + "px";
			DragDropHelper.style.display = 'block';  

			AddEvent(document, "MouseMove", MouseMove);
		}

//*****************************************************************************************
//	Releases the DragDrop Element. Called when mouse is released.
//*****************************************************************************************
		function UnsetDragDropElement() {
			if (CurrentSource != null) {
				SetClass(CurrentSource.Obj, false, "DragDropSourceHover");
				CurrentSource = null;
			}

			if (CurrentTarget != null) {
				SetClass(CurrentTarget.Obj, false, "DragDropTargetHover");
				CurrentTarget = null;
			}
			
			while (DragDropHelper.childNodes.length > 0) 
				DragDropHelper.removeChild(DragDropHelper.lastChild);
			
			DragDropHelper.style.display = 'none';  
			RemoveEvent(document, "MouseMove", MouseMove);
		}
		
//*****************************************************************************************
//	Imitates the hover CSS rule
//*****************************************************************************************
		function MouseOver(TheEvent) {
			TheEvent = TheEvent || window.event;
			var Target = TheEvent.target || TheEvent.srcElement;

			while (Target.getAttribute("DragDropSource") == null) {
				if ((Target.parentNode != null) && (Target.parentNode.getAttribute != null))
					Target = Target.parentNode;
				else
					return;
			}
			SetClass(Target, (Target.getAttribute("DragDropSource") != null), "DragDropSourceHover");
		}

		function MouseOut(TheEvent) {
			TheEvent = TheEvent || window.event;
			var Target = TheEvent.target || TheEvent.srcElement;
			SetClass(Target, false, "DragDropSourceHover");
		}

//*****************************************************************************************
//	Creates the drag effect. Moves the DragDropHelper in line with the mouse movement.
//	Also checks to see if the mouse is over a designated target and sets its class.
//	Only called if a designated Source has been selected.
//*****************************************************************************************
		var ScrollUp = false;
		var ScrollDown = false;
		var ScrollAmount = 5;

		function MouseMove(TheEvent) {
			TheEvent = TheEvent || window.event;
			var MousePos = MouseCoords(TheEvent);

			DragDropHelper.style.left = (MousePos.X - MouseOffsets.X) + "px";
			DragDropHelper.style.top = (MousePos.Y - MouseOffsets.Y) + "px";

			if (CurrentTarget == null) {
				for (var i = 0; i < Targets.length; i++) {
					if (Targets[i].Coords.Within(MousePos)) {
						SetClass(Targets[i].Obj, true, "DragDropTargetHover");
						CurrentTarget = Targets[i];
					}
				}
			} else {
				if (!CurrentTarget.Coords.Within(MousePos)) {
					SetClass(CurrentTarget.Obj, false, "DragDropTargetHover");
					CurrentTarget = null;
				}
			}
			
			ScrollUp = (MousePos.Y < xb_scrollTop());
			ScrollDown = (MousePos.Y > (xb_clientHeight() + xb_scrollTop()));
			ScrollAmount = Math.ceil(Math.max((xb_scrollTop() - MousePos.Y), (MousePos.Y - (xb_clientHeight() + xb_scrollTop())))/5);
			if (ScrollUp || ScrollDown)
				Scroll();
				
			Display(MousePos.Y + ":" + xb_clientHeight() + ":" + xb_scrollTop());
				
			if (TheEvent.preventDefault)
				TheEvent.preventDefault();
			return false;
		}
		
		
		function Scroll() {
			if (ScrollUp) {
				window.scrollBy(0, -ScrollAmount);
				DragDropHelper.style.top = parseInt(DragDropHelper.style.top) - ScrollAmount + "px";
				window.setTimeout("Scroll()", 100);
			}
				
			if (ScrollDown) {
				window.scrollBy(0, ScrollAmount);
				DragDropHelper.style.top = parseInt(DragDropHelper.style.top) + ScrollAmount + "px";
				window.setTimeout("Scroll()", 100);
			}
		}
		
//*****************************************************************************************
//	Checks and sets up a designated Source for dragging.
//*****************************************************************************************
		function MouseDown(TheEvent) {
			TheEvent = TheEvent || window.event;
			var Target = TheEvent.target || TheEvent.srcElement;
			var MousePos = MouseCoords(TheEvent);
			DragDropSourcePos = ElementCoords(Target);

			UnsetDragDropElement();
			if (Target.getAttribute("DragDropSource") != null) {
				MouseOffsets = 	{ X: MousePos.X - DragDropSourcePos.Left, Y: MousePos.Y - DragDropSourcePos.Top };   
				SetDragDropElement(Target);
			}

			if (TheEvent.preventDefault)
				TheEvent.preventDefault();
			return false;
		}
		
//*****************************************************************************************
//	Calls drop processing (if available) and then unsets the designated target.
//*****************************************************************************************
		function MouseUp(TheEvent) {
			if ((self["ProcessDragDrop"] != null) && (CurrentSource != null) && (CurrentTarget != null))
				ProcessDragDrop(CurrentSource.Obj, CurrentTarget.Obj);
				
			UnsetDragDropElement();

			if (TheEvent.preventDefault)
				TheEvent.preventDefault();
			return false;
		}
		
		
		function Display(Text) {
			var Target = xbGetElementById("Display");
			if (Target != null)
				xbSetInnerHTML(Target, Text);
		}		