
// restorable_context.js
// a 2d drawing context wrapper that keeps it state
// copyright xThink 2007
// This code is the property of xThink.




var RestorableContext = Class.create();

RestorableContext.prototype = {
	
	initialize: function(canvasEl) {
		this.delegateCanvas = canvasEl;
		this.delegateCtx = canvasEl.getContext("2d");
		this.delegateCtx.scale(1, 1);
		this.scaleX = 1;
		this.scaleY = 1;
		this.initCoords();
		this.clear();
	},
	
	initCoords: function() {
		this.canvasOffsets = Position.cumulativeOffset($('calc'));
		this.canvasDimensions = this.delegateCanvas.getDimensions();
	},
	
	clear: function() {
		this.erase();
		this.strokes = new Array();
		this.lastpos = {x:-1, y:-1};
	},
	
	erase: function() {
		this.delegateCtx.clearRect(0, 0, this.canvasDimensions.width * 1/this.scaleX, this.canvasDimensions.height * 1/this.scaleY);
	},
	
	singlePointStroke: function(x, y) {
		this.delegateCtx.fillRect(x - 2, y - 2, 4, 4);
	},
	
	openStrokeSequence: function(pos, color) {
		this.currentPositions = new Array();
		this.firstPoint = true;
		this.color = color;
		this.record_pos(pos);
	},
	
	addStroke: function(pos) {
		this.firstPoint = false;
		this.delegateCtx.beginPath();
		this.delegateCtx.moveTo(this.lastpos.x, this.lastpos.y);
		this.delegateCtx.lineTo(pos.x, pos.y);
		this.delegateCtx.stroke();
		this.record_pos(pos);
	},

	closeStrokeSequence: function() {
		if (this.firstPoint) {
			/* single point stroke: paint a dot */
			this.singlePointStroke(this.lastpos.x, this.lastpos.y);
		}
		// save the strokes into the strokes array
		var strokeObj = new Object();
		strokeObj.positions = this.currentPositions;
		strokeObj.color = this.color;
		this.strokes[this.strokes.length] = strokeObj;
		
	},
	
	removeLastStrokeSequence: function() {
		if (this.strokes.length > 0) {
			this.strokes.length--;
			this.redraw();
		}
	},
	
	record_pos: function(pos) {
		this.lastpos = pos;
		this.currentPositions[this.currentPositions.length] = pos;
	},
	
	redraw: function() {
		this.erase();
		for (var i = 0; i < this.strokes.length; i++) {
			this.delegateCtx.strokeStyle = this.strokes[i].color;
			this.delegateCtx.fillStyle = this.strokes[i].color;
			var positions = this.strokes[i].positions;
			if (positions.length == 1) {
				this.singlePointStroke(positions[0].x, positions[0].y);
			} else {
				for (var j = 1; j < positions.length; j++) {
					this.delegateCtx.beginPath();
					this.delegateCtx.moveTo(positions[j-1].x, positions[j-1].y);
					this.delegateCtx.lineTo(positions[j].x, positions[j].y);
					this.delegateCtx.stroke();
				}
			}
  	}
  },

	copyFrom: function(restorablectx) {
		this.strokes = new Array();
		for (var i = 0; i < restorablectx.strokes.length; i++) {
			this.strokes[i] = new Object();
			this.strokes[i].positions = restorablectx.strokes[i].positions.clone();
			this.strokes[i].color = restorablectx.strokes[i].color;
		}
		this.redraw();
	},

  createRecognizerInput: function() {
		var s = "";
		for (var i = 0; i < this.strokes.length; i++) {
			if (this.strokes[i].color == '#000') {
				if (s != "") {
					s += ':';
		  	}
				for (var j = 0; j < this.strokes[i].positions.length; j++) {
					s += this.strokes[i].positions[j].x * 10 + "," + this.strokes[i].positions[j].y * 10;
					if (j < this.strokes[i].positions.length - 1) {
						s += ';';
					}
				}
			}
  	}
  	return s;
  },


	/**
	 * Properties of the delegate exposed as setters.
	 */
	
	setStrokeStyle: function(strokeStyle) {
		this.delegateCtx.strokeStyle = strokeStyle;
	},
	
	setFillStyle: function(fillStyle) {
		this.delegateCtx.fillStyle = fillStyle;
	},
	
	setLineWidth: function(lineWidth) {
		this.delegateCtx.lineWidth = lineWidth;
	},
	
	setLineJoin: function(lineJoin) {
		this.delegateCtx.lineJoin = lineJoin;
	},
	
	setScale: function(scaleX, scaleY) {
		this.resetScale();
		this.scaleX = scaleX;
		this.scaleY = scaleY;
		this.delegateCanvas.getContext("2d").scale(scaleX, scaleY);
	},
	
	resetScale: function() {
		this.delegateCtx.scale(1/this.scaleX, 1/this.scaleY);
		this.scaleX = 1;
		this.scaleY = 1;
	}

}
