﻿<?xml version="1.0" encoding="utf-8" ?> 
<!-- XML Component File -->
<application-components>
   <application-component id = "canvas" participant-id ="canvas">
      <![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(){
         }
      ]]>
   </application-component>
</application-components>
