<?xml version="1.0" encoding="UTF-8"?>
<DWAC Title = "Canvas Hierarchy" DWacTemplateId = "Hierarchy Example">
<fragments>
<fragment id = "TemplateTools">
<span>
	<embedded-script>
			<![CDATA[
		embedded_init : function(){
			if(this.getStatus().preferred_title && typeof this.setTitle == "function"){
				this.setTitle(this.getStatus().preferred_title);
			}
			this.setupButtons("buttons-bar");
			// Clear any status
			//
			if(typeof this.setStatus == "function") this.setStatus("");
		},
		FormatStringIntoHtml : function(oNode, sData){
			if(!oNode || !sData) return;
			var aDat = sData.split("\n");
			for(var i = 0; i < aDat.length; i++){
				var oD = document.createElement("p");
				var sLine = this.TrimSafe(aDat[i]);
				if(sLine.length == 0) oD.appendChild(document.createElement("br"));
				else oD.appendChild(document.createTextNode(sLine));
				oNode.appendChild(oD);
			}
		},
		GetElementByRID : function(n){
			var o = this.getTemplateEngine().getObjectByName(n);
			if(!o) return 0;
			if(o.object){
				if(typeof o.object.getContainer == 'function') return o.object.getContainer();
				return o.object;
			}
			return o;
		},
		// TODO: Temporary fix until form set value is fixed for selects
		//
		SetSelectValueByIndex : function(n,v){
			var o = this.GetElementByRID(n);
			if(!o || typeof o.selectedIndex != "number") return;
			for(var i = 0; i < o.options.length; i++){
				if(o.options[i].value == v || (o.options[i].value == "" && o.options[i].text == v)){
					o.selectedIndex = i;
					break;
				}
				
			}
		},
		// TODO: There is a bug in the setValue function in ocjxf.setValue where select options
		// are not being selected
		//
		SetFormValue : function(n, v){
			return org.cote.js.xhtml.form.XHTMLFormComponent.setValue(n,v, this.getTemplateEngine().engine_id)
		},
		GetFormValue : function(n){
			return org.cote.js.xhtml.form.XHTMLFormComponent.getValue(n,this.getTemplateEngine().engine_id)
		},
		GetForm : function(){
			return org.cote.js.xhtml.form.XHTMLFormComponent.getFormByName(this.getTemplateEngine().engine_id);
		},
		ClearForm : function(){
			return org.cote.js.xhtml.form.XHTMLFormComponent.clearForm(this.getTemplateEngine().engine_id,0,0);
		},
		GetElementText : function(oParent, sName){
			var aN = oParent.getElementsByTagName(sName);
			if(aN.length == 0) return ""; // was 0;
			return org.cote.js.xml.getInnerText(aN[0]);
		},
		SetText : function(sName, sValue){
			var o = this.GetElementByRID(sName);
			if(!o) return;
			org.cote.js.xml.setInnerXHTML(o,sValue);
		},
		Register : function(){
    		var oX = this.SerializeForm();
				var oR = org.cote.js.xml.postXml("Registration.aspx?is-xml=1&NewRegistration=1",oX);
				if(oR == null || oR.documentElement == null){
					this.setStatus("Error sending/receiving registration request.");
				}
				else if(this.IsSuccess(oR)){
					this.setStatus("Submitted Registration");
					this.loadTemplate("Templates/RegistrationCompleted.xml");
				}
				else{
					this.setStatus("Failed to submit registration request");
				}
		},
		IsSuccess : function(oX){
		  if(!oX || !oX.documentElement) return 0;
		  return (oX.getElementsByTagName("Success").length > 0 ? 1 : 0);
		},
		IsLoginRequired : function(oX){
		  if(!oX || !oX.documentElement) return 0;
		  return (oX.getElementsByTagName("Login-Required").length > 0 ? 1 : 0);
		},
		ShowLogin : function(){
			var oW = GetWindowManager().GetWindowByName("LoginWindow");
			if(oW){
				oW.open();
				oW.restore();
				GetSession().Refresh(1);
				oW.setStatus("Logged out");
				oW.loadTemplate("ActionForms/Login.xml");
			}
		},
		SetElementParam : function(oX, name, val){
		  if(!oX || !oX.documentElement) return 0;
		  var oParams = oX.documentElement.getElementsByTagName("Params");
		  if(oParams.length == 0){
			oParams = oX.createElement("Params");
		  }
		  else{
			oParams = oParams[0];
		  }
	      
		  var oParam = oX.createElement("Param");
				oParams.appendChild(oParam);
		  oParam.setAttribute("Name",name);
				oParam.setAttribute("Value","#cdata");
				oParam.appendChild(oX.createCDATASection(val));
		},
		GetDataNameExists : function(sSubAppPath,aFields){
			var oForm = this.SerializeForm(0,aFields);
			var oX = org.cote.js.xml.postXml(g_application_path + sSubAppPath + "/CheckName?is-xml=1",oForm);

			if(oX == null || oX.documentElement == null){
				alert("Error retrieving response");
				return 1;
			}
			if(oX.getElementsByTagName("True").length > 0) return 1;
			return 0;
		},
		SerializeForm : function(oX,aLimit){
			var eid = this.getTemplateEngine().engine_id;
			
			if(!oX) oX = org.cote.js.xml.newXmlDocument("Request");
			var oForm = oX.createElement("Form");
			oForm.setAttribute("cid",this.getObjectId());
			oForm.setAttribute("eid",eid);
			
			oX.documentElement.appendChild(oForm);				
			var aElements = this.GetForm().getElements();
			for(var e = 0; e < aElements.length;e++){
				var name = aElements[e].getName();
				if(typeof aLimit == "object" && aLimit.length){
					var b = 0;
					for(var m = 0; m < aLimit.length; m++){
						if(aLimit[m] == name){
							b = 1;
							break;
						}
					}
					if(!b) continue;
				}

				/*
					use the getValue() method to ensure that the value is taken from the visible element first, then the cache value
					otherwise, the value of the element object - not the Form Element HTML node - may not be synchronized, and thus not the expected value
				*/
				var val = org.cote.js.xhtml.form.XHTMLFormComponent.getValue(name,eid);
				if(typeof val == "boolean") val = val.toString();
				var sType = aElements[e].getType();
				
				if(!val || val.length == 0 || !sType) continue;
				 
				var oElement = oX.createElement("Element");
				oForm.appendChild(oElement);
				var oName = oX.createElement("Name");
				oName.appendChild(oX.createCDATASection(name));
				oElement.appendChild(oName);
				var oValue = oX.createElement("Value");
				oValue.appendChild(oX.createCDATASection(val));
				oElement.appendChild(oValue);
				oElement.setAttribute("Type",sType);
			}
			return oX;
		},
		ValidateForm : function(b){
			var oF = this.GetForm();
			return org.cote.js.xhtml.form.XHTMLFormComponent.validateForm(oF.i, b);
		},
		ValidateForPattern : function(n, p){
			var oF = this.GetForm();
			if(!oF) return 0;
			var oE = oF.getElementByName(n);
			if(!oE) return 0;
			return org.cote.js.xhtml.validator.XHTMLValidator.validateField(oE.getElement(),p);
		},
		DiagramStep : function(sLabel, iMark, iTotal){
			var oLabel = this.GetElementByRID("step_label");
			var oDiag = this.GetElementByRID("step_diagram");
			if(!oLabel || !oDiag) return;
			org.cote.js.xml.setInnerXHTML(oLabel,sLabel);
			for(var i = 0; i < iTotal; i++){
				var oI = document.createElement("img");
				oI.setAttribute("src","Graphics/" + (iMark > i ? "star_hover.jpg" : "star_empty.jpg"));
				oI.setAttribute("width","20");
				oI.setAttribute("width","20");
				oDiag.appendChild(oI);
			}
		},
		EnableButton : function(n){
			this.SwitchButton(n,false);
		},
		DisableButton : function(n){
			this.SwitchButton(n,true);
		},
		SwitchButton : function(n, b){
			var o = this.GetElementByRID(n),a,ac=" ";
			if(!o) return;
			a = o.getAttribute("button-action");
			if(a) ac += a.toLowerCase() + "_button";
			o.disabled = b;
			o.className = "designer_button" + ac;
		},
		setupButtons : function(sName){
			var o = this.getTemplateObjectByName(sName);
			if(!o) return;
			var aC = o.childNodes,a;
			this.createHandler("toggle_highlight",0,0,1);
			this.createHandler("exec_button",0,0,1);
			for(var i = 0; i < aC.length; i++){
				
				if(aC[i].nodeType == 1){
					a = aC[i].getAttribute("button-action");
					if(!a || a.length == 0) continue;
					aC[i].onmouseover = this._prehandle_toggle_highlight;
					aC[i].onmouseout = this._prehandle_toggle_highlight;
					if(a != "avoid" && typeof this._handle_exec_button == "function" && !aC[i].onclick) aC[i].onclick = this._prehandle_exec_button;
				}
			}
		},
		_handle_toggle_highlight : function(e){
			var o = org.cote.js.dom.event._gevt_src(e),a,ac = " ";
			e = org.cote.js.dom.event._gevt(e);
			a = o.getAttribute("button-action");
			if(a) ac += a.toLowerCase() + "_button";
			if(e.type == "mouseover")
				o.className = "designer_button designer_button_highlight" + ac;
			else
				o.className = "designer_button" + ac;
		},
		
		get_frame : function(n){
			var aF = this.getContainer().getElementsByTagName("iframe");
			for(var i = 0; i < aF.length; i++){
				if(aF[i].getAttribute("rid") == n){
					o = aF[i];
					break;
				}
			}
			if(o) o = (o.contentWindow || o.contentDocument);
			if(!o) return null;
			//if(o.document) o = o.document;
			if(!o.document || !o.document.body) return null;
			return o;
		},
		
		GetComponentByRID : function(sRid){
			var o = this.getTemplateEngine().getObjectByName(sRid);
			if(!o || !o.object) return 0;
			return o.object.getApplicationComponent();

		},
		ResizeFrame : function(n,iModWidth,iModHeight){
			try{
				var d = this.getTemplateObjectByName(n);
				
				var iT = d.offsetTop;
				// the parentNode x 3 is a bug
				// where Engine is not correctly swapping out the html-fragment element
				//
				var iB = d.parentNode.parentNode.parentNode.clientHeight;
							//(typeof this.getBody == "function" ? this.getBody() : d.parentNode).clientHeight;
							//n.parentNode.parentNode.parentNode.clientHeight;
				var iH = (iB - iT );
				if(iModHeight > 0) iH -= iModHeight;
				
				if(iH < 1) iH = 1;
				
				var iW = this.getContainer().clientWidth - 20;
				if(iModWidth > 0) iW -= iModWidth;
				if(iW < 1) iW = 1;
				
				d.style.height = iH + "px";
				d.style.width = iW + "px";
			}
			catch(e){
				this.setStatus("Unexpected UI Error: " + (e.message ? e.message : e.description));
			}
		},
		TrimSafe : function(s){
			if(typeof s != "string") return "";
			s = s.replace(/^\s*/gi,"");
			s = s.replace(/\s*$/gi,"");
			return s;
		}
	]]></embedded-script>
</span></fragment></fragments>
<tasks>
</tasks>
<application-components><application-component id="canvas" package-name="">
<![CDATA[
component_init : function()
{
   //org.cote.js.message.MessageService.sendMessage(this.getContainer().clientWidth);
									
						/// Setup properties
						///
   
						this.getStatus().MouseTrackLeft = 0;
						this.getStatus().MouseTrackTop = 0;
						this.getStatus().MouseTrackDown = 0;
						this.getStatus().MouseOffsetX = 0;
						this.getStatus().MouseOffsetY = 0;
						this.getStatus().DefaultShapeRadius = 20;
						this.getStatus().DefaultShapeVerticalSpacing = 15;
						this.getStatus().DefaultShapeHorizontalSpacing = 5;
						this.getStatus().DefaultShapeGridUnit = ((this.getStatus().DefaultShapeRadius * 2) + (this.getStatus().DefaultShapeHorizontalSpacing * 2));
   
						/// Setup object pointer references
						///
						this.getPointers().canvas = 0;
						this.getPointers().canvas_2d = 0;
						this.getPointers().temp_canvas = 0;
						this.getPointers().temp_canvas_2d = 0;
   
						/// shapes contains object representations of vectors applied to the canvas
						///
						this.getPointers().shapes = [];
									 
						/// temp_shapes contains shapes currently applied to the temporary canvas
						///
						this.getPointers().temp_shapes = [];
									 
						/// shape_track_map is a jagged array of x-axis[int],y-axis[int],node_indices[]
						///
						this.getPointers().shape_track_map = [];
						
						/// Current shape decorator
						///
						this.getPointers().ShapeDecorators = [];
						this.getPointers().CurrentShape = 0;
						this.getPointers().MouseDropShape = 0;
   
						var oC = this.getContainer();
						if(oC.nodeName.toLowerCase() != "canvas"){
							oC = document.createElement("canvas");
							this.getContainer().appendChild(oC);
						}
						this.getPointers().canvas = oC;
						if(typeof oC.getContext == "undefined"){
								org.cote.js.message.MessageService.sendMessage("Browser does not support canvas","200.4");
								return;
						}
						this.getPointers().canvas_2d = oC.getContext("2d");
						var oT = document.createElement("canvas");
						oT.width = oC.clientWidth;
						oT.height = oC.clientHeight;
						oT.style.cssText = "position:absolute;top:0px;left:0px;";
						oC.parentNode.appendChild(oT);
						this.getPointers().temp_canvas = oT;
						this.getPointers().temp_canvas_2d = oT.getContext("2d");
						
						oC.parentNode.style.position = "relative";
						
						this.createHandler("canvas_mouse",0,0,1);
				    org.cote.js.dom.event.addEventListener(oT,'mousedown', this._prehandle_canvas_mouse);
						org.cote.js.dom.event.addEventListener(oT,'mousemove', this._prehandle_canvas_mouse);
						org.cote.js.dom.event.addEventListener(oT,'mouseup', this._prehandle_canvas_mouse);
						
						this.Draw(this.NewText("Loaded Canvas",0,0,"#000000"));
},

AddShapeDecorator : function(o)
{
   this.getPointers().ShapeDecorators.push(o);
},

Clear : function()
{
   this.ClearTempCanvas();
						this.ClearCanvas();
},

ClearTempCanvas : function()
{
   this.getPointers().temp_shapes = [];
							this.getPointers().temp_canvas_2d.clearRect(0, 0, this.getPointers().canvas.clientWidth, this.getPointers().canvas.clientHeight);
},

ClearCanvas : function()
{
   this.getPointers().shape_track_map = [];
							this.getPointers().canvas_2d.clearRect(0, 0, this.getPointers().canvas.clientWidth, this.getPointers().canvas.clientHeight);
							this.getPointers().shapes = [];
							/// TODO: Delete non-vectors based on shape property, not blind delete all spans
							///
							var aText = this.getPointers().canvas.parentNode.getElementsByTagName("span");
							for(var i = aText.length - 1; i >=0; i--){
								this.getPointers().canvas.parentNode.removeChild(aText[i]);
							}
},

Draw : function(oShape, bStroke)
{
   if(typeof oShape != "object" || typeof oShape.type != "string") return;
							switch(oShape.type){
								case "RoundedRect":
									this.getPointers().temp_shapes.push(oShape);
									oShape.rendered = 1;
									this.DrawRoundedRect(oShape);
									break;
								case "Ellipse":
									this.getPointers().temp_shapes.push(oShape);
									oShape.rendered = 1;
									this.DrawEllipse(oShape);
									break;
								case "Arc":
									this.getPointers().temp_shapes.push(oShape);
									oShape.rendered = 1;
									this.DrawArc(oShape.x,oShape.y,oShape.radius,oShape.startAngle,oShape.endAngle,bStroke,oShape.fillStyle,oShape.strokeStyle);
									break;
								case "Rect":
									this.getPointers().temp_shapes.push(oShape);
									oShape.rendered = 1;
									this.DrawRect(oShape.x, oShape.y, oShape.width, oShape.height, bStroke, oShape.fillStyle,oShape.strokeStyle);
									break;
								case "Text":
									this.getPointers().temp_shapes.push(oShape);
									oShape.rendered = 1;
									var bType = this.DrawText(oShape.text, oShape.x, oShape.y, oShape.fillStyle);
									if(bType == 2) oShape.is_html = 1;
									break;
								default:
									alert("Unknown shape: " + oShape.type);
							}
},

DrawRoundedRect : function(oShape)
{
   /// RoundedRect  based on CanvasPaint's paint.js - http://canvaspaint.org
						///
						if(!oShape.type == "RoundedRect") return;
						var x1 = oShape.x, x2 = oShape.x + oShape.width, y1 = oShape.y, y2 = oShape.y + oShape.height
								,dx, dy, _p = this.getPointers()
						;
						dx = Math.abs(x2-x1);
						dy = Math.abs(y2-y1);
   
						var dmin = (dx < dy) ? dx : dy;
						var cornersize = (dmin/2 >= 15) ? 15 : dmin/2;
						
						var xdir = (x2 > x1) ? cornersize : -1*cornersize;
						var ydir = (y2 > y1) ? cornersize : -1*cornersize;
   
						_p.temp_canvas_2d.beginPath();
						_p.temp_canvas_2d.fillStyle = oShape.fillStyle;
						_p.temp_canvas_2d.strokeStyle = oShape.strokeStyle;
						_p.temp_canvas_2d.moveTo(x1, y1+ydir);
						_p.temp_canvas_2d.quadraticCurveTo(x1, y1, x1+xdir, y1);
						_p.temp_canvas_2d.lineTo(x2-xdir, y1);
						_p.temp_canvas_2d.quadraticCurveTo(x2, y1, x2, y1+ydir);
						_p.temp_canvas_2d.lineTo(x2, y2-ydir);
						_p.temp_canvas_2d.quadraticCurveTo(x2, y2, x2-xdir, y2);
						_p.temp_canvas_2d.lineTo(x1+xdir, y2);
						_p.temp_canvas_2d.quadraticCurveTo(x1, y2, x1, y2-ydir);
						_p.temp_canvas_2d.fill();
						_p.temp_canvas_2d.stroke();
						_p.temp_canvas_2d.closePath();
},

DrawEllipse : function(oShape)
{
   /// Elipse  based on CanvasPaint blog - http://canvaspaint.org/blog/2006/12/ellipse/
						///
						if(!oShape.type == "Ellipse") return;
   
						var x1 = oShape.x,
								x2 = oShape.x2,
								y1 = oShape.y,
								y2 = oShape.y2,
								kappa = oShape.kappa,
								rx, ry, cx, cy,
								 _p = this.getPointers()
						;
						rx = (x2-x1)/2;
						ry = (y2-y1)/2;
						cx = x1 + rx;
						cy = y1 + ry;
   
						_p.temp_canvas_2d.beginPath();
						_p.temp_canvas_2d.fillStyle = oShape.fillStyle;
						_p.temp_canvas_2d.strokeStyle = oShape.strokeStyle;
						_p.temp_canvas_2d.moveTo(cx, cy - ry);
						_p.temp_canvas_2d.bezierCurveTo(cx + (kappa * rx), cy - ry,  cx + rx, cy - (kappa * ry), cx + rx, cy);
						_p.temp_canvas_2d.bezierCurveTo(cx + rx, cy + (kappa * ry), cx + (kappa * rx), cy + ry, cx, cy + ry);
						_p.temp_canvas_2d.bezierCurveTo(cx - (kappa * rx), cy + ry, cx - rx, cy + (kappa * ry), cx - rx, cy);
						_p.temp_canvas_2d.bezierCurveTo(cx - rx, cy - (kappa * ry), cx - (kappa * rx), cy - ry, cx, cy - ry);
						_p.temp_canvas_2d.fill();
						_p.temp_canvas_2d.stroke();
						_p.temp_canvas_2d.closePath();
},

DrawArc : function(x, y, radius, s, e, bStroke, fill_color, border_color)
{
   var _p = this.getPointers();
   
  						if(!fill_color) fill_color = _p.temp_canvas_2d.fillStyle;
							if(!border_color) border_color = fill_color;
							_p.temp_canvas_2d.beginPath();
							_p.temp_canvas_2d.fillStyle = fill_color;
							_p.temp_canvas_2d.strokeStyle = border_color;
							_p.temp_canvas_2d.arc(x,y,radius,s,e,false);
							_p.temp_canvas_2d.fill();
							if(bStroke) _p.temp_canvas_2d.stroke();
							_p.temp_canvas_2d.closePath();
},

DrawRect : function(x, y, w, h, bStroke, fill_color, border_color)
{
   var _p = this.getPointers();
							if(!fill_color) fill_color = _p.temp_canvas_2d.fillStyle;
							if(!border_color) border_color = fill_color;
							_p.temp_canvas_2d.fillStyle = fill_color;
							_p.temp_canvas_2d.strokeStyle = border_color;
							_p.temp_canvas_2d[(bStroke ? "strokeRect" : "fillRect")](x,y,w,h);
},

DrawText : function(sText, vX, vY, sColor)
{
   var iH = this.getPointers().canvas.clientHeight;
							if(!sColor) sColor = "#000000";
							/*
							if(typeof this.getPointers().canvas_2d.measureText != "undefined"){
    						this.getPointers().temp_canvas_2d.font = "10pt Courier";
    						this.getPointers().temp_canvas_2d.fillStyle = "#0000FF";
								if(vX == "center"){
									var iW = this.getPointers().canvas.width;
									var iTW = this.getPointers().canvas_2d.measureText(sText).width;
									if(iTW < iW) vX = (iW / 2) - (iTW / 2);
									else vX = 0;
								}
								this.getPointers().temp_canvas_2d.fillText(sText,vX,vY);
								return 1;
							}
							else{
							*/
								var oT = document.createElement("span");
								oT.appendChild(document.createTextNode(sText));
								oT.style.cssText = "font: normal 10pt Courier;color: " + sColor + ";position:absolute;top:" + vY + "px;left:" + vX + "px;";
								this.getPointers().canvas.parentNode.appendChild(oT);
								return 2;
							//}
},

ConnectShapes : function(oShape1, oShape2, sType)
{
   if(!sType) sType = "elbow";
										 
							/// Straight Line
							///
							if(sType == "line"){
								this.getPointers().temp_canvas_2d.beginPath();
								this.getPointers().temp_canvas_2d.moveTo(oShape1.x,oShape1.y);
								this.getPointers().temp_canvas_2d.lineTo(oShape2.x,oShape2.y);
								this.getPointers().temp_canvas_2d.stroke();
								this.getPointers().temp_canvas_2d.closePath();
							}
							/// Elbow Connector
							///
							else if(sType == "elbow"){
								//org.cote.js.message.MessageService.sendMessage("Connect " + oP.shape.x + "," + oP.shape.y + " -> " + oNode.shape.x + "," + oNode.shape.y);
								this.getPointers().temp_canvas_2d.beginPath();
								this.getPointers().temp_canvas_2d.fillStyle = "#000000";
								this.getPointers().temp_canvas_2d.strokeStyle = "#000000";
								//this.getPointers().temp_canvas_2d.lineCap = "round";
								//this.getPointers().temp_canvas_2d.lineJoin = "miterLimit";
								var iMod = 0;
								if(oShape1.type == "Rect") iMod = 20;
								this.getPointers().temp_canvas_2d.moveTo(oShape1.x + iMod,oShape1.y + iMod + 20);
								this.getPointers().temp_canvas_2d.lineTo(oShape1.x + iMod,oShape1.y + iMod + 25);
								this.getPointers().temp_canvas_2d.lineTo(oShape2.x + iMod,oShape1.y + iMod + 25);
								this.getPointers().temp_canvas_2d.lineTo(oShape2.x + iMod,oShape2.y + iMod - 20);
								this.getPointers().temp_canvas_2d.stroke();
								this.getPointers().temp_canvas_2d.closePath();
							}
},

Rasterize : function()
{
   var _p = this.getPointers();
							_p.canvas_2d.drawImage(_p.temp_canvas, 0, 0);
							_p.temp_canvas_2d.clearRect(0, 0, _p.canvas.clientWidth, _p.canvas.clientHeight);
},

Ellipse : function(x, y, x2, y2, fill_color, border_color)
{
   var o = this.NewEllipse(x,y,x2,y2,fill_color,border_color);
							//alert(border_color + ":" + o.strokeStyle);
							this.Draw(o);
							return o;
},

Circle : function(x, y, r, fill_color, border_color)
{
   var o = this.NewCircle(x,y,r,fill_color,border_color);
							this.Draw(o);
							return o;
},

RoundedRect : function(x, y, w, h, fill_color, border_color)
{
   var o = this.NewRoundedRect(x,y,w,h,fill_color,border_color);
							this.Draw(o);
							return o;
},

Rect : function(x, y, w, h, fill_color, border_color)
{
   var o = this.NewRect(x,y,w,h,fill_color,border_color);
							this.Draw(o);
							return o;
},

Text : function(sText, x, y, fill_color, stroke_color)
{
   var o = this.NewText(sText, x, y, fill_color, stroke_color);
							this.Draw(o);
							return o;
},

NewEllipse : function(x, y, x2, y2, sFill, sStroke)
{
   var iIndex = this.getPointers().shapes.length;
							return this.getPointers().shapes[iIndex] = this.Merge(
								this.NewShape(iIndex,"Ellipse",sFill, sStroke),
								{
									x:x,
									y:y,
									x2:x2,
									y2:y2,
									kappa:4 * ((Math.sqrt(2) -1) / 3)
								}
							);
},

NewCircle : function(x, y, r, sFill, sStroke)
{
   var iIndex = this.getPointers().shapes.length;
							return this.getPointers().shapes[iIndex] = this.Merge(
								this.NewShape(iIndex,"Arc",sFill, sStroke),
								{
									x:x,
									y:y,
									radius:r,
									startAngle:0,
									endAngle:Math.PI*2
								}
							);
},

NewText : function(sText, x, y, sFill, sStroke)
{
   var iIndex = this.getPointers().shapes.length;
							return this.getPointers().shapes[iIndex] = this.Merge(
								this.NewShape(iIndex,"Text",sFill, sStroke),
								{
									x:x,
									y:y,
									text:sText,
								}
							);
},

NewRoundedRect : function(x, y, w, h, sFill, sStroke)
{
   var o = this.NewRect(x, y, w, h, sFill, sStroke);
							o.type = "RoundedRect";
							return o;
},

NewRect : function(x, y, w, h, sFill, sStroke)
{
   var iIndex = this.getPointers().shapes.length;
							return this.getPointers().shapes[iIndex] = this.Merge(
								this.NewShape(iIndex,"Rect",sFill, sStroke),
								{
									x:x,
									y:y,
									height:h,
									width:w
								}
							);
},

NewShape : function(iIndex, sType, sFill, sStroke)
{
   return {
								index : iIndex,
								type:sType,
								layerIndex:0,
								fillStyle: sFill,
								strokeStyle: sStroke,
								id:null,
								rendered:0,
								children:[],
								parent:0,
								is_html:0,
								reference_id:-1,
								selectable : 1
							};
},

Merge : function(s, t)
{
   for(var i in s){
								if(typeof t[i] == "undefined") t[i]=s[i];
							}
							return t;
},

ShapeAt : function(x, y)
{
   if(typeof this.getPointers().shape_track_map[x] == "object" && typeof this.getPointers().shape_track_map[x][y] == "number"){
							return this.getPointers().shapes[this.getPointers().shape_track_map[x][y]];
						}
						
						var oS = this.FindShapeAt(x, y);
						if(oS){
							if(typeof this.getPointers().shape_track_map[x] != "object") this.getPointers().shape_track_map[x] = [];
							this.getPointers().shape_track_map[x][y] = oS.index;
						}
						return oS;
},

FindShapeAt : function(x, y)
{
   var oShape,oMatch = 0;
						for(var i = 0; i < this.getPointers().shapes.length; i++){
							if(!(oShape = this.getPointers().shapes[i]) || !oShape.selectable) continue;
							switch(oShape.type){
								
								case "Arc":
									// Not valid - replace with point<->circle intersection
									//
									if(x >= oShape.x && x <= ( oShape.x + (oShape.radius*2) ) && y >= oShape.y && y <= (oShape.y + (oShape.radius*2))) oMatch = oShape;
									break;
								case "Rect":
									// org.cote.js.message.MessageService.sendMessage(x + ">=" + oShape.x + " : " + x + " <= " + (oShape.x + oShape.width));
									// org.cote.js.message.MessageService.sendMessage(y + " > " + oShape.y + " > " + oShape.height);
									if(x >= oShape.x && x <= ( oShape.x + oShape.width ) && y >= oShape.y && y <= (oShape.y + oShape.height)) oMatch = oShape;
									break;
								default:
									// org.cote.js.message.MessageService.sendMessage("Skip: " + oShape.type + " : " + oShape.x);
									break;
							}
							if(oMatch) break;
						}
						return oMatch;
},

handle_canvas_mousemove : function(e)
{
   //if(this.getStatus().MouseTrackDown == 1){
								this.getPointers().MouseDropShape = this.ShapeAt(this.getStatus().MouseTrackLeft,this.getStatus().MouseTrackTop);
							//}
							this.dispatch_decorators(e);
},

handle_canvas_mouseup : function(e)
{
   this.dispatch_decorators(e);
						  this.getStatus().MouseTrackDown = 0;
							this.getPointers().CurrentShape = 0;
							this.getPointers().MouseDropShape = 0;
							this.getStatus().MouseTrackChoose = 0;
							this.getStatus().MouseOffsetX = 0;
							this.getStatus().MouseOffsetY = 0;
							this.getStatus().MouseTrackLeft = 0;
							this.getStatus().MouseTrackTop = 0;
},

dispatch_decorators : function(e)
{
   var aD = this.getPointers().ShapeDecorators;
						for(var i = 0; i < aD.length; i++){
							if(typeof aD[i]["handle_canvas_" + e.type] == "function") aD[i]["handle_canvas_" + e.type](this,e);
						}
},

handle_canvas_mousedown : function(e)
{
   this.getStatus().MouseTrackDown = 1;
						var oShape = this.ShapeAt(this.getStatus().MouseTrackLeft,this.getStatus().MouseTrackTop);
						if(oShape){
							this.getPointers().CurrentShape = oShape;
							this.getStatus().MouseTrackChoose = 1;
							this.getStatus().MouseOffsetX = this.getStatus().MouseTrackLeft - oShape.x;
							this.getStatus().MouseOffsetY = this.getStatus().MouseTrackTop - oShape.y;
							// org.cote.js.message.MessageService.sendMessage("Hit!");
							//this.Rect(oN.shape.x, oN.shape.y, oN.shape.width, oN.shape.height, "#00FF00", "#000000");
						}
						//else org.cote.js.message.MessageService.sendMessage("Miss!");
						this.dispatch_decorators(e);
},

_handle_canvas_mouse : function(e)
{
   e = org.cote.js.dom.event._gevt(e);
						var sHandler = "handle_canvas_" + e.type;
						//if(!SvgHierarchy.ShapeTool || typeof SvgHierarchy.ShapeTool[sHandler] != "function") return;
		
						this.getStatus().MouseTrackLeft = (typeof e.layerX == "number" ? e.layerX : e.offsetX); //e.clientX;
						this.getStatus().MouseTrackTop = (typeof e.layerY == "number" ? e.layerY : e.offsetY); //e.clientY;
						
						if(typeof this[sHandler] == "function") this[sHandler](e);
						//SvgHierarchy.ShapeTool[sHandler](e);
},

component_destroy : function()
{
   
},

Resize : function(x, y)
{
   this.getPointers().canvas.height = y;
   this.getPointers().canvas.width = x;
   this.getPointers().temp_canvas.height = y;
   this.getPointers().temp_canvas.width = x;
}
]]>
</application-component><application-component id="hierarchy" participant-id="canvas" package-name="">
<![CDATA[
SetCanvasComponent : function(o)
{
   if(typeof o.getObjectType == "undefined" || o.getObjectType() != "application_component"){
							alert("Expecting 'canvas' application component");
							return;
						}
						this.getPointers().canvas = o;	 
						o.AddShapeDecorator(this.getPointers().hierarchy_decorator);
},

NodeHierarchyToJSON : function()
{
   if(!this.getPointers().node_tree[1]) return "{\"Hierarchy\":[]}";
						var aN = this.getPointers().node_tree[1];
						var a = [];
						for(var i = 0;i < aN.length; i++){
							var oN = this.getPointers().nodes[aN[i]];
							if(!oN) continue;
							a.push(this.NodeToJSON(oN));
						}
						return "{\"Hierarchy\":[" + a.join(",") + "]}";
},

NodeToJSON : function(oNode)
{
   var a = [];
						a.push("{\"name\":\"" + oNode.text + "\",\"id\":\"" + oNode.id + "\",\"nodes\":[");
						var c = [];
						for(var i = 0; i < oNode.children.length;i++){
							c.push(this.NodeToJSON(this.getPointers().nodes[oNode.children[i]]));
							
						}
						a.push(c.join(","));
						a.push("]}");
						return a.join("");
},

ClearHierarchy : function()
{
   this.getStatus().node_counter = 0;
						this.getPointers().nodes = [];
						this.getPointers().node_tree = [];
						this.getPointers().canvas.Clear();
},

Render : function()
{
   this.getPointers().canvas.ClearTempCanvas();
							this.getPointers().canvas.ClearCanvas();
							//org.cote.js.xml.removeChildren(document.getElementById("_spot"));
							//OrganizeTree();
							//PlotOrganizationsSubStrate(1);
							this.BalanceTree();
							this.PlotOrganizations(1);
							this.getPointers().canvas.Rasterize();
},

PlotOrganizations : function(iDepth)
{
   var iLeafWidth = 0;
							var vNodes = this.GetNodesAtDepthByParent(iDepth);
							var aNodes = this.GetNodesAtDepth(iDepth);
							
							var iPrevWidth = 0;
							var iStartLeft = 0;
   
							// iterate through parent node aggregate
							//
							for(var p = 0; p < vNodes.length; p++){
								if(!vNodes[p]) continue;
   
								var iLeafWidth = 0;
								var bMod = 0;
   
								// iterate through leaf nodes
								//
								for(var i = 0; i < vNodes[p].length; i++){
									var oNode = vNodes[p][i];
									var oParent = 0;
									var iGridColumn = 0;
									if(oNode.parent >= 0) oParent = this.getPointers().nodes[oNode.parent];
   
									// pixel width of the maximum leaf nodeset
									//
									iLeafWidth = oNode.left_breadth + oNode.right_breadth + 1;
									var iGridMod = 0;
   
									if(oParent){
											
										var iModCol = oParent.children.length;
										if(!iPrevWidth) iPrevWidth = oParent.grid_column - oParent.left_breadth;
										if(oParent.children.length == 1){
											iGridColumn = oParent.grid_column;
										}
										else{
											iGridMod = (
												oParent.children.length % 2 == 0
												&&
												(oNode.position + oNode.right_breadth) >= Math.ceil(oParent.children.length/2)
												? 1 : 0
												);
   
											/// If the position is pushed to the right of the parent w / even children
											/// Then skip the extra alignment bump.
											/// The alignment bump is only to distribute even children to either side of the parent
											///
											if(!bMod && (iPrevWidth + oNode.left_breadth) > oParent.grid_column) bMod = 1;
											iGridColumn = (!bMod ? iGridMod : 0) + iPrevWidth + oNode.left_breadth;
											bMod = (!bMod && iGridMod ? 1 : 0);
										}
										iPrevWidth = iGridColumn + oNode.right_breadth + 1;
									}
									else{
										iGridColumn = iPrevWidth + (iGridMod ? iGridMod : oNode.left_breadth);
										iPrevWidth += iLeafWidth + (oNode.children.length % 2 == 0 ? 1 : 0);
									}
									oNode.grid_column = iGridColumn;
   
									iStartLeft = iGridColumn * this.getPointers().canvas.getStatus().DefaultShapeGridUnit;
   
									var iX = iStartLeft;
									var iY = (this.getPointers().canvas.getStatus().DefaultShapeRadius * 2 * (iDepth-1)) + (this.getPointers().canvas.getStatus().DefaultShapeVerticalSpacing * (iDepth - 1));
   
									oNode.shape = 
										//Rect(iX - SvgHierarchy.ShapeRadius, iY - SvgHierarchy.ShapeRadius, SvgHierarchy.ShapeRadius * 2, SvgHierarchy.ShapeRadius *2, "#0000FF","#CFCFCF")
										this.getPointers().canvas.Rect(iX, iY, this.getPointers().canvas.getStatus().DefaultShapeRadius * 2, this.getPointers().canvas.getStatus().DefaultShapeRadius *2, "#0000FF","#CFCFCF")
										//Circle(iX, iY, SvgHierarchy.ShapeRadius, "#0000FF", "#CFCFCF")
									;
									 
									oNode.shape.reference_id = oNode.index;
   
									if(oNode.parent >=0) this.getPointers().canvas.ConnectShapes(this.getPointers().nodes[oNode.parent].shape, oNode.shape);
									var oText = this.getPointers().canvas.Text(oNode.text,iX,iY,"#00FF00");
									oText.reference_id = oNode.index;
									
								}
							}		
   
							if(this.getPointers().node_tree.length > iDepth) this.PlotOrganizations(iDepth + 1);
							return;
},

BalanceTree : function()
{
   var aN = this.getPointers().node_tree;
							for(var i = aN.length - 1; i >=0; i--){
								if(typeof aN[i] != "object"){
									/// Tree not extended at this depth
									continue;
								};
								for(var c = aN[i].length - 1; c>=0; c--){
									if(typeof aN[i][c] != "number"){
										alert('Splice error at ' + i + ":" + c);
										continue;
									}
									if(this.getPointers().nodes[aN[i][c]].parent >= 0) this.UpdateLeaf(this.getPointers().nodes[aN[i][c]],this.getPointers().nodes[this.getPointers().nodes[aN[i][c]].parent]);
								}
							}
},

GetNodesAtDepthByParent : function(iDepth)
{
   var a = this.GetNodesAtDepth(iDepth);
							var oa = [];
							for(var i = 0; i < a.length; i++){
								var o = a[i];
								var iP = o.parent;
								// root node is -1
								// so bump to 0 for the purposes of sorting
								//
								if(iP < 0) iP = 0;
								if(!oa[iP]) oa[iP] = [];
								oa[iP].push(o);
							}
							return oa;
},

GetNodesAtDepth : function(iDepth)
{
   var a = (this.getPointers().node_tree[iDepth] ? this.getPointers().node_tree[iDepth] : []);
							var oa = [];
							for(var i = 0; i < a.length; i++){
								oa.push(this.getPointers().nodes[a[i]]);
							}
							return oa;
},

ReparentOrganizationNode : function(oNode, oNewParent)
{
   // node cannot be parented below itself.
							//
							if(oNode.index == oNewParent.index || oNode.parent == oNewParent.index){
								org.cote.js.message.MessageService.sendMessage("Nothing to do");
								return 0;		
							}
							if(this.IsChild(oNewParent,oNode)){
								org.cote.js.message.MessageService.sendMessage("Cannot reparent to a child node");
								return 0;
							}
							if(oNode.parent >= 0){
								org.cote.js.message.MessageService.sendMessage("Removing node " + oNode.text + " from " + this.getPointers().nodes[oNode.parent].text);
							}
							else{
								org.cote.js.message.MessageService.sendMessage("Removing node " + oNode.text + " from top organization");
							}
							
							this.RemoveNodeFromTree(oNode,1);
							if(oNode.parent >=0) this.RemoveNodeFromParent(oNode);
							
							org.cote.js.message.MessageService.sendMessage("Attaching node " + oNode.text + " (" + oNode.index + ") to " + oNewParent.text + " (" + oNewParent.index + ")");
							oNode.parent = oNewParent.index;
							oNode.depth = oNewParent.depth + 1;
   
							this.AddNodeToTree(oNode);
							
							this.BalanceTree();
   
							this.Render();
},

AddNodeToTree : function(oNode, bNoReParent)
{
   var _p = this.getPointers();
							/// Expand the tree depth to accommodate the specified level
							///
							for(var i = 1; i <= oNode.depth; i++){
								if(_p.node_tree[i]) continue;
								_p.node_tree[i] = [];
							}
							
							/// Insert the node reference (using in-memory index) into the tree at the specified depth
							//
							var l = _p.node_tree[oNode.depth].length;
							_p.node_tree[oNode.depth][l] = oNode.index;
							
							if(!bNoReParent) this.AddNodeAtParent(oNode);
   
							/// If the node has any children, rebuild the children tree
							/// This occurs when moving nodes around via Remove then Add
							/// Make sure the depth correctly adjusted
							///
							for(var i = 0; i < oNode.children.length; i++){
								_p.nodes[oNode.children[i]].depth = oNode.depth + 1;
								this.AddNodeToTree(_p.nodes[oNode.children[i]],1);
							}
							return oNode;
},

RemoveNodeFromTree : function(oNode, bKeepParent)
{
   if(typeof this.getPointers().node_tree[oNode.depth] != "object") return 0;
							
							for(var i = 0; i < oNode.children.length;i++) this.RemoveNodeFromTree(this.getPointers().nodes[oNode.children[i]], bKeepParent);
							for(var i = 0; i < this.getPointers().node_tree[oNode.depth].length; i++){
								if(this.getPointers().node_tree[oNode.depth][i] == oNode.index){
									this.getPointers().node_tree[oNode.depth].splice(i,1);
									//org.cote.js.message.MessageService.sendMessage("Splice node " + oNode.text + " at " + oNode.index);
									break;
								}
							}
							/// Debug - make sure node is out of tree
							///
							/*
							for(var n = 0; n < this.getPointers().node_tree.length; n++){
								if(typeof this.getPointers().node_tree[n] != "object") continue;
								for(var i = 0; i < this.getPointers().node_tree[n].length; i++){
									if(this.getPointers().node_tree[n][i] == oNode.index) alert('failed to splice');
								}
							}
							*/
							if(!bKeepParent && oNode.parent >= 0) this.RemoveNodeFromParent(oNode);
							oNode.depth = -1;
},

IsChild : function(oNode, oPossibleParent)
{
   var bCheck = 0;
							for(var i = 0; i < oPossibleParent.children.length; i++){
								if(oNode.index == oPossibleParent.children[i] || this.IsChild(oNode,this.getPointers().nodes[oPossibleParent.children[i]])){
									bCheck = 1;
									break;
								}
							}
							return bCheck;
},

AddNodeAtParent : function(oNode)
{
   if(oNode.depth <= 1 || oNode.parent < 0) return;
						var oP = this.getPointers().nodes[oNode.parent];
						var iL = oP.children.length;
						oP.children[iL] = oNode.index;
						oNode.position = iL;
						this.UpdateLeaf(oNode, oP);
},

RemoveNodeFromParent : function(oNode)
{
   if(oNode.parent < 0) return;
							var oP = this.getPointers().nodes[oNode.parent];
							oP.children.splice(oNode.position,1);
							//org.cote.js.message.MessageService.sendMessage("Splice node " + oNode.text + " from parent " + oP.text + " at " + oNode.position);
							/// Reset the remaining node positions
							///
							for(var i = oNode.position; i >= 0 && i < oP.children.length; i++){
								var oCN = this.getPointers().nodes[oP.children[i]];
								//org.cote.js.message.MessageService.sendMessage("Reposition adjacent child " + oCN.text + " from " + oCN.position + " to " + (oCN.position - 1));
								oCN.position--;
								//UpdateLeaf(oCN,oP);
							}
									
							/// Orphan the node
							///
							oNode.parent = -1;
							oNode.position = -1;
},

UpdateLeaf : function(oNode, oParent, iNewWidth)
{
   var iChildLen = oParent.children.length;
						if(!iNewWidth){
							iNewWidth = 1;
						}
						if(oNode.children.length == 0){
							oNode.center_breadth = 0;
							oNode.left_breadth = 0;
							oNode.right_breadth = 0;
						}
						oNode.leaf_width = Math.max(iNewWidth,Math.max(oNode.children.length,1));
						oParent.leaf_width = Math.max(oParent.children.length,1);
						
						// If the parent has children
						//    Then balance the array length with any odd value centered
						//
						if(iChildLen){
							var iSplit = Math.max(iNewWidth,iChildLen)/2;
							oParent.left_breadth = Math.floor(iSplit);
							oParent.center_breadth = (iChildLen %2);
							oParent.right_breadth = Math.ceil((iChildLen - oParent.center_breadth)/2);
							// If the node is on the right breadth, then pad the parent's required right breadth
							//
							var iNodeBreadth = oNode.left_breadth + oNode.right_breadth;
   
							if(oNode.position >= Math.ceil(iChildLen/2)){
								oParent.right_breadth += iNodeBreadth;
							}
							else oParent.right_breadth += oNode.right_breadth;
   
							if(Node.position <= Math.floor(iChildLen/2)){
								oParent.left_breadth += iNodeBreadth;
							}
							else oParent.left_breadth += oNode.left_breadth;
						}
   
						if(oParent.depth < 1 || oParent.parent < 0) return;
						
						var oP = this.getPointers().nodes[oParent.parent];
						var iP = 0;
						for(var p= 0; p < oP.children.length; p++){
							iP += this.getPointers().nodes[oP.children[p]].leaf_width;
						}
						
						this.UpdateLeaf(oParent,this.getPointers().nodes[oParent.parent],iP);
},

NewOrganizationNode : function(sId, sText, oParent)
{
   return this.Merge(this.NewNode(sId,sText,"org",oParent),
							{
							}
						);
},

Merge : function(s, t)
{
   for(var i in s){
								if(typeof t[i] == "undefined") t[i]=s[i];
							}
							return t;
},

NewNode : function(sId, sText, sType, oParent)
{
   var iIndex = this.getPointers().nodes.length;
							return this.getPointers().nodes[iIndex] = this.AddNodeToTree({
								text:(!sText ? sId : sText),
								id:sId,
								type:sType,
								left_breadth : 0,
								center_breadth : 0,
								right_breadth : 0,
								leaf_width : 0,
								children:[],
								parent:(oParent ? oParent.index : -1),
								// Index in the master node collection
								index : iIndex,
								// Position in the parent's child collection,
								position : 0,
								// Grid column position; placeholder for the renderer
								//
								grid_column : 0,
								shape : 0,
								depth:(oParent ? oParent.depth + 1 : 1)
							});
},

component_init : function()
{
   this.getStatus().node_counter = 0;
   this.getPointers().nodes = [];
   this.getPointers().node_tree = [];
}
]]>
</application-component><application-component id="hierarchy-decorator" participant-id="canvas">
			<![CDATA[
				 SetHierarchy : function(o){
						this.getPointers().Hierarchy = o;	 
					},
				 handle_canvas_mousedown : function(oCanvas, e){
						if(!oCanvas.getStatus().MouseTrackChoose) return;
						
						oCanvas.ClearTempCanvas();
						var oShape = oCanvas.getPointers().CurrentShape;
						if(oShape.type == "Rect"){
							var oM = oCanvas.Rect(oShape.x, oShape.y, oShape.width, oShape.height, "#00FF00", "#000000");
							oM.selectable = 0;
							var oCurrentNode = this.getPointers().Hierarchy.getPointers().nodes[oShape.reference_id];
							this.BlotChildrenToTempShape(oCanvas, oCurrentNode, oCurrentNode, oM);
						}

				 },
				 handle_canvas_mouseup : function(oCanvas, e){
						var _s = oCanvas.getStatus(), _p = oCanvas.getPointers();
						oCanvas.ClearTempCanvas();
						if(
									!_s.MouseTrackChoose
									||
									!_p.CurrentShape
									||
									_p.CurrentShape.reference_id < 0
									||
									!_p.MouseDropShape
									||
									_p.MouseDropShape.reference_id < 0
						){
							return;
						}
						var oSourceNode = this.getPointers().Hierarchy.getPointers().nodes[_p.CurrentShape.reference_id];
						var oTargetNode = this.getPointers().Hierarchy.getPointers().nodes[_p.MouseDropShape.reference_id];
						if(
							oSourceNode.type == "org"
							&&
							oTargetNode.type == "org"
						){
							this.getPointers().Hierarchy.ReparentOrganizationNode(oSourceNode,oTargetNode);
						}	
							
				 },
				 handle_canvas_mousemove : function(oCanvas, e){
					//if(!oCanvas.getStatus().MouseTrackDown) return;
					oCanvas.ClearTempCanvas();
					
					var sDropColor = "#FFFF00";
					var oDropShape = oCanvas.getPointers().MouseDropShape;
					var oDropNode, oCurrentNode = 0;
							 
					if(oDropShape && oDropShape.reference_id >= 0){
						oDropNode = this.getPointers().Hierarchy.getPointers().nodes[oDropShape.reference_id];
						//org.cote.js.message.MessageService.sendMessage("Drop Shape at " + oDropShape.x + ", " + oDropShape.y);
						//var oM = oCanvas.Rect(oDropShape.x, oDropShape.y, oDropShape.width, oDropShape.height, "#FFFF00", "#000000");
						//oM.selectable = 0;
					}

					var oCurrent = oCanvas.getPointers().CurrentShape;
					if(oCanvas.getStatus().MouseTrackChoose && oCurrent && oCurrent.reference_id >= 0){
						oCurrentNode = this.getPointers().Hierarchy.getPointers().nodes[oCurrent.reference_id];
						if(oCurrent.type == "Rect"){
							var oM = oCanvas.Rect(oCurrent.x, oCurrent.y, oCurrent.width, oCurrent.height, "#00FF00", "#000000");
							oM.selectable = 0;
							oM = oCanvas.Rect(
								oCanvas.getStatus().MouseTrackLeft - oCanvas.getStatus().MouseOffsetX,
								oCanvas.getStatus().MouseTrackTop - oCanvas.getStatus().MouseOffsetY,
								oCurrent.width,
								oCurrent.height, 
								"#00FF00", "#000000"
							);
							oM.selectable = 0;
							this.BlotChildrenToTempShape(oCanvas, oCurrentNode, oCurrentNode, oM);
						}
						
						if(oDropNode && oCurrentNode &&
									(
									this.getPointers().Hierarchy.IsChild(oDropNode,oCurrentNode)
									||
									oCurrentNode.parent == oDropNode.index
									)
						) sDropColor = "#FF0000";
					} 

					if(oDropNode){
						var oM = oCanvas.Rect(oDropShape.x, oDropShape.y, oDropShape.width, oDropShape.height, sDropColor, "#000000");
						oM.selectable = 0;
					}
				 },
				   
				 BlotChildrenToTempShape : function(oCanvas, oSourceParent, oCurrent, oShape){
					for(var i = 0; i < oCurrent.children.length; i++){
						var oChild = this.getPointers().Hierarchy.getPointers().nodes[oCurrent.children[i]];
						if(!oChild.shape) continue;
						var iX = oChild.shape.x - (oSourceParent.shape.x - oShape.x);
						var iY = oChild.shape.y - (oSourceParent.shape.y - oShape.y);
						var oM = oCanvas.Rect(oChild.shape.x, oChild.shape.y, oChild.shape.width, oChild.shape.height, "#00FF00", "#000000");
						oM.selectable = 0;

						oM = oCanvas.Rect(
							iX,
							iY,
							oShape.width,
							oShape.height, 
							oShape.fillStyle, oShape.strokeColor
						);
						oM.selectable = 0;
						this.BlotChildrenToTempShape(oCanvas, oSourceParent,oChild,oShape);
					    
				    }
				 }
			]]>
		</application-component></application-components><Templates>
<Template id="Hierarchy Example">
<!-- Enter valid XHTML -->

<p>
<input type="button" value="Org" onclick="${this}.DoOrg()"/>
<input type="button" value="JSON" onclick="${this}.DoToJSON()"/>
<input type="button" value="Eval" onclick="${this}.EvalHierarchy()"/>
<input type="button" value="Clear Hierarchy" onclick="${this}.DoClearHierarchy()"/>
<input type="text" rid="last_id" style="width:25px;" value="0"/>
<input type="text" rid="node_name" value=""/>
<input type="button" value="Add" onclick="${this}.DoAdd()"/>
<input type="button" value="Render" onclick="${this}.GetComponentByRID('hierarchy').Render()"/>
</p>
<div rid="canvas" acid="canvas" width="600" height="400" appcomp_path = "${dwac.path}"/>
<span rid="hierarchy" acid="hierarchy" appcomp_path = "${dwac.path}"/>
<span rid="hierarchy-decorator" acid="hierarchy-decorator" appcomp_path = "${dwac.path}"/>
<textarea rid="hierarchy-text" style="width:100%;height:200px;"/>

<import-dxml context-path="/DWAC/fragments/fragment[@id = 'TemplateTools']/span" src="${dwac.path}"/>

<embedded-script><![CDATA[
DoToJSON : function()
{
   this.GetElementByRID("hierarchy-text").value = this.GetComponentByRID("hierarchy").NodeHierarchyToJSON();
},

DoClear : function()
{
   this.GetComponentByRID("hierarchy").getPointers().canvas.Clear();
},

DoOrg : function()
{
   this.DoClear();
 this.GetComponentByRID("hierarchy").Render();
},

DoClearHierarchy : function()
{
   this.GetComponentByRID("hierarchy").ClearHierarchy();
},

template_init : function()
{
   this.GetComponentByRID("hierarchy").getPointers().hierarchy_decorator = this.GetComponentByRID("hierarchy-decorator");
   this.GetComponentByRID("hierarchy-decorator").SetHierarchy(this.GetComponentByRID("hierarchy"));
   this.GetComponentByRID("hierarchy").SetCanvasComponent(this.GetComponentByRID("canvas"));
   this.GetComponentByRID("canvas").Resize(600,400);
   //this.LoadDemo();
},

DoAdd : function()
{
   var oHC = this.GetComponentByRID("hierarchy");
   var sName = this.GetElementByRID("node_name").value;
   if(!sName.length) sName = "Node";
   var iLastId = parseInt(this.GetElementByRID("last_id").value);
   if(isNaN(iLastId)) iLastId = 0;
   var oP = 0;
   if(iLastId >= 0) oP = oHC.getPointers().nodes[iLastId];
   var oNode = oHC.NewOrganizationNode(++oHC.getStatus().node_counter,sName,oP);
   this.GetElementByRID("last_id").value = oNode.index;
   oHC.Render();
},

LoadHierarchy : function(vNode, oParent)
{
   var oOrg = this.GetComponentByRID("hierarchy").NewOrganizationNode(vNode.id,vNode.name,oParent);
   for(var i = 0; i < vNode.nodes.length; i++){
      this.LoadHierarchy(vNode.nodes[i],oOrg);
      }
},

EvalHierarchy : function()
{
   this.DoClearHierarchy();
   var sVal = this.GetElementByRID("hierarchy-text").value;
   var x;
   eval("x=" + sVal);
   if(x.Hierarchy) x = x.Hierarchy;
   for(var i = 0; i < x.length; i++){
      this.LoadHierarchy(x[i]);
      }
   this.GetComponentByRID("hierarchy").Render();
}
]]></embedded-script>
</Template></Templates>
</DWAC>
