/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.widget.Chart");

dojo.require("dojo.widget.*");
dojo.require("dojo.gfx.color");
dojo.require("dojo.gfx.color.hsl");

dojo.declare(
	"dojo.widget.Chart",
	null,
	function(){
		// summary: Base class for svg and vml implementations of Chart
		this.series = [];
	},
{
	isContainer: false,

	assignColors: function(){
		//	summary
		//	Assigns/generates a color for a data series.
		var hue=30;
		var sat=120;
		var lum=120;
		var steps = Math.round(330/this.series.length);

		for(var i=0; i<this.series.length; i++){
			var c=dojo.gfx.color.hsl2rgb(hue,sat,lum);
			if(!this.series[i].color){
				this.series[i].color = dojo.gfx.color.rgb2hex(c[0],c[1],c[2]);
			}
			hue += steps;
		}
	},
	parseData: function(table){
		var thead=table.getElementsByTagName("thead")[0];
		var tbody=table.getElementsByTagName("tbody")[0];
		if(!(thead&&tbody)) dojo.raise("dojo.widget.Chart: supplied table must define a head and a body.");

		//	set up the series.
		var columns=thead.getElementsByTagName("tr")[0].getElementsByTagName("th");	//	should be <tr><..>

		//	assume column 0 == X
		for (var i=1; i<columns.length; i++){
			var key="column"+i;
			var label=columns[i].innerHTML;
			var plotType=columns[i].getAttribute("plotType")||"line";
			var color=columns[i].getAttribute("color");
			var ds=new dojo.widget.Chart.DataSeries(key,label,plotType,color);
			this.series.push(ds);
		}

		//	ok, get the values.
		var rows=tbody.rows;
		var xMin=Number.MAX_VALUE,xMax=Number.MIN_VALUE;
		var yMin=Number.MAX_VALUE,yMax=Number.MIN_VALUE;
		var ignore = [
			"accesskey","align","bgcolor","class",
			"colspan","height","id","nowrap",
			"rowspan","style","tabindex","title",
			"valign","width"
		];

		for(var i=0; i<rows.length; i++){
			var row=rows[i];
			var cells=row.cells;
			var x=Number.MIN_VALUE;
			for (var j=0; j<cells.length; j++){
				if (j==0){
					x=parseFloat(cells[j].innerHTML);
					xMin=Math.min(xMin, x);
					xMax=Math.max(xMax, x);
				} else {
					var ds=this.series[j-1];
					var y=parseFloat(cells[j].innerHTML);
					yMin=Math.min(yMin,y);
					yMax=Math.max(yMax,y);
					var o={x:x, value:y};
					var attrs=cells[j].attributes;
					for(var k=0; k<attrs.length; k++){
						var attr=attrs.item(k);
						var bIgnore=false;
						for (var l=0; l<ignore.length; l++){
							if (attr.nodeName.toLowerCase()==ignore[l]){
								bIgnore=true;
								break;
							}
						}
						if(!bIgnore) o[attr.nodeName]=attr.nodeValue;
					}
					ds.add(o);
				}
			}
		}
		return { x:{ min:xMin, max:xMax}, y:{ min:yMin, max:yMax} };
	}
});

dojo.declare(
	"dojo.widget.Chart.DataSeries",
	null,
	function(key, label, plotType, color){
		//	summary:
		//		Every chart has a set of data series; this is the series.  Note that each
		//		member of value is an object and in the minimum has 2 properties: .x and
		//		.value.
		//
		this.id = "DataSeries"+dojo.widget.Chart.DataSeries.count++;
		this.key = key;
		this.label = label||this.id;
		this.plotType = plotType||"line";	//	let line be the default.
		this.color = color;
		this.values = [];
	},
{
	add: function(v){
		if(v.x==null||v.value==null){
			dojo.raise("dojo.widget.Chart.DataSeries.add: v must have both an 'x' and 'value' property.");
		}
		this.values.push(v);
	},

	clear: function(){
		this.values=[];
	},

	createRange: function(len){
		var idx = this.values.length-1;
		var length = (len||this.values.length);
		return { "index": idx, "length": length, "start":Math.max(idx-length,0) };
	},

	//	trend values
	getMean: function(len){
		var range = this.createRange(len);
		if(range.index<0){ return 0; }
		var t = 0;
		var c = 0;
		for(var i=range.index; i>=range.start; i--){
			var n = parseFloat(this.values[i].value);
			if(!isNaN(n)){ t += n; c++; }
		}
		t /= Math.max(c,1);
		return t;
	},

	getMovingAverage: function(len){
		var range = this.createRange(len);
		if(range.index<0){ return 0; }
		var t = 0;
		var c = 0;
		for(var i=range.index; i>=range.start; i--){
			var n = parseFloat(this.values[i].value);
			if(!isNaN(n)){ t += n; c++; }
		}
		t /= Math.max(c,1);
		return t;
	},

	getVariance: function(len){
		var range = this.createRange(len);
		if(range.index < 0){ return 0; }
		var t = 0; // FIXME: for tom: wtf are t, c, and s?
		var s = 0;
		var c = 0;
		for(var i=range.index; i>=range.start; i--){
			var n = parseFloat(this.values[i].value);
			if(!isNaN(n)){
				t += n;
				s += Math.pow(n,2);
				c++;
			}
		}
		return (s/c)-Math.pow(t/c,2);
	},

	getStandardDeviation: function(len){
		return Math.sqrt(this.getVariance(len));
	},

	getMax: function(len){
		var range = this.createRange(len);
		if(range.index < 0){ return 0; }
		var t = 0;
		for (var i=range.index; i>=range.start; i--){
			var n=parseFloat(this.values[i].value);
			if (!isNaN(n)){
				t=Math.max(n,t);
			}
		}
		return t;
	},

	getMin: function(len){
		var range=this.createRange(len);
		if(range.index < 0){ return 0; }
		var t = 0;
		for(var i=range.index; i>=range.start; i--){
			var n = parseFloat(this.values[i].value);
			if(!isNaN(n)){
				t=Math.min(n,t);
			}
		}
		return t;
	},

	getMedian: function(len){
		var range = this.createRange(len);

		if(range.index<0){ return 0; }

		var a = [];
		for (var i=range.index; i>=range.start; i--){
			var n=parseFloat(this.values[i].value);
			if (!isNaN(n)){
				var b=false;
				for(var j=0; j<a.length&&!b; j++){
					if (n==a[j]) b=true;
				}
				if(!b){ a.push(n); }
			}
		}
		a.sort();
		if(a.length>0){ return a[Math.ceil(a.length/2)]; }
		return 0;
	},

	getMode: function(len){
		var range=this.createRange(len);
		if(range.index<0){ return 0; }
		var o = {};
		var ret = 0
		var m = 0;
		for(var i=range.index; i>=range.start; i--){
			var n=parseFloat(this.values[i].value);
			if(!isNaN(n)){
				if (!o[this.values[i].value]) o[this.values[i].value] = 1;
				else o[this.values[i].value]++;
			}
		}
		for(var p in o){
			if(m<o[p]){ m=o[p]; ret=p; }
		}
		return parseFloat(ret);
	}
});

dojo["requireIf"](dojo.render.svg.capable, "dojo.widget.svg.Chart");
dojo["requireIf"](!dojo.render.svg.capable && dojo.render.vml.capable, "dojo.widget.vml.Chart");
