//
// Style
//
// Graph
var stylePath = {stroke:"#A9C3C4", "stroke-width": 2, "stroke-linecap":"round"};
var styleCircle = {"r":4, "stroke":"#FFF"}
var styleCircleMouseOver = {"r":"6", "stroke":"#A9C3C4"};

var styleInfoBox = {"fill":"#E9F3F4", "stroke":"#A9C3C4", "fill-opacity": 0.7};
var styleInfoText = {"fill":"#000"};
var stylePathToBox = {stroke:"#EAA", "stroke-width": 1};
var styleAvgLine = {stroke: "#050", "stroke-width": 1, opacity: 0.3};
// Grid
var styleGridText = {"font-size":"10","fill":"black"};
var styleGridAvgText = {"font-size":"10","fill":"#040"};
var styleGridXLine = {"stroke": "#CCC", "stroke-width": 1, "stroke-linecap": "round"};


//--------------------------
// The Statistics Object
//--------------------------
function Statistics(id, type, width, height, xunit, xunitconv, yunit, yunitconv) {
	// Params
	this.id=id;								// id of the container
	this.type=type;							// stats type (graph, pie...)
	this.canvasWidth=width;					// width of container
	this.canvasHeight=height;				// height of container
	this.x=20;								// min x
	this.y=10;								// min y
	this.width=this.canvasWidth-80;	// max width
	this.height=this.canvasHeight-20;	// max height
	this.xUnitConv=xunitconv;
	this.xUnit=xunit;
	this.yUnitConv=yunitconv;
	this.yUnit=yunit;
	
	// Options
	this.showPoints=true;
	this.showPath=true;
	this.showOuterBorder=false;
	this.showInnerBorder=true;
	this.showStandardGrid=false;
	this.show=true;					// visible or hidden
	
	// Data
	this.dataPoint=new Array();
	this.nData=0;					// number of data
	this.xMax=null;
	this.xMin=null;
	this.yMax=null;
	this.yMin=null;
	this.yAvg=0;
	
	this.xScale=1;					// xScale factor
	this.yScale=1;					// yScale fator
	
	this.debug=false;
	this.canvas = Raphael(this.id, this.canvasWidth, this.canvasHeight);
	if (this.showOuterBorder) this.outerBorder = this.canvas.drawGrid(0, 0, this.canvasWidth, this.canvasHeight, 1, 1, "#000");
	if (this.showInnerBorder) this.innerBorder = this.canvas.drawGrid(this.x, this.y, this.width, this.height, 1, 1, "#000");
	this.infoBox = new Info(this);
}


Statistics.prototype.data = function (x_csv, y_csv, d_csv) {
		var xData = x_csv.split(",");
		var yData = y_csv.split(",");
		var dData = d_csv.split(",");
		this.nData = xData.length;

		// write data into dataPoint
		for (var i=0; i < this.nData; i++) {
			this.dataPoint.push(new Point(this,Number(xData[i]),Number(yData[i]), String(dData[i])));
		}
		
		this.calcScale();
		if (this.debug) {
			alert("X-CSV: " + x_csv + "\nY-CSV: " + y_csv + "\nD-CSV: " + d_csv + "\nN-Data: " + this.nData + "\nxScale: " + this.xScale + "\nyScale: " + this.yScale + "\nxMax: " + this.xMax + "\nxMin: " + this.xMin + "\nyMax: " + this.yMax + "\nyMin: " + this.yMin);
		}
	}
	
Statistics.prototype.calcScale =  function() {
		for (var i=0; i < this.nData; i++) {
			if (this.dataPoint[i].x > this.xMax || this.xMax == null) this.xMax = this.dataPoint[i].x;
			if (this.dataPoint[i].x < this.xMin || this.xMin == null) this.xMin = this.dataPoint[i].x;
			
			if (this.dataPoint[i].y > this.yMax || this.yMax == null) this.yMax = this.dataPoint[i].y;
			if (this.dataPoint[i].y < this.yMin || this.yMin == null) this.yMin = this.dataPoint[i].y;
			this.yAvg += this.dataPoint[i].y/this.nData;
		}
		if (this.xMax == this.xMin) {
			this.xMax += this.xMax/10;
			this.xMin -= this.xMin/10;
		}
		if (this.yMax == this.yMin) {
			this.yMax += this.yMax/10;
			this.yMin -= this.yMin/10;
		}
		this.xScale = (this.width)/(this.xMax-this.xMin);
		this.yScale = (this.height)/(this.yMax-this.yMin);
	}

Statistics.prototype.transformX = function (value) {
		var transformedX = (value - this.xMin) * this.xScale + this.x;
		if (this.debug) alert("X: " + value + "\nTransformedX: " + transformedX);	
		return transformedX;
	}
	
Statistics.prototype.transformXUnit = function (value) {
		var result="none";
		
		if (this.xUnit=='date') {
			// convert to UNIX timestamp
			value*=this.xUnitConv;
			// convert to timestamp
			var date = new Date();
			date.setTime(value * 1000);
			result = (date.getMonth()+1) + "/" + date.getFullYear();
		}
		return result;
	}
	
Statistics.prototype.transformY = function (value) {
		var transformedY = (this.height) - ((value - this.yMin) * this.yScale) + this.y;
		if (this.debug) alert("Y: " + value + "\nTransformedY: " + transformedY);	
		return transformedY;
	}
	
Statistics.prototype.transformYUnit = function (value) {
		var result="none";
		// convert  yUnit
		result = Math.round(value*this.yUnitConv);
		// convert to timestamp	
		return result +" "+ this.yUnit;
	}
	
Statistics.prototype.drawGrid = function () {
		if (this.showStandardGrid) this.grid = this.canvas.drawGrid(this.x, this.y, this.width, this.height, this.nData, 1, "#ddd");
		this.gridAvgLine = this.canvas.path(styleAvgLine).moveTo(this.x, this.transformY(this.yAvg)).lineTo(this.width+this.x, this.transformY(this.yAvg));
		this.gridAvgText = this.canvas.text(this.width+this.x+33, this.transformY(this.yAvg)+3, this.transformYUnit(this.yAvg)).attr(styleGridAvgText);
		this.gridYMaxText = this.canvas.text(this.width+this.x+33, this.transformY(this.yMax)+3, this.transformYUnit(this.yMax)).attr(styleGridText);
		this.gridYMinText = this.canvas.text(this.width+this.x+33, this.transformY(this.yMin)+3, this.transformYUnit(this.yMin)).attr(styleGridText);
		this.gridXMaxText = this.canvas.text(this.transformX(this.xMax), this.height+this.y+10, this.transformXUnit(this.xMax)).attr(styleGridText);
		this.gridXMinText = this.canvas.text(this.transformX(this.xMin), this.height+this.y+10, this.transformXUnit(this.xMin)).attr(styleGridText);
		this.gridXText = new Array();
		this.gridXLine = new Array();
		for (var i=1; i < this.nData-1; i++) {
			this.gridXText.push(this.canvas.text(this.transformX(this.dataPoint[i].x), this.height+this.y+10, this.transformXUnit(this.dataPoint[i].x)).attr(styleGridText));
			this.gridXLine.push(this.canvas.path(styleGridXLine).moveTo(this.transformX(this.dataPoint[i].x), this.height+this.y+10).lineTo(this.transformX(this.dataPoint[i].x), this.y));
			this.gridXLine[i-1].toBack();
		}
	}

Statistics.prototype.draw = function () {
		this.drawGrid();
		for (var i=0; i < this.nData; i++) {
			var x1 = this.transformX(this.dataPoint[i].x);
			var y1 = this.transformY(this.dataPoint[i].y);
			
			// draw path
			if (this.showPath) {
				if (i== 0) var path = this.canvas.path(stylePath).moveTo(x1, y1);
				else path.cplineTo(x1,y1,5);
			}
			// draw points
			if (this.showPoints) {
				this.dataPoint[i].setPoint(this.canvas.circle(x1, y1, 4).attr({"fill":"#E00"}).animate(styleCircle, 50));
			}
		}
	}

//
// Point Object
//
function Point(stats, x, y, d) {
	this.S=stats;
	this.x=x;
	this.y=y;
	this.d=d;
	
	this.point=null;
}

Point.prototype.setPoint = function(point) { 
	this.point=point;
	var ref=this;
	point.node.onmouseover = function() {
		ref.point.animate(styleCircleMouseOver, 200);
		ref.S.infoBox.showInfoBox(ref.x, ref.y, ref.d);
		}
		
	point.node.onmouseout = function() {
		ref.point.animate(styleCircle, 50);
		ref.S.infoBox.hideInfoBox();
		} 
	}
	
	
//
// Info-Box Object
//
function Info(stats) {
	this.S = stats;
	this.x=0;
	this.y=0;
	this.xPoint=0;
	this.yPoint=0;
	this.width=60;
	this.height=20;
	this.description="";
	this.canvas = this.S.canvas;
	this.box = this.canvas.rect(0, 0, this.width, this.height, 10).attr(styleInfoBox).hide();
	this.text = this.canvas.text(0,0,"").attr(styleInfoText).hide();
	this.path = this.canvas.path(stylePathToBox).moveTo(0, 0).lineTo(0, 0);
}

Info.prototype.showInfoBox = function(x,y,d) {
	
	this.xPoint = this.S.transformX(x);
	this.yPoint = this.S.transformY(y);
	
	this.x = this.S.transformX(x)+10;
	this.y = this.S.transformY(y)-25;
	
	// check left/right boundaries
	if (this.x-this.width/2 < this.S.x) this.x = this.S.x + this.width/2;
	if (this.x+this.width/2 > this.S.x+this.S.width) this.x = this.S.x + this.S.width - this.width/2;
	// check top boundarie
	if (this.y-this.height/2 < this.S.y) this.y = this.yPoint + this.height/2 + 25;
	
	this.description = d;
	this.width = this.description.length*10;
	this.box.show().animate({"x":this.x-this.width/2, "y":this.y-this.height/2, "width":this.width, "height":this.height}, 0).toFront()
	this.text.show().animate({"x":this.x, "y":this.y+4, "text":d}, 0).toFront();
	
	// update path string
	var pathString = "M " + this.x + " " + this.y + " L " + this.xPoint + " " + this.yPoint;
	this.path.attr({"path":pathString}).show();

}

Info.prototype.hideInfoBox = function() {
	this.box.hide();
	this.text.hide();
	this.path.hide();
}