function ChartData(name,color,data,max) {
	this.name = name;
	this.color = color;
	this.data = data;
	if (!max) this.max = Infinity;
	else this.max = max;
	this.push = function(x) {
		this.data.push(x);
		if (this.data.length > max) this.data.shift();
	}
}
function Chart(w,h,dw,dh,max,gridX,gridY) {
	var self = this;
	var canvas = document.createElement('canvas');
	canvas.width = w;
	canvas.height = h;
	canvas.innerHTML = 'A real browser is needed to see the canvas element.';
	var ctx = canvas.getContext('2d');
	ctx.lineWidth = 1;
	if (!dw) dw = w;
	if (!dh) dh = h;
	var sx = w/dw;
	var sy = h/dh;
	var dataSets = {};
	this.addDataSet = function (name,color,data) {
		dataSets[name] = new ChartData(name,color,data,max);
	};
	this.removeDataSet = function (name) {
		dataSets[name] = null;
	};
	this.getDataSet = function (name) {
		return dataSets[name];
	};
	this.setDataHeight = function (n) {
		dh = n;
		sy = h/dh;
	};
	this.setDataWidth = function (n) {
		dw = n;
		sx = w/dw;
	};
	this.appendTo = function(elm) {
		if (!elm.appendChild) elm = document.getElementById(elm);
		elm.appendChild(canvas);
	};
	this.setTitle = function (title) {
		canvas.title = title;
	};
	this.getCanvas = function () {
		return canvas;
	};
	this.getContext = function () {
		return ctx;
	};
	this.clear = function () {
		ctx.clearRect(0,0,w,h);
	};
	this.drawGrid = function () {
		var i;
	    ctx.strokeStyle = 'silver';
		if (gridY)
			for (i = 0; i < h; i += gridY) {
				ctx.beginPath();
				ctx.moveTo(0,i);
				ctx.lineTo(w,i);
				ctx.stroke();
			}
		if (gridX)
			for (i = 0; i < w; i += gridX) {
				ctx.beginPath();
				ctx.moveTo(i,0);
				ctx.lineTo(i,h);
				ctx.stroke();
			}
	};
	this.drawSquare = function(x,y,w,h,color,border) {
		x = Math.round(x * sx - w/2);
		y = Math.round((dh - y) * sy -h/2);
		if (isNaN(x) || !isFinite(x) || isNaN(y) || !isFinite(y))
			throw 'Chart Error: Invalid data to plot (x='+x+', y='+y+')';
		ctx.fillStyle = color;
		ctx.fillRect(x,y,w,h);
		if (border) {
			ctx.strokeStyle = border;
			ctx.strokeRect(x,y,w,h);			
		}
	}
	this.draw = function () {
		var i, j, x, y, oldX, oldY;
		this.clear();
		this.drawGrid();
		for (i in dataSets) {
		    ctx.strokeStyle = dataSets[i].color;
			ctx.beginPath();
			for (j in dataSets[i].data) {
				x = Math.round(j * sx);
				y = Math.round((dh - dataSets[i].data[j]) * sy);
				if (isNaN(x) || !isFinite(x) || isNaN(y) || !isFinite(y))
					throw 'Chart Error: Invalid data to plot (x='+x+', y='+y+')';
				if (j == 0) ctx.moveTo(x,y);
				else ctx.lineTo(x,y);
			}
			ctx.stroke();
		}
	};
}

