//<script type="text/javascript">

Graphics = JSX.Class.create({
	name: 'Graphics',
	constructor: function(canvas) {
		this.canvas = canvas;
		this.cache = new Array;
		this.shapes = new Object;
		this.nObject = 0;

		// defaults
		this.penColor = "black";
		this.zIndex = 0;
	},
	members: {
		createPlotElement: function(x,y,w,h) {
			// detect canvas
			if ( !this.oCanvas ) {
				if ( this.canvas == undefined ) {
					this.oCanvas = document.body;
				} else if ( typeof(this.canvas) == 'string' ) {
					this.oCanvas = document.getElementById(this.canvas);
				} else {
					this.oCanvas = this.canvas;
				}
			}

			// retrieve DIV
			var oDiv;
			if ( this.cache.length ) {
				oDiv = this.cache.pop();
			} else {
				oDiv = document.createElement('div');
				this.oCanvas.appendChild(oDiv);

				oDiv.style.position = "absolute";
				oDiv.style.margin = "0px";
				oDiv.style.padding = "0px";
				oDiv.style.overflow = "hidden";
				oDiv.style.border = "0px";
			}

			// set attributes
			oDiv.style.zIndex = this.zIndex;
			oDiv.style.backgroundColor = this.penColor;
			
			// reset some other attributes
			oDiv.style.cursor = '';
			oDiv.onmousedown = null;
			oDiv.onmousemove = null;
			oDiv.onmouseup = null;
			
			// set position
			oDiv.style.left = x + 'px';
			oDiv.style.top = y + 'px';
			oDiv.style.width = w + "px";
			oDiv.style.height = h + "px";

			oDiv.style.visibility = "visible";
			
			return oDiv;
		},

		releasePlotElement: function(oDiv) {
			oDiv.style.visibility = "hidden";
			this.cache.push(oDiv);
		},

		addShape: function(shape) {
			shape.oGraphics = this;
			shape.graphicsID = this.nObject;
			this.shapes[this.nObject] = shape;
			this.nObject++;
			shape.draw();
			return shape;
		},

		removeShape: function(shape) {
			if ( (shape instanceof Object) && 
					(shape.oGraphics == this) && 
					(this.shapes[shape.graphicsID] == shape) ) {
				
				shape.undraw();
				delete this.shapes[shape.graphicsID];
				delete shape.oGraphics;
			}
		},
		clear: function() {
			for ( var i in this.shapes ) {
				this.removeShape(this.shapes[i]);
			}
		},

		// draw functions		
		drawPoint: function(x,y) {
			return this.addShape(new Graphics.Point(x,y))
		},
		drawLine: function(x1,y1,x2,y2) {
			return this.addShape(new Graphics.Line(x1,y1,x2,y2))
		},
		drawCircle: function(x,y,r) {
			return this.addShape(new Graphics.Circle(x,y,r))
		},
		fillRectangle: function(x,y,w,h) {
			return this.addShape(new Graphics.FillRectangle(x,y,w,h))
		}
	}
});

//=============================================================================
// Shape - base class to all graphics shapes
Graphics.Shape = JSX.Class.create({
	name: 'Shape',
	constructor: function() {
		this.plots = new Array();
	},
	members: {
		addPlot: function(plot) {
			this.plots.push(plot);
		},

		undraw: function() {
			while ( this.plots.length ) {
				this.oGraphics.releasePlotElement(this.plots.pop());
			}
		},

		setMouseDown: function(onMouseDown) {
			for ( var i = 0; i < this.plots.length; i++ ) {
				this.plots[i].onmousedown = onMouseDown;
			}
		},
		setMouseMove: function(onMouseMove) {
			for ( var i = 0; i < this.plots.length; i++ ) {
				this.plots[i].onmousemove = onMouseMove;
			}
		},
		setMouseUp: function(onMouseUp) {
			for ( var i = 0; i < this.plots.length; i++ ) {
				this.plots[i].onmouseup = onMouseUp;
			}
		},
		setStyle: function(style, value) {
			for ( var i = 0; i < this.plots.length; i++ ) {
				this.plots[i].style[style] = value;
			}
		}
	}
});


//=============================================================================
// Point
Graphics.Point = JSX.Class.create({
	name: 'Point',
	constructor: function(x,y) {
		this.Shape.call(this);

		this.x = x;
		this.y = y;
	},
	members: {
		draw: function() {
			this.addPlot(this.oGraphics.createPlotElement(this.x,this.y,1,1));
		}
	}
});

//=============================================================================
// Line
Graphics.Line = JSX.Class.create({
	name: 'Line',
	constructor: function(x1,y1,x2,y2) {
		this.Shape.call(this);

		this.x1 = x1;
		this.y1 = y1;
		this.x2 = x2;
		this.y2 = y2;
	},
	base: Graphics.Shape,
	members: {
		draw: function() {
			var dx = this.x2 - this.x1;
			var dy = this.y2 - this.y1;
			var x = this.x1;
			var y = this.y1;

			var n = Math.max(Math.abs(dx),Math.abs(dy));
			dx = dx / n;
			dy = dy / n;
			for ( i = 0; i <= n; i++ ) {
				this.addPlot(this.oGraphics.createPlotElement(Math.round(x),Math.round(y),1,1));

				x += dx;
				y += dy;
			}
		}
	}
});

//=============================================================================
// Circle
Graphics.Circle = JSX.Class.create({
	name: 'Circle',
	constructor: function(x,y,r) {
		this.Shape.call(this);

		this.x = x;
		this.y = y;
		this.radius = r;
	},
	members: {
		draw: function() {
			var r2 = this.radius * this.radius;
			var x = 0;
			var y = this.radius;

			while ( x <= y ) {
				this.addPlot(this.oGraphics.createPlotElement(Math.round(this.x + x), Math.round(this.y + y), 1, 1));
				this.addPlot(this.oGraphics.createPlotElement(Math.round(this.x - x), Math.round(this.y + y), 1, 1));
				this.addPlot(this.oGraphics.createPlotElement(Math.round(this.x + x), Math.round(this.y - y), 1, 1));
				this.addPlot(this.oGraphics.createPlotElement(Math.round(this.x - x), Math.round(this.y - y), 1, 1));
				this.addPlot(this.oGraphics.createPlotElement(Math.round(this.x + y), Math.round(this.y + x), 1, 1));
				this.addPlot(this.oGraphics.createPlotElement(Math.round(this.x + y), Math.round(this.y - x), 1, 1));
				this.addPlot(this.oGraphics.createPlotElement(Math.round(this.x - y), Math.round(this.y + x), 1, 1));
				this.addPlot(this.oGraphics.createPlotElement(Math.round(this.x - y), Math.round(this.y - x), 1, 1));

				x++;
				y = Math.round(Math.sqrt(r2 - x*x));
			}
		}
	}
});

//=============================================================================
// FillRectangle
Graphics.FillRectangle = JSX.Class.create({
	name: 'FillRectangle',
	constructor: function(x,y,w,h) {
		this.Shape.call(this);

		this.x = x;
		this.y = y;
		this.w = w;
		this.h = h;
	},
	members: {
		draw: function() {
			this.addPlot(this.oGraphics.createPlotElement(this.x,this.y,this.w,this.h));
		}
	}
});


//</script>
