function mean(params) {
	var datasetNr = params.datasetNr;
	var data = params.data;
	var mean = 0;
	var nr = 0;
	for (var j = 0; j < data.datasets[datasetNr].data.length; j++) {
		// important to check because missing values are possible
		if (!(typeof(data.datasets[datasetNr].data[j])=='undefined')){
			mean += 1*data.datasets[datasetNr].data[j];
			nr++;
		}
	}
	mean /= nr;
	return mean;
}

function varianz(params) {
	var data = params.data;
	var datasetNr = params.datasetNr;
	var meanVal = mean(params);
	var varianz = 0;
	var nr = 0;
	for (var j = 0; j < data.datasets[datasetNr].data.length; j++) {
		// important to check because missing values are possible
		if (!(typeof(data.datasets[datasetNr].data[j])=='undefined')) {
			varianz += Math.pow(1*data.datasets[datasetNr].data[j]-meanVal,2);
			nr++;
		}
	}
	return varianz/nr;
}

function stddev(params) {
	return Math.sqrt(varianz(params));
}

function cv(params) {
	return stddev(params)/mean(params);
}



function drawMath(ctx,config,data,msr,vars) {
	var xAxisPosY = vars.xAxisPosY;
	var yAxisPosX = vars.yAxisPosX;
	var valueHop  = vars.valueHop;
	var scaleHop  = vars.scaleHop;
	var zeroY     = vars.zeroY;
	var calculatedScale = vars.calculatedScale;
	var calculateOffset = vars.calculateOffset;
	var barWidth = vars.barWidth;
	var barBool = !(typeof barWidth == "undefined") ? true : false;

	// check each dataset if a mathDraw function exists
	for (var i = 0; i < data.datasets.length; i++) {
		// get mathFctName (stddev|mean|...)
		var deviationFct = data.datasets[i].drawMathDeviation;
		if (deviationFct) {
			drawMathDeviation(i,deviationFct);
		}
		var lineFct = data.datasets[i].drawMathLine;
		if (lineFct) {
			drawMathLine(i,lineFct);
		}
	}

	/**
	 * Draw a deviation vertical line (if needed with top and bottom horizontal lines)
	 * @param i {integer} dataset number
	 * @param deviationFct {string} math function name
	 */
	function drawMathDeviation(i,deviationFct) {
		var deviation = 0;
		// check if the math function exists
		if (typeof eval(deviationFct) == "function") {
			var parameter = {data:data,datasetNr: i};
			deviation = window[deviationFct](parameter);
		 }
		if (isNumber(deviation)) {
			ctx.strokeStyle= data.datasets[i].deviationStrokeColor ? data.datasets[i].deviationStrokeColor : config.defaultStrokeColor;
			ctx.lineWidth = config.datasetStrokeWidth;
			ctx.beginPath();
			for (var j = 0; j < data.datasets[i].data.length; j++) {
				// important to check because missing values are possible
				if (!(typeof(data.datasets[i].data[j])=='undefined')) {
					var deviationWidth = data.datasets[i].deviationWidth;
					// draw the top and the bottom of the vertical line if a deviationWidth exists
					if (deviationWidth) {
						ctx.moveTo(xPos(j,i,barWidth,barBool)-deviationWidth,yPos(i,j,-deviation,true));
						ctx.lineTo(xPos(j,i,barWidth,barBool)+deviationWidth,yPos(i,j,-deviation,true));
						ctx.moveTo(xPos(j,i,barWidth,barBool)-deviationWidth,yPos(i,j,deviation,true));
						ctx.lineTo(xPos(j,i,barWidth,barBool)+deviationWidth,yPos(i,j,deviation,true));
					}
					// draw the vertical line
					ctx.moveTo(xPos(j,i,barWidth,barBool),yPos(i,j,-deviation,true));
					ctx.lineTo(xPos(j,i,barWidth,barBool),yPos(i,j,deviation,true));
				}
			}
			ctx.stroke();
			ctx.closePath();
		}
	}

	/**
	 * Draw a horizontal line
	 * @param i {integer} numer of dataset
	 * @param lineFct {string} name of the mathfunctions => compute height
	 */
	function drawMathLine(i,lineFct) {
		var line = 0;
		// check if the math function exists
		if (typeof eval(lineFct) == "function") {
			var parameter = {data:data,datasetNr: i};
			line = window[lineFct](parameter);
		 }
		if (!(typeof(line)=='undefined')) {
			ctx.strokeStyle= data.datasets[i].mathLineStrokeColor ? data.datasets[i].mathLineStrokeColor : config.defaultStrokeColor;
			ctx.lineWidth = config.datasetStrokeWidth;
			ctx.beginPath();
			ctx.moveTo(yAxisPosX,yPos(i,0,line,false));
			ctx.lineTo(yAxisPosX + msr.availableWidth,yPos(i,data.datasets[i].data.length-1,line,false));
			ctx.stroke();
			ctx.closePath();
		}
	}

	/**
	 * Get a y position depending on the current values
	 * @param dataset {integer} number of dataset
	 * @param iteration {integer} number of value inside dataset.data
	 * @param add {float} add a value to the current value if value is true
	 * @param value {bool} true => value+add, false=>add
	 * @returns {float} position (px)
	 */
	function yPos(dataSet, iteration, add,value) {
		value = value ? 1*data.datasets[dataSet].data[iteration] : 0;
		return xAxisPosY - calculateOffset(config, value+add, calculatedScale, scaleHop);
	};
	function xPos(iteration,dataSet,barWidth,bar) {
		if (bar) {
			return yAxisPosX + config.barValueSpacing + valueHop * iteration + barWidth * dataSet
			       + config.barDatasetSpacing * dataSet + config.barStrokeWidth * dataSet+barWidth/2;
		} else {
		   return yAxisPosX + (valueHop * iteration);
		}

	};
}
