<!--
//Expected diagram size: 1190 * 840
//

//W3Presence - xpathdesigner 2007
//			the objects are created dynamically - they need to be contained within a div - < ! - -start instance object layer-  - > < div id="ObjectLayer">< / div > < ! - -end instance object layer- - >
//			the service uses class to identify the group (eg: class=tool) - title is used to identify the object (eg: title=trashcan) - together: class=tool, title=trashcan;
//			objects are created dynamically via javascript - the object id are created automatically (numeric increment) the increment is stored in the div layer
//			textfields dropped onto shapes become bonded - bonded textfields can only be move around the bonded object

//			the basic control functions are:
//				left click and hold - move object
//				wheel up/down - alter zindex property (allowed only within the clas limit)
//				altKey wheel up/down - resize object (center: adjust x&y - edges: adjust x or y)
//				doubleClick - action the object - bonded textfields are unbonded
//				drop objects on tool (ie: trashcan)

//		key class names:
//			background - used to identify a background shape : z-index 200
//			shape - used to identify a standard shape : z-index 400
//			textfield - used to identify a text layer : z-index 600
//			mask - used to identify a mask : z-index 800
//			infolayer - used to identify a info layer : z-index 1000
//			textlabel - used to identify a text lable : z-index 1200
//			tool - used to identify tools : z-index 1400
//			toolmenu - used to identify the tool menu : z-index 1600
//			group limit - 20 : default = group + (limit/2)


// - initialise the xpath services by setting the body tag to: < body onload="fXPathInitialise('xpathdiv', false)" >


///Things to look at - when you get a moment
/////////////////////////////////////////////////////////////////////
///
/////////////////////////////////////////////////////////////////////
//JavaScript Function with Named Arguments
// Define function to take one "argument", which is in fact an object:
//function fnParseInt( oArg ){ 
//return parseInt( oArg.number, oArg.radix );
//}
//
// Which you then call like this (pass in an object literal):
//fnParseInt( { number : 'afy', radix : 36 } );
//////////////////////////////////////////////////////////////////////



//create global variables - do not change
var gObjX=0, gObjY=0, gMouseX=0, gMouseY=0, gOriginalObjectZIndex=0, gObject=false, gDiagramObjectID=false, gBackgroundObjectID=false;
var gDragAllowed=true, gAllowMultipleMenus=false, gAllowBondedDragging=false, gDebugMode=false;
var gXPathDIVLayer="xpathdiv"; //defines the <div> layer id used to contain the dynamic objects - IMPORTANT - must exist within the web page

//create global constants 
var gZIndexBackground=200, gZIndexShape=400, gZIndexTextfield=600, gZIndexMask=800, gZIndexInfolayer=1000, gZIndexTextlabel=1200,  gZIndexTool=1400, gZIndexToolMenu=1600, gZIndexLimit=20, gZIndexSelected=2800;
var gOnElementAllowedOffset=20, gXPathObjDefinition="_xobjdefinition", gToolMenuButtonExtension="_menubutton", gToolMenuImageExtension="_menuimage",  gXPathDiagramDefinition="_xdiagramdefinition", gOffInstanceStatusMessage="W3Presence XPathEditor - ";
var gDefinition_TRASHCAN="trashcan", gDefinition_TOOLMENU="toolmenu";

//UI functions
function fUIService_SwithElement_ONOFF(sElement, bAssumeHidden) {
//this function create a virtual switch for the specified element
var oElement=document.getElementById(sElement), sVisible;

	if(oElement) {
		sVisible=oElement.style.visibility;
		sVisible=sVisible.toLowerCase();
		
		switch (sVisible) {
			case "visible": oElement.style.visibility="hidden"; 	break;
			case "hidden": oElement.style.visibility="visible";break;
			default: 
				switch (bAssumeHidden) {
					case true:
						oElement.style.visibility="visible";break;
						break;
					default:
						oElement.style.visibility="hidden"; break;
						break;
				}
				break;
		}
	}
}


//USER functions
function fXPathInitialise(sXPathDIV, bDebugMode) {
//function initalises the xpath editor preloader - also initalises a user defined function, sXPathDIV define the layer within the webpage used to manage the xpath objects
var sDescription;

	//initalise xpath preferences
	if(sXPathDIV) { gXPathDIVLayer=sXPathDIV; } //initalise the xpath DIV layer - else leave as default XPATHDIV
	if(bDebugMode) { gDebugMode=bDebugMode; } //set debug status

	//initalise xpath preloader - a user define function used to load scripted objects
	try {
		fXPathObjectPreloader();
	}
	catch (err) {
		sDescription=err.description;
	}
}

function fXPathPublishedEvent_MouseOverShape(oObject) {
//This function fires when the mouse moves over a published path shape
	try {
		fSwithInfoLayers(oObject.id);
	} catch (err) {
	}
}

function fXPathPublishedEvent_MouseOutShape(oObject) {
//this function fires when the mouse moves out of the published path shape	
	try {
		fSwithInfoLayers(oObject.id);
	} catch (err) {
	}
}

function fXPathPublishedEvent_MouseClick(oObject) {
//this function fires when the mouse is clicked on the published path shape
	try {
		fOpenFeedbackManager(oObject);
	} catch (err) {
	}
}

String.prototype.trim=function(){
    return this.replace(/^\s*|\s*$/g,'');
}

String.prototype.ltrim=function(){
    return this.replace(/^\s*/g,'');
}

String.prototype.rtrim=function(){
    return this.replace(/\s*$/g,'');
}

function fXPathLoadBackground(sSrc, lRealOId, sTitle, sAlt, lLeft, lTop, lWidth, lHeight, lCharacterLimit) {
//function creates an appropriate element - background
var sTag="img", sClass="background", lZIndex=fObject_GetClassZIndexDefaultValue(sClass).zindex, lZoom=100, sId=0, bAllowLoad=true;

	switch (sTitle.toLowerCase()) { //check the title for the tool to load
		default:
			bAllowLoad=true;
			break;
	}

	if(bAllowLoad==true) { sId=fXPathCreateLayerElement(0, lRealOId, sTag, sSrc, sTitle, sAlt, lLeft, lTop, lWidth, lHeight, lZIndex, lZoom, sClass, lCharacterLimit).id; } else { //create layer element
		 fSupport_WarningMessage("Load Background Item:\nMultiple background item support is currently disabled."); 
	} 
}

function fXPathLoadShape(sSrc, lRealOId, sTitle, sAlt, lLeft, lTop, lWidth, lHeight, lCharacterLimit) {
//function creates an appropriate element - shape
var sTag="img", sClass="shape", lZIndex=fObject_GetClassZIndexDefaultValue(sClass).zindex, lZoom=100, sId=0, bAllowLoad=true;

	switch (sTitle.toLowerCase()) { //check the title for the tool to load
		default:
			bAllowLoad=true;
			break;
	}

	if(bAllowLoad==true) { sId=fXPathCreateLayerElement(0, lRealOId, sTag, sSrc, sTitle, sAlt, lLeft, lTop, lWidth, lHeight, lZIndex, lZoom, sClass, lCharacterLimit).id; } else { //create layer element
		 fSupport_WarningMessage("Load Shape Item:\nMultiple shape item support is currently disabled."); 
	} 
}

function fXPathLoadTextfield(sSrc, lRealOId, sTitle, sAlt, lLeft, lTop, lWidth, lHeight, lCharacterLimit) {
//function creates an appropriate element - textfield
var sTag="img", sClass="textfield", lZIndex=fObject_GetClassZIndexDefaultValue(sClass).zindex, lZoom=100, sId=0, bAllowLoad=true;

	switch (sTitle.toLowerCase()) { //check the title for the tool to load
		default:
			bAllowLoad=true;
			break;
	}

	if(bAllowLoad==true) { sId=fXPathCreateLayerElement(0, lRealOId, sTag, sSrc, sTitle, sAlt, lLeft, lTop, lWidth, lHeight, lZIndex, lZoom, sClass, lCharacterLimit).id; } else { //create layer element
		 fSupport_WarningMessage("Load Textfield Item:\nMultiple textfield item support is currently disabled."); 
	} 
}

function fXPathLoadInfolayer(sSrc, lRealOId, sTitle, sAlt, lLeft, lTop, lWidth, lHeight, lCharacterLimit) {
//function creates an appropriate element - infolayer
var sTag="img", sClass="infolayer", lZIndex=fObject_GetClassZIndexDefaultValue(sClass).zindex, lZoom=100, sId=0, bAllowLoad=true;

	switch (sTitle.toLowerCase()) { //check the title for the tool to load
		default:
			bAllowLoad=true;
			break;
	}

	if(bAllowLoad==true) { sId=fXPathCreateLayerElement(0, lRealOId, sTag, sSrc, sTitle, sAlt, lLeft, lTop, lWidth, lHeight, lZIndex, lZoom, sClass, lCharacterLimit).id; } else { //create layer element
		 fSupport_WarningMessage("Load Infolayer Item:\nMultiple infolayer item support is currently disabled."); 
	} 
}

function fXPathLoadTextlabel(sSrc, lRealOId, sTitle, sAlt, lLeft, lTop, lWidth, lHeight, lCharacterLimit) {
//function creates an appropriate element - textlabel
var sTag="img", sClass="textlabel", lZIndex=fObject_GetClassZIndexDefaultValue(sClass).zindex, lZoom=100, sId=0, bAllowLoad=true;

	switch (sTitle.toLowerCase()) { //check the title for the tool to load
		default:
			bAllowLoad=true;
			break;
	}

	if(bAllowLoad==true) { sId=fXPathCreateLayerElement(0, lRealOId, sTag, sSrc, sTitle, sAlt, lLeft, lTop, lWidth, lHeight, lZIndex, lZoom, sClass, lCharacterLimit).id; } else { //create layer element
		 fSupport_WarningMessage("Load textlabel Item:\nMultiple textlabel item support is currently disabled."); 
	} 
}

function fXPathLoadMask(sSrc, lRealOId, sTitle, sAlt, lLeft, lTop, lWidth, lHeight, lCharacterLimit) {
//function creates an appropriate element - mask
var sTag="img", sClass="mask", lZIndex=fObject_GetClassZIndexDefaultValue(sClass).zindex, lZoom=100, sId=0, bAllowLoad=true;

	switch (sTitle.toLowerCase()) { //check the title for the tool to load
		default:
			bAllowLoad=true;
			break;
	}

	if(bAllowLoad==true) { sId=fXPathCreateLayerElement(0, lRealOId, sTag, sSrc, sTitle, sAlt, lLeft, lTop, lWidth, lHeight, lZIndex, lZoom, sClass, lCharacterLimit).id; } else { //create layer element
		 fSupport_WarningMessage("Load Mask Item:\nMultiple mask item support is currently disabled."); 
	} 
}

function fXPathLoadTool(sSrc, lRealOId, sTitle, sAlt, lLeft, lTop, lWidth, lHeight, lCharacterLimit) {
//function creates an appropriate element - tool - define tools (as classified via element.title): trashcan - auto deletes objects dropped
var sTag="img", sClass="tool" , lZIndex=fObject_GetClassZIndexDefaultValue(sClass).zindex, lZoom=100, sId=0, bAllowLoad=true;

	switch (sTitle.toLowerCase()) { //check the title for the tool to load
		case gDefinition_TRASHCAN: //only allow one instance of the trashcan
			if( fObject_FindObject(document.getElementById(gXPathDIVLayer).id, sClass, gDefinition_TRASHCAN, false).found==true) { bAllowLoad=false; }
			break;
			
		default:
			bAllowLoad=true;
			break;
	}

	if(bAllowLoad==true) { sId=fXPathCreateLayerElement(0, lRealOId, sTag, sSrc, sTitle, sAlt, lLeft, lTop, lWidth, lHeight, lZIndex, lZoom, sClass, lCharacterLimit).id; } else { //create layer element
		 fSupport_WarningMessage("Load Tool Item:\nMultiple tool item support is currently disabled."); 
	} 
	return (sId);
}

function fXPathLoadMenu(lLeft, lTop, lWidth, lHeight) {
//function creates the toolmenu div
var sTag="div", sTitle=gDefinition_TOOLMENU, sClass=gDefinition_TOOLMENU, sSrc="", sAlt="toolmenu alt", lZIndex, lZIndex=fObject_GetClassZIndexDefaultValue(sClass).zindex, lZoom=100;
var oToolMenuDIV;

	if(fObject_FindObject(gXPathDIVLayer, gDefinition_TOOLMENU, gDefinition_TOOLMENU, gAllowMultipleMenus).found==false) { //only allow one instance of the tool menu at any one time
		
		//create tool menu DIV layer - and create a reference to the element id
		oToolMenuDIV=document.getElementById((fXPathCreateLayerElement(0, -1, sTag, sSrc, sTitle, sAlt, lLeft, lTop, lWidth, lHeight, lZIndex, lZoom, sClass).id));
		oToolMenuDIV.removeAttribute("name"); //clean any unnecessary attributes - good practice - good example reference
		oToolMenuDIV.removeAttribute("src");
	
		return { id: fObject_GetActualElementInfo(oToolMenuDIV.id).id, storageid: fObject_GetActualElementInfo(oToolMenuDIV.id).storageid }
	} else { if(gDebugMode==true) { fSupport_WarningMessage("ToolMenu:\nMultiple menu support is currently disabled."); } }
}

function fXPathLoadMenuImage(oToolMenu, sSrc, sTitle, sAlt, sClass, sEvent) {
//function creates the toolmenu image button - if not sure of the current toolmenu reference pass "false" and the system will find the toolmenu div
var sElement ,oActiveToolMenu, sMenuCode, lInstance;
var sId, sImageId;

	//check whether the function was called with a specific element - if not use the current grabbed object
	if(oToolMenu) { 
		oActiveToolMenu=oToolMenu; 
	} else { 
		//find the current toolmenu
		sElement=fObject_FindObject(gXPathDIVLayer, gDefinition_TOOLMENU, gDefinition_TOOLMENU, gAllowMultipleMenus).id;
		if(parseInt(sElement, 10)>0) { oActiveToolMenu=document.getElementById(sElement); } //create a reference to the toolmenu
	}
	
	if(oActiveToolMenu) { //a valid toolmenu object has been identified
		if((oActiveToolMenu.tagName).toLowerCase()=="div") { //the toolmenu must be contained within a div
				
			//get the insert layer instance - used to store the last dynamic object instance id created - I originally used title but tests confirm that the system seems to create attributes automatically if not already in existance
			lInstance=parseInt(oActiveToolMenu.instance, 10); //get the the instance - based on the title as the instance number
			if(isNaN(lInstance)==true) { 	lInstance=1; } else { lInstance++; }		
			oActiveToolMenu.instance=lInstance; //store the new instance back to the layer	
		
			sId=(lInstance.toString()) + gToolMenuButtonExtension;
			sImageId=sId + gToolMenuImageExtension + "IMG";
												
			//build the toolmenu image button
			sMenuCode="<!-- toolmenu button -->" +
				"<" + "button" +
						" id=\"" + sId + "\"" +
						" name=\"" + sId + "\"" +
						" style=\"position: relative\"" +
						" class=\"" + sClass + "\"" +
						" onmouseover=\"fDrag_Disabled();\"" +
						" onmouseout=\"fDrag_Enabled()\"" +
						" onmouseup=\"" + sEvent + "; fDrag_Enabled();\"" +
				">" + 
					"<" + "img" +
						" id=\"" + sImageId + "\"" +
						" name=\"" + sImageId + "\"" +
						" src=\"" + sSrc + "\"" +
						" title=\"" + sTitle + "\"" +
						" alt=\"" + sAlt + "\"" +
					"/>";
				"</button>";
		
			//insert the item code
			oActiveToolMenu.insertAdjacentHTML("beforeEnd",sMenuCode); //execute the code	
		} else { if(gDebugMode==true) { fSupport_WarningMessage("ToolMenu Image:\nUnable to add item - expected DIV toolmenu, check you are requesting a valid toolmenu."); } }
	} else { if(gDebugMode==true) { fSupport_WarningMessage("ToolMenu Image:\nUnable to add item - cant find ToolMenu."); } }
}

//ZOOM support
function fZoom_GetElementZoom(sElement) {
//this function returns the current zoom value for the specified element
var oObject=document.getElementById(sElement), lZoomFactor, cDefaultZoom=100;
	
	lZoomFactor=cDefaultZoom; //set default zoom factor - 100=100% full size (1:1)
	if(oObject) { //do we have a selected object
		lZoomFactor=parseInt(0 + oObject.style.zoom, 10); //extract the zoom property - atleast 0 (base 10)
		if(lZoomFactor<=0) { lZoomFactor=cDefaultZoom;} //if zoom <=0 set zoom to default
	}
	return lZoomFactor;
}

function fZoom_GetElementSize(sElement) {
//this function returns the current size value for the specified element
var oObject=document.getElementById(sElement), lHeight, lWidth, cDefault=0;
	
	lHeight=cDefault; //set default height - 0
	lWidth=cDefault; //set default width - 0
	if(oObject) { //do we have a selected object
	
		lWidth=parseInt(0 + oObject.style.width, 10) + "px"; //extract the height property - atleast 0 (base 10)
		if(lWidth<=0) { lWidth=cDefault;} //if width <=0 set to default
		
		lHeight=parseInt(0 + oObject.style.height, 10) + "px"; //extract the height property - atleast 0 (base 10)
		if(lHeight<=0) { lHeight=cDefault;} //if height <=0 to default		
		
	}
	return { width: lWidth, height: lHeight };
}

function fZoom_SetElementSize_Width(sElement, lWidth) {
//this function sets the width (object and style) size value for the specified element
var oObject=document.getElementById(sElement);
	
	if(oObject) { //do we have a selected object
		lWidth=parseInt(lWidth, 10) + "px"; //create the width property
		oObject.width=lWidth;
		oObject.style.width=lWidth;
	}
}

function fZoom_SetElementSize_Height(sElement, lHeight) {
//this function sets the height (object and style) size value for the specified element
var oObject=document.getElementById(sElement);
	
	if(oObject) { //do we have a selected object
		lHeight=parseInt(lHeight, 10) + "px"; //create the height property
		oObject.height=lHeight;
		oObject.style.height=lHeight;		
	}
}

function fZoom_IncreaseElementSize_WidthHeight(sElement, lIncrease) {
//this function sets both the height & width (object and style) size value for the specified element
var lWidth, lHeight, oObject=document.getElementById(sElement);
	
	if(oObject) { //do we have a selected object
		//get the current element size		
		lWidth=parseInt(fZoom_GetElementSize(sElement).width, 10) + lIncrease;
		lHeight=parseInt(fZoom_GetElementSize(sElement).height, 10) + lIncrease;
		
		//store the increased element size
		fZoom_SetElementSize_Width(sElement, lWidth);
		fZoom_SetElementSize_Height(sElement, lHeight);
	}
}

function fZoom_SizeValue(lSize, lMinSize, lMaxSize, bInvertDirection, bLoopSize, sScaleDescription) {
//this function uses the wheelDelta property to indicate the distance that the wheel button has rotated (expressed in multiples of 120)
	
	lSize=parseInt(lSize+0, 10); //convert the size to a base 10 numeric value
	
	//increase / decrease size variable depending on wheel rotation
	if(event.wheelDelta>=120) { //the wheel is rolled forward (away from user)
		if(bInvertDirection==false) { lSize++; } else { lSize--; }
	} else if(event.wheelDelta<=120) { //the wheel is rolled backward (toward the user)
		if(bInvertDirection==false) { lSize--; } else { lSize++; }
	}
	
	//validate size variable - based on min/max and whether to loopsize
	if(lSize<lMinSize) { if(bLoopSize==true) { lSize=lMaxSize;	} else { fSupport_WarningMessage(sScaleDescription + " Information:\nMinimum range (layer: " + lMinSize + ") reached - further scaling in this direction is currently not available."); lSize=lMinSize; 	}} 
	else if(lSize>lMaxSize) { if(bLoopSize==true) { lSize=lMinSize; } else { fSupport_WarningMessage(sScaleDescription + " Information:\nMaximum range (layer: " + lMaxSize + ")  reached - further scaling in this direction is currently not available."); lSize=lMaxSize; }}
	return lSize; //return the size value
}

function fZoom_WheelScroll(bInvertDirection) {
//function returns whether the wheel has been scrolled
var bIncrease=false, bDecrease=false;

	//detect wheel rotation
	if(event.wheelDelta>=120) { //the wheel is rolled forward (away from user)
		if(bInvertDirection==false) { bIncrease=true; } else { bDecrease=true; }
	} else if(event.wheelDelta<=120) { //the wheel is rolled backward (toward the user)
		if(bInvertDirection==false) { bDecrease=true; } else { bIncrease=true; 	}
	}
	return { increase: bIncrease, decrease: bDecrease }
}

function fZoom_ResizeObject(oElement) {
//resize the specified object using the wheelDelta
var lIncrement, lZIndexMin, lZIndexMax;

	if(event.altKey==1) { // the altKey is active
		if(fObject_ObjectHotSpot(oElement).left==true) { //the left hotspot active - scale element - width
			fSupport_SetMouseCursor_ResizeH(oElement);	
			fZoom_SetElementSize_Width(oElement.id, (String(fZoom_SizeValue(fZoom_GetElementSize(oElement.id).width, 10, 500, true, false, "Dynamic Width Scaling") + "")));	
		} 

		if(fObject_ObjectHotSpot(oElement).top==true) { //the top hotspot active - scale element - height
			fSupport_SetMouseCursor_ResizeV(oElement);
			fZoom_SetElementSize_Height(oElement.id, (String(fZoom_SizeValue(fZoom_GetElementSize(oElement.id).height, 10, 500, true, false, "Dynamic Height Scaling") + "")));
		} 
		
		if(fObject_ObjectHotSpot(oElement).right==true) { //the right hotspot active - scale element - width
			fSupport_SetMouseCursor_ResizeH(oElement);
			fZoom_SetElementSize_Width(oElement.id, (String(fZoom_SizeValue(fZoom_GetElementSize(oElement.id).width, 10, 500, true, false, "Dynamic Width Scaling") + "")));	
		} 
		
		if(fObject_ObjectHotSpot(oElement).bottom==true) { //the bottom hotspot active - scale element - height
			fSupport_SetMouseCursor_ResizeV(oElement);
			fZoom_SetElementSize_Height(oElement.id, (String(fZoom_SizeValue(fZoom_GetElementSize(oElement.id).height, 10, 500, true, false, "Dynamic Height Scaling") + "")));
		} 
		
		if(fObject_ObjectHotSpot(oElement).center==true) { //the center hotspot active - zoom element - width/height
			fSupport_SetMouseCursor_ResizeAll(oElement);
			switch (fZoom_WheelScroll(true).increase) { //check to see which way we are scrolling
				case true: 	lIncrement=1; break;
				case false: lIncrement=-1; break;
			}
			
			//oElement.style.zoom=String(fZoom_SizeValue(fZoom_GetElementZoom(oElement.id), 50, 150, true, false, "Dynamic Zoom Scaling") + "%"); //update object zoom property
			fZoom_IncreaseElementSize_WidthHeight(oElement.id, lIncrement); //update element size - width and height
		} 								
		
	} else { 	//the altKey is not active
		lZIndexMin=fObject_GetClassZIndexDefaultValue(oElement.className).zindexmin; //calculate the zindex limits based on the element class
		lZIndexMax=fObject_GetClassZIndexDefaultValue(oElement.className).zindexmax;	
		oElement.style.zIndex=fZoom_SizeValue(fObject_GetActualElementInfo(oElement.id).zindex, lZIndexMin, lZIndexMax, true, false, "Dynamic Layer Scaling"); //update the element zIndex property
		
	}
	fObject_UpdateDefinition(oElement); //store the active element - pass the object to override any current grabbed object
}


//DRAG support
function fDrag_DropEvent() {
//execute the drop object function

	if (gObject) {
	
		fSupport_SetMouseCursor_Pointer(gObject); //update the mouse cursor
		gObject.style.zIndex = gOriginalObjectZIndex; //set the objects zindex back the original position
		fObject_UpdateDefinition(); //update the object location
		fDrag_SearchForDropTarget("img"); //search for img drop targets
		
		gObject=false; //set the object to false to indicate that the move has completed
		gOriginalObjectZIndex=false; //destroy original zindex  
	}

	document.onmousemove=null; //destroy the event functions
	document.onmouseup=null;
	document.onmousedown=null;	
	
	return false; //set the return status 
}

function fDrag_MoveEvent() {
//execute the move selected object function
//notes: event.clientX/Y is the position of the mouse relating to the absolute screen
var bAllowMode=true, lMouseX, lMouseY, lBondedObject;

	if (gObject) {
	
		fSupport_SetMouseCursor_Move(gObject); //update the mouse cursor
	
		lMouseX=event.clientX;
		lMouseY=event.clientY;
	
		lBondedObject=parseInt(fObject_IsBonded(gObject).bondedobject, 10);
		if(lBondedObject>0) { 	//are mouse coordinates outside bonded object
			if(gAllowBondedDragging==false) { //confirm bonded dragging
				if(fObject_OnElement(lMouseX, lMouseY, document.getElementById(lBondedObject))==false) { bAllowMode=false; }
			}
		}
	
		if(bAllowMode==true) { //allow the move event
			fObject_GetActualElementLocation(gObject.id);
	
			gObject.style.left=gObjX + lMouseX - gMouseX; //update the object property based on current, event and mouse position
			gObject.style.top=gObjY + lMouseY - gMouseY;
		
			fObject_UpdateDefinition(); //update the object location
		}
		
	}
	return false; //set the return status 
}

function fDrag_DragEvent() {
//execute the drag object function

	if (gObject) {

		fSupport_SetMouseCursor_Move(gObject); //update the mouse cursor
		gObjX=parseInt(event.srcElement.style.left+0,10);	//the parseInt function is used to ensure a numeric value is created
		gObjY=parseInt(event.srcElement.style.top+0,10);

		gMouseX=event.clientX; //store the mouse position
		gMouseY=event.clientY;

		document.onmousemove=fDrag_MoveEvent; //create mouse move event
	}	
	
    return false;  //set the return status 
}

function fDrag_SearchForDropTarget(sClass) {
//this function check whether the element was dropped on a target
	if(gObject) { fObject_IsElementDroppedOnTargetTagClass(gObject, sClass); }
}

//create the drag enabled flag services
function fDrag_Enabled() { gDragAllowed=true; }
function fDrag_Disabled() { gDragAllowed=false; }
function fDrag_ElementDragable() { return gDragAllowed; }

//SUPPORT services
function fSupport_WarningMessage(sMessage) { //display an alert notification with the specified message
	alert(sMessage);
}

function fSupport_SetBrowserStatus(sMessage) { //update the browser status 
	window.status=sMessage;
}

function fSupport_PositionWithinArea(lXPos, lYPos, lLeft, lTop, lRight, lBottom) {
//returns true/false depending on whether the x/y is within the specified area
var bStatus=false;

	XPos=(parseInt(lXPos, 10)+0); lYPos=(parseInt(lYPos, 10)+0); lLeft=(parseInt(lLeft, 10)+0); lTop=(parseInt(lTop, 10)+0); lRight=(parseInt(lRight, 10)+0); lBottom=(parseInt(lBottom, 10)+0);
	if(lXPos>=lLeft && lXPos<=lRight&&lYPos>=lTop&&lYPos<=lBottom) { 	bStatus=true;	 }
	return bStatus;
}

function fSupport_MouseOffObjectBrowser() {
//creates a dynamic browser status message
var lD_ID, sReference, lMode, sName, dRevision, lWidth, lHeight, sMessage

	//get diagram information
	lD_ID=fDiagram_GetActualInfo().id;
	sReference=fDiagram_GetActualInfo().reference;
	lMode=fDiagram_GetActualInfo().mode;
	sName=fDiagram_GetActualInfo().name;
	dRevision=fDiagram_GetActualInfo().revision;
	lWidth=fDiagram_GetActualInfo().width;
	lHeight=fDiagram_GetActualInfo().height;

	//define message
	sMessage=gOffInstanceStatusMessage + sName + " (Id: " + lD_ID + "); rev: " + dRevision + " - mode: " + lMode + " (w: " + lWidth + ", h: " + lHeight + ")";
	fSupport_SetBrowserStatus(sMessage);

}

function fSupport_ReturnElementIDReference(lId) {
//this function returns the next available element id - also increments to ensure unique
var oGlobalDiv=document.getElementById(gXPathDIVLayer), lInstance;

	lId=parseInt(lId, 10)+0;
	if(lId>0) {
		lInstance=lId.toString();
	} else {
		//get the insert layer instance - used to store the last dynamic object instance id created - I originally used title but tests confirm that the system seems to create attributes automatically if not already in existance
		lInstance=parseInt(oGlobalDiv.instance, 10); //get the the instance - based on the title as the instance number
		if(isNaN(lInstance)==true) { 	lInstance=1; } else { lInstance++; }			
	}
	
	oGlobalDiv.instance=lInstance; //store the new instance back to the layer
	return lInstance;
}

function fSupport_SetMouseCursor_Default(oElement) { oElement.style.cursor="default"; }
function fSupport_SetMouseCursor_Pointer(oElement) { oElement.style.cursor="pointer"; }
function fSupport_SetMouseCursor_Move(oElement) { oElement.style.cursor="all-scroll"; }
function fSupport_SetMouseCursor_ResizeH(oElement) { oElement.style.cursor="e-resize"; }
function fSupport_SetMouseCursor_ResizeV(oElement) { oElement.style.cursor="n-resize"; }
function fSupport_SetMouseCursor_ResizeAll(oElement) { oElement.style.cursor="move"; }


//ACTION services
function fAction_TargetDropDetected(oElement, oTarget) {
//a target drop has occured - execute the appropriate function
var sClass_Element=oElement.className, sClass_Target=oTarget.className, sTitle_Element=oElement.title, sTitle_Target=oTarget.title;

	//execute drop functions - target class: background
	if(fObject_GetZIndexGroup(oTarget).background==true) {
		switch(sTitle_Target.toLowerCase()) {
			default: //target title not defined in drop list
				if(gDebugMode==true) { fSupport_WarningMessage("Drop On Background:\nObject: " + sTitle_Element + " (" + oElement.id  + ") " + sClass_Element + " - no operations defined for drop."); }
				break;
		}		
	}

	//execute drop functions - target class: shape
	if(fObject_GetZIndexGroup(oTarget).shape==true) {
		switch(sTitle_Target.toLowerCase()) {
			default: //target title not defined in drop list
				if(gDebugMode==true) { fSupport_WarningMessage("Drop On Shape:\nObject: " + sTitle_Element + " (" + oElement.id  + ") " + sClass_Element + " - no operations defined for drop."); }
				break;
		}
		
		//the following functions are used to provide additional drop on shape functions
		switch(sClass_Element.toLowerCase()) { //filter element class
			case "textfield":
				if(fObject_IsBonded(oElement).bonded==false) {
					fObject_BondObject(oElement, oTarget.id); //bond the textfield to the target (shape)
				}
			case "textlabel":
				if(fObject_IsBonded(oElement).bonded==false) {
					fObject_BondObject(oElement, oTarget.id); //bond the textfield to the target (shape)
				}
			case "infolayer":
				if(fObject_IsBonded(oElement).bonded==false) {
					fObject_BondObject(oElement, oTarget.id); //bond the infolayer to the target (shape)
				}
		}	
	}

	//execute drop functions - target class: textfield
	if(fObject_GetZIndexGroup(oTarget).textfield==true) {
		switch(sTitle_Target.toLowerCase()) {
		
			case "infolayer": //we are dropping an infolayer on to a text layer
				if(fObject_IsBonded(oTarget).bonded==true) { //the textfield is bonded
					fObject_BondObject(oElement, fObject_IsBonded(oTarget).bondedobject); //bond infolayer to the same object as the textfield
					alert("bonding infolayer to textfield bonded object");
				}
		
			default: //target title not defined in drop list
				if(gDebugMode==true) { fSupport_WarningMessage("Drop On Textfield:\nObject: " +  sTitle_Element + " (" + oElement.id  + ") " + sClass_Element + " - no operations defined for drop."); }
				break;
		}
	}

	//execute drop functions - target class: infolayer
	if(fObject_GetZIndexGroup(oTarget).infolayer==true) {
		switch(sTitle_Target.toLowerCase()) {
			default: //target title not defined in drop list
				if(gDebugMode==true) { fSupport_WarningMessage("Drop On Infolayer:\nObject: " +  sTitle_Element + " (" + oElement.id  + ") " + sClass_Element + " - no operations defined for drop."); }
				break;
		}
	}

	//execute drop functions - target class: textlabel
	if(fObject_GetZIndexGroup(oTarget).textlabel==true) {
		switch(sTitle_Target.toLowerCase()) {
			default: //target title not defined in drop list
				if(gDebugMode==true) { fSupport_WarningMessage("Drop On Textlabel:\nObject: " + sTitle_Element + " (" + oElement.id  + ") " + sClass_Element + " - no operations defined for drop."); }
				break;
		}
	}

	//execute drop functions - target class: mask
	if(fObject_GetZIndexGroup(oTarget).mask==true) {
		switch(sTitle_Target.toLowerCase()) {
			default: //target title not defined in drop list
				if(gDebugMode==true) { fSupport_WarningMessage("Drop On Mask:\nObject: " + sTitle_Element + " (" + oElement.id  + ") " + sClass_Element + " - no operations defined for drop."); }
				break;
		}
	}

	//execute drop functions - target class: tool
	if(fObject_GetZIndexGroup(oTarget).tool==true) {
		switch(sTitle_Target.toLowerCase()) {
			case gDefinition_TRASHCAN: //the target title is trashcan
				fRemoveManagedElement(oElement.id);
				break;
			
			default: //target title not defined in drop list
				if(gDebugMode==true) { fSupport_WarningMessage("Drop On Tool:\nObject: " + sTitle_Element + " (" + oElement.id  + ") " + sClass_Element + " - no operations defined for drop."); }
				break;
		}
	}
}

function fAction_DoubleClickElementDetected(oElement) {
//an object double click occured - execute the appropriate function
var sClass_Element=oElement.className, sTitle_Element=oElement.title;

	//execute double click functions - element class: background
	if(fObject_GetZIndexGroup(oElement).background==true) {
		switch(sTitle_Element.toLowerCase()) {
			default: //element title not defined in double click list
				if(gDebugMode==true) { fSupport_WarningMessage("Double Click Background:\nObject " + sTitle_Element + " - no operation defined."); }
				break;
		}
	}

	//execute double click functions - element class: shape
	if(fObject_GetZIndexGroup(oElement).shape==true) {
		switch(sTitle_Element.toLowerCase()) {
			default: //element title not defined in double click list
				if(gDebugMode==true) { fSupport_WarningMessage("Double Click Shape:\nObject " + sTitle_Element + " - no operation defined."); }
				break;
		}
	}

	//execute double click functions - element class: textfield
	if(fObject_GetZIndexGroup(oElement).textfield==true) {	
		switch(sTitle_Element.toLowerCase()) {
			default: //element title not defined in double click list
				if(gDebugMode==true) { fSupport_WarningMessage("Double Click Textfield:\nObject " + sTitle_Element + " - no operation defined."); }
				break;
		}
		
		//handle bonded textfields
		if(fObject_IsBonded(oElement).bonded==true) { //unbond textfield binding
			fObject_BondObject(oElement, -1); 	fObject_UpdateDefinition(oElement); 
		}
		
	}

	//execute double click functions - element class: infolayer
	if(fObject_GetZIndexGroup(oElement).infolayer==true) {	
		switch(sTitle_Element.toLowerCase()) {
			default: //element title not defined in double click list
				if(gDebugMode==true) { fSupport_WarningMessage("Double Click Infolayer:\nObject " + sTitle_Element + " - no operation defined."); }
				break;
		}
		
		//handle bonded infolayers
		if(fObject_IsBonded(oElement).bonded==true) { //unbond infolayer binding
			fObject_BondObject(oElement, -1); 	fObject_UpdateDefinition(oElement); 
		}
		
	}

	//execute double click functions - element class: textlabel
	if(fObject_GetZIndexGroup(oElement).textlabel==true) {
		switch(sTitle_Element.toLowerCase()) {
			default: //element title not defined in double click list
				if(gDebugMode==true) { fSupport_WarningMessage("Double Click Textlabel:\nObject " + sTitle_Element + " - no operation defined."); }
				break;
		}
		
		//handle bonded textlabels
		if(fObject_IsBonded(oElement).bonded==true) { //unbond textlabel binding
			fObject_BondObject(oElement, -1); 	fObject_UpdateDefinition(oElement); 
		}
		
	}

	//execute double click functions - element class: mask
	if(fObject_GetZIndexGroup(oElement).mask==true) {
		switch(sTitle_Element.toLowerCase()) {
			default: //element title not defined in double click list
				if(gDebugMode==true) { fSupport_WarningMessage("Double Click Mask:\nObject " + sTitle_Element + " - no operation defined."); }
				break;
		}
	}

	//execute double click functions - element class: tool
	if(fObject_GetZIndexGroup(oElement).tool==true) {
		switch(sTitle_Element.toLowerCase()) {
			case gDefinition_TRASHCAN: //the target title is trashcan
				fRemoveManagedElement(oElement.id); //remove the element object (the element is the trashcan)
				break;		
		
			default: //element title not defined in double click list
				if(gDebugMode==true) { fSupport_WarningMessage("Double Click Tool:\nObject " + sTitle_Element + " - no operation defined."); }
				break;
		}
	}
}


//OBJECT support
function fObject_UpdateBrowserStatus(oElement) {
var sTitle, sAlt, lLeft, lTop, lZIndex, lZoom, sClassName, lWidth, lHeight, lCenterX, lCenterY, lMouseX, lMouseY, sBondedObject="", lRealOId, lCharacterLimit, sCharacter="";
	
	lMouseX=window.event.clientX; //get the current mouse position
	lMouseY=window.event.clientY;	
	
	sTitle=fObject_GetActualElementInfo(oElement.id).title;
	sAlt=fObject_GetActualElementInfo(oElement.id).alt;
	lLeft=parseInt(fObject_GetActualElementInfo(oElement.id).left, 10);
	lTop=parseInt(fObject_GetActualElementInfo(oElement.id).top, 10);
	lZIndex=parseInt(fObject_GetActualElementInfo(oElement.id).zindex, 10);
	lZoom=parseInt(fObject_GetActualElementInfo(oElement.id).zoom, 10);
	sClassName=fObject_GetActualElementInfo(oElement.id).classname;
	lCharacterLimit=fObject_GetActualElementInfo(oElement.id).characterlimit;
	if(lCharacterLimit>0) { sCharacter="- chars: " + lCharacterLimit; }	
	
	if(fObject_GetZIndexGroup(oElement).textfield==true || fObject_GetZIndexGroup(oElement).textlabel==true || fObject_GetZIndexGroup(oElement).infolayer==true ) { //textfield/infolayer - get the bonded object status
		switch(fObject_IsBonded(oElement).bonded) {
			case true: sBondedObject=" (bonded to ElementId: " + fObject_IsBonded(oElement).bondedobject + ")"; break;
			case false: sBondedObject=""; break;
		}
	}
	
	lRealOId=parseInt(fObject_GetActualElementInfo(oElement.id).realoid, 10);	
	lWidth=parseInt(fObject_GetActualElementInfo(oElement.id).width, 10);
	lHeight=parseInt(fObject_GetActualElementInfo(oElement.id).height, 10);
	lCenterX=parseInt(fObject_GetActualElementInfo(oElement.id).centerx, 10);
	lCenterY=parseInt(fObject_GetActualElementInfo(oElement.id).centery, 10);
	
	//update the browser status bar
	window.status="object id: " + lRealOId + " - " + sTitle + " (element: " + oElement.id + ") - class: " + sClassName + sBondedObject + " - (l: " + lLeft + ", t: " + lTop + ", w: " + lWidth + ", h: " + lHeight + ", z: " + lZIndex + ") - zoom: " + lZoom + "% " + sCharacter;
}

function fObject_UpdateDefinition(oElement) {
//updates the objectd definition - the storage element uses the following format: [STARTOFTEXT: ASCII(02)]~ID~TITLE~ALT~LEFT~TOP~WIDTH~HEIGHT~ZINDEX~ZOOM~CLASS~BONDEDOBJECTID~REALOBJECTID~SOURCE~SRC~CHARLIMIT
var sStorageId, sAlt, sTitle, lLeft, lTop, lZIndex, lZoom, sBondedObject, lRealOId, sSource, sSrc, lCharacterLimit, oMyActiveObject, cSOT=String.fromCharCode(2), cSeperator=String.fromCharCode(31), sDescription; //the startoftext code is (STX) - CHR(2), the seperator code is UNIT SEPERATOR (US) - CHRS(31)

	//try to update the definition for the specified object - this allows any object to be dragged
	try {
		//check whether the function was called with a specific element - if not use the current grabbed object
		if(oElement) { oMyActiveObject=oElement; } else { oMyActiveObject=gObject; }

		//check the object is active
		if (oMyActiveObject) {	
			sAlt=oMyActiveObject.alt;
			sTitle=oMyActiveObject.title;
			lLeft=parseInt(oMyActiveObject.style.left, 10); //get the object position
			lTop=parseInt(oMyActiveObject.style.top, 10);
			lZoom=fZoom_GetElementZoom(oMyActiveObject.id); //get the current zoom factor
			if(gOriginalObjectZIndex) {lZIndex=gOriginalObjectZIndex;} else {lZIndex=oMyActiveObject.style.zIndex;} //get the zindex - if the gOriginalObjectZIndex exists use that else get the default
			lWidth=parseInt(fZoom_GetElementSize(oMyActiveObject.id).width, 10); //get the current width
			lHeight=parseInt(fZoom_GetElementSize(oMyActiveObject.id).height, 10); //get the current width
			sClassName=oMyActiveObject.className; //get the class name
			sBondedObject=fObject_GetActualElementInfo(oMyActiveObject.id).bondedobject; //get the bonded shape
			lRealOId=fObject_GetActualElementInfo(oMyActiveObject.id).realoid; //get the real object id
			sSource=fObject_GetActualElementInfo(oMyActiveObject.id).source; //get the oringal source
			sSrc=fObject_GetActualElementInfo(oMyActiveObject.id).src; //get the object source			
			lCharacterLimit=fObject_GetActualElementInfo(oMyActiveObject.id).characterlimit; //get the object character limit

			//get the storage element - and update it
			document.getElementById(fObject_GetActualElementInfo(oMyActiveObject.id).storageid).value=cSOT + oMyActiveObject.id + cSeperator + sTitle + cSeperator + sAlt + cSeperator + lLeft + cSeperator + lTop + cSeperator + lWidth + cSeperator + lHeight + cSeperator + lZIndex + cSeperator + lZoom + cSeperator + sClassName + cSeperator + sBondedObject + cSeperator + lRealOId + cSeperator + sSource + cSeperator + sSrc + cSeperator + lCharacterLimit; //store the current object info in the storage element
		}
	
		fObject_UpdateBrowserStatus(oMyActiveObject); //update the windows status bar with the object details
	
	}
	//if the update failed - catch the error and continue
	catch (err) {
		sDescription=err.description;
	}
	
	return false; //set the return status 
	
}

function fObject_UpdateDiagramInfo() {
//updates the diagram definition - the system uses an existing diagram object id: the storage element uses the following format: [STARTOFHEADING: ASCII(01)]~DIAGRAMID~REFERENCE~MODE~NAME~REVISION~WIDTH~HEIGHT 
var oActiveDiagramObject, cSOH=String.fromCharCode(1), cSeperator=String.fromCharCode(31); //the startofheading code is (SOH) - CHR(1), the seperator code is UNIT SEPERATOR (US) - CHRS(31)
var lD_ID, sReference, lMode, sName, sAuthor_SMTP, dRevision, lWidth, lHeight;

	oActiveDiagramObject=document.getElementById(fXPathGetDiagramInfoID());
	
	if(oActiveDiagramObject) {	
		lD_ID=fDiagram_GetActualInfo().id;
		sReference=fDiagram_GetActualInfo().reference;
		lMode=fDiagram_GetActualInfo().mode;
		sName=fDiagram_GetActualInfo().name;
		dRevision=fDiagram_GetActualInfo().revision;
		lWidth=fDiagram_GetActualInfo().width;
		lHeight=fDiagram_GetActualInfo().height;
		if(gBackgroundObjectID) { fObject_RefreshBackground(); }	//refresh the background
		
		//get the diagram element - and update it
		oActiveDiagramObject.value=cSOH + lD_ID + cSeperator + sReference  + cSeperator + lMode + cSeperator + sName + cSeperator + dRevision + cSeperator + lWidth + cSeperator + lHeight; //store the info in the diagram element
			
	}	
}

function fObject_DragElement(oElement) { 
//initalise the grab function - the function expects two variables the object and the id for the storage text element (the hidden textfield used to store the location of the object)
var sShapeStorage;

	//only allow if element is dragable
	if(fDrag_ElementDragable()==true) {
		gObject=oElement; //create the element to the object buffer
		gOriginalObjectZIndex=gObject.style.zIndex; //store the current object zorder	
		gObject.style.zIndex = gZIndexSelected; //move the object to the top (zorder above any other object)
	
		fObject_UpdateDefinition(); //update the object location
	
		//create the event functions
		document.onmousedown=fDrag_DragEvent;
		document.onmouseup=fDrag_DropEvent;
	}
}

function fObject_DoubleClick(oElement) { //this function executes when the object is double clicked
	fAction_DoubleClickElementDetected(oElement);
}

function fObject_PostCreate(sElement) {
//this function is execute after an object is created
var sClass=fObject_GetActualElementInfo(sElement).classname;

	switch(sClass.toLowerCase()) {
		case "background":
			if(gBackgroundObjectID) { fRemoveManagedElement(gBackgroundObjectID); } //remove existing background object
			gBackgroundObjectID=sElement;
			fObject_RefreshBackground();
			break;
			
		case "shape": break;
		case "textfield": break;
		case "infolayer": break;
		case "textlabel": break;
		case "mask": break;
		case "tool": break;
		case "toolmenu": break;
		default: break;
	}
}

function fObject_RefreshBackground() {
//this function sets up the background
var lDWidth, lDHeight;

	if(gBackgroundObjectID) {
		//get the diagram size information
		lDWidth=fDiagram_GetActualInfo().width;
		lDHeight=fDiagram_GetActualInfo().height;	
	
		//set the background image to the dimension of the diagram
		fZoom_SetElementSize_Width(gBackgroundObjectID, lDWidth);
		fZoom_SetElementSize_Height(gBackgroundObjectID, lDHeight);
		fObject_UpdateDefinition(document.getElementById(gBackgroundObjectID)); //store the element
	}
}

function fObject_GetActualElementInfo(sElement) {
//this function returns the selected properties of the specified object - reference return value via return object - fObject_GetElementInfo('elementid').zoom
var sTitle="n/a", sAlt="n/a", lLeft=0, lTop=0, lZIndex=0, lZoom=0, lRealOId=0, sStorageId=0, sClassName="n/a", lWidth, lHeight, lCenterX, lCenterY, sBondedObject, lRealOId=-1, sSource, sSrc, lCharacterLimit;
var oObject=document.getElementById(sElement);
	
	if(oObject) {
		//export the specified object values
		sTitle=oObject.title; //export the object title
		sAlt=oObject.alt; //export the object alt
		lLeft=oObject.style.left; //export object left position
		lTop=oObject.style.top; //export object top position
		lZIndex=oObject.style.zIndex; //export object zIndex value
		lZoom=fZoom_GetElementZoom(sElement); //export the object zoom value
		sId=oObject.id; //export object id
		sStorageId=String(sId + gXPathObjDefinition); //export object id used to store object data (object definition)	
		sClassName=oObject.className; //export the object class
		sBondedObject=oObject.bondedObject; //export a custom object parameter
		if(isNaN(sBondedObject)==true) { sBondedObject=-1; } //filter the bonded shape value
		lRealOId=oObject.realOId; //export a custom object parameter
		if(isNaN(lRealOId)==true) { lRealOId=-1; } //filter the real object id
		sSource=oObject.getAttribute("source"); //get the original source
		sSrc=oObject.getAttribute("src"); //get the image source
		lCharacterLimit=oObject.getAttribute("characterlimit"); //get the character limit
		if(isNaN(lCharacterLimit)==true) { lCharacterLimit=0; } else { lCharacterLimit=parseInt(lCharacterLimit, 10) + 0; }
		
		//this calculation returns the calculated width/height of the object
		lWidth=fZoom_GetElementSize(sElement).width;
		lHeight=fZoom_GetElementSize(sElement).height;
		
		lCenterX=parseInt((parseInt(lWidth, 10)/2), 10); //this calculation returns the calculated centre positions the object
		lCenterY=parseInt((parseInt(lHeight, 10)/2), 10);		
	}
	return { title: sTitle, alt: sAlt, left:lLeft, top:lTop, zindex:lZIndex, zoom:lZoom, id:sId, storageid: sStorageId, classname: sClassName, width: lWidth, height: lHeight, centerx: lCenterX, centery: lCenterY, bondedobject: sBondedObject, realoid: lRealOId, source: sSource, src: sSrc, characterlimit: lCharacterLimit };
}

function fObject_GetActualElementLocation(sElement) {
//returns the global element position
var lLeft, lTop, lRight, lBottom;

	lLeft=parseInt(fObject_GetActualElementInfo(sElement).left, 10);
	lTop=parseInt(fObject_GetActualElementInfo(sElement).top, 10);	
	lRight=lLeft + (parseInt(fObject_GetActualElementInfo(sElement).width, 10));
	lBottom=lTop + (parseInt(fObject_GetActualElementInfo(sElement).height, 10));
		
	return { left: lLeft, top: lTop, right: lRight, bottom: lBottom }
}

function fDiagram_GetActualInfo() {
//this function returns the diagram information
var oActiveDiagramObject, lD_ID=-1, sReference="", lMode=-1, sName="", sAuthor_SMTP="", dRevision=-1, lWidth=-1, lHeight=-1;

	oActiveDiagramObject=document.getElementById(fXPathGetDiagramInfoID());
	if(oActiveDiagramObject) {	
		//load the diagram values
		lD_ID=oActiveDiagramObject.diagramId; if(isNaN(lD_ID)==true) { lD_ID=-1; }
		sReference=oActiveDiagramObject.diagramReference; if(sReference==undefined) { sReference=""; }
		lMode=oActiveDiagramObject.diagramMode; if(isNaN(lMode)==true) { lMode=-1; }
		sName=oActiveDiagramObject.diagramName; if(sName==undefined) { sName=""; }
		sAuthor_SMTP=oActiveDiagramObject.diagramAuthor; if(sAuthor_SMTP==undefined) { sAuthor_SMTP=""; }
		dRevision=oActiveDiagramObject.diagramRevision; if(isNaN(dRevision)==true) { dRevision=-1; }
		lWidth=oActiveDiagramObject.diagramWidth; if(isNaN(lWidth)==true) { lWidth=-1; }
		lHeight=oActiveDiagramObject.diagramHeight; if(isNaN(lHeight)==true) { lHeight=-1; }
	}
	
	return { id: lD_ID, reference: sReference, mode: lMode, name: sName, author: sAuthor_SMTP, revision: dRevision, width: lWidth, height: lHeight }
}

function fObject_IsElementDroppedOnTargetTagClass(oElement, sTag, bAllowAllZIndexTargets) {
//this function checks whether the element was drop on element of type=tag (eg: IMG)
var lInstance, oObjects=document.getElementsByTagName(sTag);
var lTargetLeft, lTargetTop, lTargetRight, lTargetBottom, lTargetZIndex, lElementX, lElementY, lElementZIndex;

	try {

		for(lInstance=0; lInstance<oObjects.length; lInstance++) { //a possible tag/class match has been detected - check positions
			
			lTargetLeft=fObject_GetActualElementLocation(oObjects[lInstance].id).left; //get the target location
			lTargetTop=fObject_GetActualElementLocation(oObjects[lInstance].id).top;
			lTargetRight=fObject_GetActualElementLocation(oObjects[lInstance].id).right;
			lTargetBottom=fObject_GetActualElementLocation(oObjects[lInstance].id).bottom;
			
			if(oElement.id!=oObjects[lInstance].id) { //check to make sure we dont target the dropped element as this is illogical		
				if(isNaN(lTargetLeft)==false && isNaN(lTargetTop)==false) { //check whether we have a positioned potential target - based on the center of the element
							
					lElementX=parseInt(fObject_GetActualElementInfo(oElement.id).left, 10) + fObject_GetActualElementInfo(oElement.id).centerx;
					lElementY=parseInt(fObject_GetActualElementInfo(oElement.id).top, 10) + fObject_GetActualElementInfo(oElement.id).centery;
					lElementZIndex=parseInt(fObject_GetActualElementInfo(oElement.id).zindex, 10)+0
					
					//confirm the coordinates are on the specified area				
					if(fSupport_PositionWithinArea(lElementX, lElementY, lTargetLeft, lTargetTop, lTargetRight, lTargetBottom)==true) {
						fAction_TargetDropDetected(oElement, oObjects[lInstance]);
					}
				}
			}
			
		}
	
	}
	catch (err) {
	
	}
}
	
function fObject_ObjectHotSpot(oElement) {
//the function returns the square position the mouse is located on the object
var lMouseX, lMouseY, lLeft, lTop, lRight, lBottom, lWidth, lHeight, lWidth_Divider, lHeight_Divider, bLeft=false, bTop=false, bRight=false, bBottom=false, bCenter=false;
var lHotspot_Left, lHotspot_Top, lHotspot_Right, lHotspot_Bottom, gDivisions=6, gZoneSize=2;

	lMouseX=window.event.clientX; //get the current mouse position
	lMouseY=window.event.clientY;

	//calculate the boundary positions
	lLeft=parseInt(fObject_GetActualElementInfo(oElement.id).left, 10);
	lTop=parseInt(fObject_GetActualElementInfo(oElement.id).top, 10);
	lWidth=parseInt(fObject_GetActualElementInfo(oElement.id).width, 10);
	lHeight=parseInt(fObject_GetActualElementInfo(oElement.id).height, 10);

	//calculate the divider values - used to create the hotspots	
	lWidth_Divider=parseInt(lWidth/gDivisions, 10);
	lHeight_Divider=parseInt(lHeight/gDivisions, 10);
	
	//check the left hotspot
	lHotspot_Left=lLeft;
	lHotspot_Top=lTop;
	lHotspot_Right=parseInt(lLeft + (lWidth_Divider*gZoneSize), 10);
	lHotspot_Bottom=parseInt(lTop + lHeight);
	bLeft=fSupport_PositionWithinArea(lMouseX, lMouseY, lHotspot_Left, lHotspot_Top, lHotspot_Right, lHotspot_Bottom); //check left zone
	
	//check the top hotspot
	lHotspot_Left=parseInt(lLeft + (lWidth_Divider*gZoneSize), 10);
	lHotspot_Top=lTop;
	lHotspot_Right=parseInt(((lLeft + lWidth) - (lWidth_Divider*2)), 10);
	lHotspot_Bottom=parseInt(lTop + (lHeight_Divider*gZoneSize), 10);
	bTop=fSupport_PositionWithinArea(lMouseX, lMouseY, lHotspot_Left, lHotspot_Top, lHotspot_Right, lHotspot_Bottom); //check top zone
	
	//check the right hotspot
	lHotspot_Left=parseInt(((lLeft + lWidth) - (lWidth_Divider*gZoneSize)), 10);
	lHotspot_Top=lTop;
	lHotspot_Right=parseInt(lLeft + lWidth, 10);
	lHotspot_Bottom=parseInt(lTop + lHeight);	
	bRight=fSupport_PositionWithinArea(lMouseX, lMouseY, lHotspot_Left, lHotspot_Top, lHotspot_Right, lHotspot_Bottom); //check left zone

	//check the bottom hotspot
	lHotspot_Left=parseInt(lLeft + (lWidth_Divider*gZoneSize), 10);
	lHotspot_Top=parseInt(((lTop + lHeight) - (lHeight_Divider*gZoneSize)), 10);
	lHotspot_Right=parseInt(((lLeft + lWidth) - (lWidth_Divider*gZoneSize)), 10);
	lHotspot_Bottom=parseInt(lTop + lHeight);
	bBottom=fSupport_PositionWithinArea(lMouseX, lMouseY, lHotspot_Left, lHotspot_Top, lHotspot_Right, lHotspot_Bottom); //check bottom zone
	
	//check the center hotspot
	lHotspot_Left=parseInt((lLeft + 1) + (lWidth_Divider*gZoneSize), 10);
	lHotspot_Top=parseInt((lTop + 1) + (lHeight_Divider*gZoneSize), 10);
	lHotspot_Right=parseInt(((lLeft + lWidth - 1) - (lWidth_Divider*gZoneSize)), 10);
	lHotspot_Bottom=parseInt(((lTop + lHeight - 1) - (lHeight_Divider*gZoneSize)), 10);
	bCenter=fSupport_PositionWithinArea(lMouseX, lMouseY, lHotspot_Left, lHotspot_Top, lHotspot_Right, lHotspot_Bottom); //check left zone
	
	return { left: bLeft, top: bTop, right: bRight, bottom: bBottom, center: bCenter }
}

function fObject_GetZIndexGroup(oElement) {
//function returns true/false depending on which group the zindex belongs
var bBackground=false, bShape=false, bTextfield=false, bInfolayer=false, bTextlabel=false, bMask=false, bTool=false, bToolMenu=false, lZIndex=0;
	
	if(oElement) {
		lZIndex=oElement.style.zIndex;
		if(lZIndex>=gZIndexBackground && lZIndex<=parseInt(gZIndexBackground + gZIndexLimit, 10)) { 	bBackground=true; }
		if(lZIndex>=gZIndexShape && lZIndex<=parseInt(gZIndexShape + gZIndexLimit, 10)) { bShape=true; }
		if(lZIndex>=gZIndexTextfield && lZIndex<=parseInt(gZIndexTextfield + gZIndexLimit, 10)) { bTextfield=true; }
		if(lZIndex>=gZIndexInfolayer && lZIndex<=parseInt(gZIndexInfolayer + gZIndexLimit, 10)) { bInfolayer=true; }
		if(lZIndex>=gZIndexTextlabel && lZIndex<=parseInt(gZIndexTextlabel + gZIndexLimit, 10)) { bTextlabel=true; }
		if(lZIndex>=gZIndexMask && lZIndex<=parseInt(gZIndexMask + gZIndexLimit, 10)) { bMask=true; }
		if(lZIndex>=gZIndexTool && lZIndex<=parseInt(gZIndexTool + gZIndexLimit, 10)) { bTool=true; }
		if(lZIndex>=gZIndexToolMenu && lZIndex<=parseInt(gZIndexToolMenu + gZIndexLimit, 10)) { bToolMenu=true; }
	}
	return { background: bBackground, shape: bShape, textfield: bTextfield, infolayer: bInfolayer, textlabel: bTextlabel, mask: bMask, tool: bTool, toolmenu: bToolMenu } 
}

function fObject_GetClassZIndexDefaultValue(sClass) {
//this function returns the default zIndex value based on the specified class
var lZIndex=0, lClassZIndexMin=0, lClassZIndexMax=0;

	switch(sClass.toLowerCase()) {
		case "background": lClassZIndexMin=gZIndexBackground; lClassZIndexMax=(lClassZIndexMin+gZIndexLimit); lZIndex=(gZIndexBackground+(gZIndexLimit/2)); break;
		case "shape": lClassZIndexMin=gZIndexShape; lClassZIndexMax=(lClassZIndexMin+gZIndexLimit); lZIndex=(gZIndexShape+(gZIndexLimit/2)); break;	
		case "textfield": lClassZIndexMin=gZIndexTextfield; lClassZIndexMax=(lClassZIndexMin+gZIndexLimit); lZIndex=(gZIndexTextfield+(gZIndexLimit/2)); break;		
		case "infolayer": lClassZIndexMin=gZIndexInfolayer; lClassZIndexMax=(lClassZIndexMin+gZIndexLimit); lZIndex=(gZIndexInfolayer+(gZIndexLimit/2)); break;
		case "textlabel": lClassZIndexMin=gZIndexTextlabel; lClassZIndexMax=(lClassZIndexMin+gZIndexLimit); lZIndex=(gZIndexTextlabel+(gZIndexLimit/2)); break;		
		case "mask": lClassZIndexMin=gZIndexMask; lClassZIndexMax=(lClassZIndexMin+gZIndexLimit); lZIndex=(gZIndexMask+(gZIndexLimit/2)); break;		
		case "tool": lClassZIndexMin=gZIndexTool; lClassZIndexMax=(lClassZIndexMin+gZIndexLimit); lZIndex=(gZIndexTool+(gZIndexLimit/2)); break;
		case "toolmenu": lClassZIndexMin=gZIndexToolMenu; lClassZIndexMax=(lClassZIndexMin+gZIndexLimit); lZIndex=(gZIndexToolMenu+(gZIndexLimit/2)); break;	
		default: 	lClassZIndexMin=gZIndexShape; lClassZIndexMax=(lClassZIndexMin+gZIndexLimit); lZIndex=(gZIndexShape+(gZIndexLimit/2)); break;
	}
	return { zindex: lZIndex, zindexmin: lClassZIndexMin, zindexmax: lClassZIndexMax }
}

function fXPathGetDiagramInfoID() { 	return gDiagramObjectID; }

function fDiagram_SetID(lD_ID) {
var oActiveDiagramObject; 
	oActiveDiagramObject=document.getElementById(fXPathGetDiagramInfoID()); if(oActiveDiagramObject) { oActiveDiagramObject.diagramId=lD_ID; fObject_UpdateDiagramInfo(); }
}

function fDiagram_SetReference(sReference) {
var oActiveDiagramObject;
	oActiveDiagramObject=document.getElementById(fXPathGetDiagramInfoID()); if(oActiveDiagramObject) { oActiveDiagramObject.diagramReference=sReference; fObject_UpdateDiagramInfo(); }
}

function fDiagram_SetMode(lMode) {
var oActiveDiagramObject;
	oActiveDiagramObject=document.getElementById(fXPathGetDiagramInfoID()); if(oActiveDiagramObject) { oActiveDiagramObject.diagramMode=lMode; fObject_UpdateDiagramInfo(); }
}

function fDiagram_SetName(sName) {
var oActiveDiagramObject;
	oActiveDiagramObject=document.getElementById(fXPathGetDiagramInfoID()); if(oActiveDiagramObject) { oActiveDiagramObject.diagramName=sName; fObject_UpdateDiagramInfo(); }
}

function fDiagram_SetRevision(dRevision) {
var oActiveDiagramObject;
	oActiveDiagramObject=document.getElementById(fXPathGetDiagramInfoID()); if(oActiveDiagramObject) { oActiveDiagramObject.diagramRevision=dRevision; fObject_UpdateDiagramInfo(); }
}

function fDiagram_SetWidth(lWidth) {
var oActiveDiagramObject;
	oActiveDiagramObject=document.getElementById(fXPathGetDiagramInfoID()); if(oActiveDiagramObject) { oActiveDiagramObject.diagramWidth=lWidth; fObject_UpdateDiagramInfo(); }
}

function fDiagram_SetHeight(lHeight) {
var oActiveDiagramObject;
	oActiveDiagramObject=document.getElementById(fXPathGetDiagramInfoID()); if(oActiveDiagramObject) { oActiveDiagramObject.diagramHeight=lHeight; fObject_UpdateDiagramInfo(); }
}

function fObject_SetObjectSrc(oElement, sSrc) {
//function stores the source against the specified element
	if(oElement) {
		oElement.source=sSrc; //create a custom object parameter
		fObject_UpdateDefinition(oElement); //update the element
	}
}

function fObject_GetObjectSrc(oElement) {
//returns the source of the specified element
var sSrc;
	sSrc=fObject_GetActualElementInfo(oElement.id).source;
	return { source: sSrc }
}

function fObject_SetObjectRealID(oElement, lRealOId) {
//function stores the real object id against the specified element
	if(oElement) {
		oElement.realOId=lRealOId; //create a custom object parameter
		fObject_UpdateDefinition(oElement); //update the element
	}
}	

function fObject_GetObjectRealID(oElement) {
//returns the real object id of the specified element
var lRealOId;
	lRealOId=fObject_GetActualElementInfo(oElement.id).realOId;
	return { realoid: lRealOId }
}

function fObject_SetObjectCharacterLimit(oElement, lCharacterLimit) {
//function stores the character limit against the specified element
	if(oElement) {
		oElement.characterlimit=lCharacterLimit; //create a custom object parameter
		fObject_UpdateDefinition(oElement); //update the element
	}
}	

function fObject_GetObjectCharacterLimit(oElement) {
//returns the real object id of the specified element
var lCharacterLimit;
	lCharacterLimit=fObject_GetActualElementInfo(oElement.id).characterlimit;
	return { characterlimit: lCharacterLimit }
}

function fObject_BondObject(oElement, sObject) {
//function creates a bond between the element and bonded shape

	if(oElement) {
		oElement.bondedObject=sObject; //create a custom object parameter
		fObject_UpdateDefinition(oElement); //update the element
	}
}
	
function fObject_IsBonded(oElement) {
//returns the bond status or bonded object
var sBondedObject;

	sBondedObject=fObject_GetActualElementInfo(oElement.id).bondedobject
	switch(parseInt(sBondedObject, 10)) {
		case -1: bBonded=false; break;
		default: bBonded=true; break;
	}
	
	return { bonded: bBonded, bondedobject: sBondedObject }
}
		
function fObject_FindObject(sContainer, sClass, sTitle, bForceNotFound) {
//function returns the first found id of any element matching class and title information - within the container
var oContainer, lNode, sElement_Class, sElement_Title, sId=0, bFound=false;

	oContainer=document.getElementById(sContainer);	
	if(oContainer.hasChildNodes()==true) {
		
		for(lNode=0; lNode<oContainer.childNodes.length; lNode++) {

			//create lower case descriptions
			sElement_Class=(oContainer.childNodes[lNode].className).toLowerCase();
			sElement_Title=(oContainer.childNodes[lNode].title).toLowerCase();

			//compare the descriptions with the pased variables
			if(sElement_Class==sClass.toLowerCase() && sElement_Title==sTitle.toLowerCase()) {
				sId=oContainer.childNodes[lNode].id; //set the return element id
				if(bForceNotFound==false) { bFound=true; } //check to see if we want to force a not found status 
				lNode=oContainer.childNodes.length; //set the loop to terminate
			}
		}
	}
	return { id: sId, found: bFound }
}

function fObject_OnElement(lCoordX, lCoordY, oElement) {
//returns true/false depending on whether the coordinates on within the element
var lLeft, lTop, lWidth, lHeight, lRight, lBottom;

	//use the direct values - as this increases performance
	lLeft=parseInt(oElement.style.left, 10);
	lTop=parseInt(oElement.style.top, 10);
	lWidth=parseInt(oElement.style.width, 10);
	lHeight=parseInt(oElement.style.height, 10);
	lRight=lLeft + lWidth;
	lBottom=lTop + lHeight;
	
	//adjust for OnElementOffsets
	lLeft=lLeft - gOnElementAllowedOffset;
	lTop=lTop - gOnElementAllowedOffset;
	lRight=lRight + gOnElementAllowedOffset;
	lBottom=lBottom + gOnElementAllowedOffset;
	
	return (fSupport_PositionWithinArea(lCoordX, lCoordY, lLeft, lTop, lRight, lBottom));
}
	
	
//DYNAMIC support
function fDynamicObject_InserNewScriptInstanceTESTINGONLY() {
//this function has been left in for example and possible later development
	var sHTML="<input type=button onclick=" + "go2()" + " value='Click Me' id=button3 name=button3><BR>"
	var sScript='<SCR' + 'IPT DEFER>'
	sScript = sScript + 'function go2(){ alert("Hello from inserted script.") }'
	sScript = sScript + '</scr' + 'ipt' + '>';
	ObjectInstance.insertAdjacentHTML("afterBegin",sHTML + sScript);
}

function fRemoveManagedElement(sElement) {
//this function removes a dynamic object and the storage element - function has been updated to allow for element to be under diferent parent containers
var oElementContainer=false, oStorageContainer=false, oElement=false, oStorage=false; //ElementStorage;

	//determine the object elements
	oElement=document.getElementById(sElement);	//get the element
	oStorage=document.getElementById(fObject_GetActualElementInfo(sElement).storageid); //get the storage element

	//get the parent container element - a possible better version: parentElement (ie)
	oElementContainer=oElement.parentNode;
	oStorageContainer=oStorage.parentNode;

	//remove the elements	
	if(oStorageContainer) { oStorageContainer.removeChild(oStorage); } //remove the storage object - just incase its contained with the element being deleted
	if(oElementContainer) { oElementContainer.removeChild(oElement); } //remove the element object	

	fSupport_SetBrowserStatus(gOffInstanceStatusMessage);

}

function fXPathCreateLayerElement(lId, lRealOId, sTag, sSrc, sTitle, sAlt, lLeft, lTop, lWidth, lHeight, lZindex, lZoom, sClass, lCharacterLimit) {
//this function create a dynamic layer element object - the element can be dragged/scaled/zindexed, returns the id or storageid
var oGlobalDiv=document.getElementById(gXPathDIVLayer), sHtmlCode, lInstance, sStorageType, sId, sStorageId, oElement;

	lInstance=fSupport_ReturnElementIDReference(lId);

	//set minimum defaults
	if(parseInt(lWidth, 10)<=0) { lWidth=0; }
	if(parseInt(lHeight, 10)<=0) { lHeight=0; }

	//create the image details properties
	sTag=sTag.toString();
	sSrc=sSrc.toString();
	sId=lInstance.toString();
	sStorageId=sId + gXPathObjDefinition;	
	sTitle=sTitle.toString();
	sAlt=sAlt.toString();
	lLeft=parseInt(lLeft, 10) + "px";
	lTop=parseInt(lTop, 10) + "px";
	lWidth=parseInt(lWidth, 10) + "px";
	lHeight=parseInt(lHeight, 10) + "px";
	lZindex=parseInt(lZindex, 10);
	lZoom=parseInt(lZoom, 10) + "%"
	sClass=sClass.toString();
	lCharacterLimit=parseInt(lCharacterLimit, 10);
		
	//define the type of storage elements
	if(gDebugMode==true) { sStorageType="text"; } else { sStorageType="hidden"; }
	
	//compile the instance html code string
	sHtmlCode="<!--managed object instance-->" +
		"<" + sTag + 
				" src=\"" + sSrc + "\"" +
				" id=\"" + sId + "\"" +
				" name=\"" + sId + "\"" +  
				" title=\"" + sTitle + "\"" + 
				" alt=\"" + sAlt + "\"" +
				" style=\"position: absolute; left: " + lLeft + "; top: " + lTop + "; width: " + lWidth + "; height: " + lHeight + "; z-index: " + lZindex + "; zoom=" + lZoom + "; visibility: visible;\"" +
				" class=\"" + sClass + "\"" +
				" width=\"" + lWidth + "\"" +    
				" height=\"" + lHeight + "\"" +        
				" onmousedown=\"fObject_DragElement(this)\"" +
				" onmousewheel=\"fZoom_ResizeObject(this)\"" +
				" onmouseout=\"fSupport_SetMouseCursor_Default(this); fSupport_MouseOffObjectBrowser()\"" +
				" onmouseover=\" fSupport_SetMouseCursor_Pointer(this); fObject_UpdateBrowserStatus(this)\"" +
				" ondblclick=\"fObject_DoubleClick(this)\"" +
		"/>" +
		"<!--static object storage -->" +
		"<" + "input" +
				" type=\"" + sStorageType + "\"" +
				" id=\"" + sStorageId + "\"" +
				" name=\"" + sStorageId + "\"" +
				" style=\"width: 1100px;\"" +
		"/>";

	oGlobalDiv.insertAdjacentHTML("beforeEnd",sHtmlCode); //execute the code	
	oElement=document.getElementById(sId); //create a reference to the new element
	fObject_UpdateDefinition(oElement); //store the created element
	fObject_SetObjectRealID(oElement, lRealOId); //store the real id
	fObject_SetObjectSrc(oElement, sSrc); //store the original source
	fObject_SetObjectCharacterLimit(oElement, lCharacterLimit); //store the character limit
	fObject_PostCreate(sId);	//execute post create functions
	
	return { id: sId, storageid: sStorageId }
}

function fXPathCreateDiagramInfo(lId, sReference, lMode, sName, dRevision, lWidth, lHeight) {
var oGlobalDiv=document.getElementById(gXPathDIVLayer), sHtmlCode, lInstance, sId, lElementID;

	lInstance=fSupport_ReturnElementIDReference(lId);

	//set minimum defaults
	if(parseInt(lWidth, 10)<=0) { lWidth=0; }
	if(parseInt(lHeight, 10)<=0) { lHeight=0; }

	//create the diagram infoproperties
	sId=lInstance.toString() + gXPathDiagramDefinition;
	lWidth=parseInt(lWidth, 10);
	lHeight=parseInt(lHeight, 10);
		
	//define the type of storage elements
	if(gDebugMode==true) { sStorageType="text"; } else { sStorageType="hidden"; }
	
	//compile the instance html code string
	sHtmlCode="<!--managed object instance-->" +
		"<!--diagram object -->" +
		"<" + "input" +
				" type=\"" + sStorageType + "\"" +
				" id=\"" + sId + "\"" +
				" name=\"" + sId + "\"" +
				" style=\"width: 1100px;\"" +
		"/>";

	oGlobalDiv.insertAdjacentHTML("afterBegin",sHtmlCode); //execute the code	
	gDiagramObjectID=document.getElementById(sId).id; //create a reference to the new element
		
	//set initial diagram values
	fDiagram_SetID(lId);
	fDiagram_SetReference(sReference);
	fDiagram_SetMode(lMode);
	fDiagram_SetName(sName);
	fDiagram_SetRevision(dRevision);
	fDiagram_SetWidth(lWidth); //set the diagram width
	fDiagram_SetHeight(lHeight); //set the diagram width	
	
	//return a pointer to the object
	return { id: gDiagramObjectID }
}

//-->
