//<script type="text/javascript">

Doodle.Canvas = JSX.Class.create({
	name: 'Canvas',
	constructor: function(divCanvas, application) {
		this.divCanvas = divCanvas;
		this.application = application;
		this.document = application.getDocument();
		this.gr = new Graphics(divCanvas);
		
		this.widgets = new Array(); // array of widgets indexed by ID

		// set up mouse handlers
		this.divCanvas.onmousedown = this.onMouseDown.bindEvent(this);
		this.divCanvas.onmousemove = this.onMouseMove.bindEvent(this);
		this.divCanvas.onmouseup = this.onMouseUp.bindEvent(this);
		this.divCanvas.onclick = this.onClick.bindEvent(this);
		this.divCanvas.ondblclick = this.onDblClick.bindEvent(this);
		
		// canvas properties
		this.bMouseDown = false;
		
		// other properties
		this.gr.penColor = "black";
		
		// widget selection
		this.primaryWidget = null;
	},

	members: {
		getDocument: function() {
			return this.document;
		},

		addWidget: function(widget) {
			this.widgets[widget.getID()] = widget;
		},
		delWidget: function(widget) {
			delete this.widgets[widget.getID()];
		},
		delWidgetByID: function(id) {
			delete this.widgets[id];
		},

		select: function(widget) {
			if ( this.primaryWidget ) this.unselect(this.primaryWidget);
			
			this.primaryWidget = widget;
			widget.onSelect();
		},
		unselect: function(widget) {
			if ( this.primaryWidget === widget ) {
				this.primaryWidget.onUnselect();
				this.primaryWidget = null;
			}
		},

		getMousePos: function(evt) {
			var pos = dhtml.getElementPosition(this.divCanvas);
			var scroll = dhtml.getScrollPos();
			var x = evt.clientX - (pos.left - scroll.left);
			var y = evt.clientY - (pos.top - scroll.top);
				
			return {x:x, y:y};
		},

		onMouseDown: function(evt) {
			var pos = this.getMousePos(evt);
			if ( !this.primaryWidget ) {
				switch ( this.application.getShapeType() ) {
				case Doodle.Doc.Shape.Types.POINT:
					this.primaryWidget = new Doodle.Canvas.Point(this);
					break;
				case Doodle.Doc.Shape.Types.LINE:
					this.primaryWidget = new Doodle.Canvas.Line(this);
					break;
				case Doodle.Doc.Shape.Types.ELLIPSE:
					this.primaryWidget = new Doodle.Canvas.Ellipse(this);
					break;
				case Doodle.Doc.Shape.Types.BEZIER_CURVE:
					this.primaryWidget = new Doodle.Canvas.BezierCurve(this);
					break;
				}
				var pos = this.getMousePos(evt);
				this.primaryWidget.create(evt, pos);
			} else {
				this.primaryWidget.onMouseDown(evt, pos);
			}
			return false;
		},
		onMouseMove: function(evt) {
			if ( this.primaryWidget ) {
				this.primaryWidget.onMouseMove(evt, this.getMousePos(evt));
			}
		},
		onMouseUp: function(evt) {
			if ( this.primaryWidget ) {
				this.primaryWidget.onMouseUp(evt, this.getMousePos(evt));
			}
		},
		onClick: function(evt) {
			if ( this.primaryWidget ) {
				this.primaryWidget.onClick(evt, this.getMousePos(evt));
			}
		},
		onDblClick: function(evt) {
			if ( this.primaryWidget ) {
				this.primaryWidget.onDblClick(evt, this.getMousePos(evt));
			}
		}
	}
});

//=============================================================================
// Widget heirarchy
//
// Widgets are view-objects that represent document shapes within the canvas
Doodle.Canvas.Widget = JSX.Class.create({
	name: 'Widget',
	constructor: function(canvas, shape) {
		// base classes must do nothing when constructed with no arguments
		if ( arguments.length == 0 ) return;
		
		// pointer to canvas
		this.canvas = canvas;
		
		// pointer to graphics
		this.gr = canvas.gr;
		
		// store the document shape
		this.shape = shape;
		
		// some properties
		this.bSelected = false;
	},

	members: {
		create: function(shape, evt, bSelected) {
			this.shape = shape;
			this.bSelected = bSelected;
			
			this.draw();
		},

		getID: function() {
			return this.shape.getID();
		},

		onMouseDown: function(evt, pos) {
			if ( !this.bSelected ) {
				this.canvas.delWidget(this);
				this.remove();
				this.destroy();
				dhtml.cancelEvent(evt);
			}
		},
		onMouseMove: function(evt) {
		},
		onMouseUp: function(evt) {
		},
		onClick: function(evt) {
		},
		onDblClick: function(evt) {
		},

		// default implementation of draw
		draw: function() {
		},

		// default implementation of undraw
		undraw: function() {
		},

		// destroy - destroy the Widget instance (doesn't affect document)
		destroy: function() {
			this.undraw();
			delete this.canvas;
			delete this.shape;
		},

		// remove - remove shape from document.
		remove: function() {
			this.canvas.getDocument().delShape(this.shape);
		},

		// select - activate widget for editing.
		select: function() {
			this.canvas.select(this);
		},

		// unselect - deactivate widget.
		unselect: function() {
			this.canvas.unselect(this);
		},

		onSelect: function() {
			this.bSelected = true;
		},
		onUnselect: function() {
			this.bSelected = false;
		}
	}
});

//=============================================================================
// Point Widget
Doodle.Canvas.Point = JSX.Class.create({
	name: 'Point',
	base: Doodle.Canvas.Widget,
	constructor: function(canvas, point) {
		this.Widget.call(this, canvas, point);
	},

	members: {
		create: function(evt, pos) {
			var point = this.canvas.getDocument().createPoint(pos);
			this.Widget.prototype.create.call(this, point, evt, true);
			this.unselect();
		},

		draw: function() {
			var p1 = this.shape.getPos();
			this.grPoint = this.gr.drawPoint(p1.x,p1.y);
			if ( !this.bSelected ) this.setTrigger();
		},
		undraw: function() {
			if ( this.grPoint ) {
				this.grPoint.undraw();
				delete this.grPoint;
			}
		},
		setTrigger: function() {
			this.grPoint.setStyle('cursor', 'pointer');
			this.grPoint.setMouseDown(this.onMouseDown.bindEvent(this));
		},
		onUnselect: function() {
			this.Widget.prototype.onUnselect.call(this);
			this.setTrigger();
		}
	}
});

//=============================================================================
// Line Widget
Doodle.Canvas.Line = JSX.Class.create({
	name: 'Line',
	base: Doodle.Canvas.Widget,
	constructor: function(canvas, line) {
		this.Widget.call(this, canvas, line);
	},

	members: {
		create: function(evt, pos) {
			var shape = this.canvas.getDocument().createLine(pos, pos);
			this.Widget.prototype.create.call(this, shape, evt, true);
		},

		draw: function() {
			var p1 = this.shape.getP1();
			var p2 = this.shape.getP2();
			this.grLine = this.gr.drawLine(p1.x,p1.y,p2.x,p2.y);
			if ( !this.bSelected ) this.setTrigger();
		},
		undraw: function() {
			if ( this.grLine ) {
				this.grLine.undraw();
				delete this.grLine;
			}
		},
		setTrigger: function() {
			this.grLine.setStyle('cursor', 'pointer');
			this.grLine.setMouseDown(this.onMouseDown.bindEvent(this));
		},
		onUnselect: function() {
			this.Widget.prototype.onUnselect.call(this);
			this.setTrigger();
		},

		setP1: function(pos) {
			var bDraw = this.grLine != null;
			if ( bDraw ) this.undraw();
			this.shape.setP1(pos);
			if ( bDraw ) this.draw();
		},
		setP2: function(pos) {
			var bDraw = this.grLine != null;
			if ( bDraw ) this.undraw();
			this.shape.setP2(pos);
			if ( bDraw ) this.draw();
		},

		onMouseMove: function(evt, pos) {
			this.setP2(pos);
		},
		onMouseUp: function(evt, pos) {
			this.setP2(pos);
			this.unselect();
		}
	}
});

//=============================================================================
// Ellipse Widget
Doodle.Canvas.Ellipse = JSX.Class.create({
	name: 'Ellipse',
	base: Doodle.Canvas.Widget,
	constructor: function(canvas, ellipse) {
		this.Widget.call(this, canvas, ellipse);
	},

	members: {
		create: function(evt, pos) {
			var shape = this.canvas.getDocument().createEllipse(pos, pos);
			this.Widget.prototype.create.call(this, shape, evt, true);
		},

		draw: function() {
			var p1 = this.shape.getP1();
			var p2 = this.shape.getP2();
			var x = Math.round((p1.x+p2.x)/2);
			var y = Math.round((p1.y+p2.y)/2);
			var rx = Math.round(Math.abs((p1.x-p2.x)/2));
			var ry = Math.round(Math.abs((p1.y-p2.y)/2));
			this.grEllipse = this.gr.drawEllipse(x,y,rx,ry);
			if ( !this.bSelected ) this.setTrigger();
		},
		undraw: function() {
			if ( this.grEllipse ) {
				this.grEllipse.undraw();
				delete this.grEllipse;
			}
		},
		setTrigger: function() {
			this.grEllipse.setStyle('cursor', 'pointer');
			this.grEllipse.setMouseDown(this.onMouseDown.bindEvent(this));
		},
		onUnselect: function() {
			this.Widget.prototype.onUnselect.call(this);
			this.setTrigger();
		},

		setP1: function(pos) {
			var bDraw = this.grEllipse != null;
			if ( bDraw ) this.undraw();
			this.shape.setP1(pos);
			if ( bDraw ) this.draw();
		},
		setP2: function(pos) {
			var bDraw = this.grEllipse != null;
			if ( bDraw ) this.undraw();
			this.shape.setP2(pos);
			if ( bDraw ) this.draw();
		},

		onMouseMove: function(evt, pos) {
			this.setP2(pos);
		},
		onMouseUp: function(evt, pos) {
			this.setP2(pos);
			this.unselect();
		}
	}
});

//=============================================================================
// BezierCurve Widget
Doodle.Canvas.BezierCurve = JSX.Class.create({
	name: 'BezierCurve',
	base: Doodle.Canvas.Widget,
	constructor: function(canvas, curve) {
		this.Widget.call(this, canvas, curve);
	},

	members: {
		create: function(evt, pos) {
			var shape = this.canvas.getDocument().createBezierCurve([pos]);
			this.Widget.prototype.create.call(this, shape, evt, true);
			this.bClick = true;
		},

		draw: function() {
			var points = this.shape.getPoints();
			this.grBezierCurve = this.gr.drawBezierCurve(points);
			if ( !this.bSelected ) this.setTrigger();
		},
		undraw: function() {
			if ( this.grBezierCurve ) {
				this.grBezierCurve.undraw();
				delete this.grBezierCurve;
			}
		},
		setTrigger: function() {
			this.grBezierCurve.setStyle('cursor', 'pointer');
			this.grBezierCurve.setMouseDown(this.onMouseDown.bindEvent(this));
		},
		onUnselect: function() {
			this.Widget.prototype.onUnselect.call(this);
			this.setTrigger();
		},

		onClick: function(evt, pos) {
			if ( this.bClick ) {
				var points = this.shape.getPoints();
				points.push(pos);
			}
			this.bClick = true;
		},

		onMouseMove: function(evt, pos) {
			var bDraw = this.grBezierCurve != null;
			if ( bDraw ) this.undraw();

			var points = this.shape.getPoints();
			if ( this.bClick ) {
				points.push(pos);
				this.bClick = false;
			} else {
				var n = points.length;
				points[n-1] = pos;
			}
			if ( bDraw ) this.draw();
		},
		onDblClick: function(evt, pos) {
			if ( !this.bSelected ) {
				this.Widget.prototype.onDblClick.call(this, evt, pos);
			} else {
				this.unselect();
			}
		}
	}
});


//</script>