dojo.provide("dojox.charting.plot2d.Pie");

dojo.require("dojox.charting.Element");
dojo.require("dojox.charting.axis2d.common");
dojo.require("dojox.charting.plot2d.common");

dojo.require("dojox.lang.functional");
dojo.require("dojox.gfx");

(function(){
	var df = dojox.lang.functional, du = dojox.lang.utils,
		dc = dojox.charting.plot2d.common,
		da = dojox.charting.axis2d.common,
		g = dojox.gfx,
		labelFudgeFactor = 0.8;		// in percents (to convert font's heigth to label width)

	dojo.declare("dojox.charting.plot2d.Pie", dojox.charting.Element, {
		defaultParams: {
			labels:			true,
			ticks:			false,
			fixed:			true,
			precision:		1,
			labelOffset:	20,
			labelStyle:		"default",	// default/rows/auto
			htmlLabels:		true		// use HTML to draw labels
		},
		optionalParams: {
			font:		"",
			fontColor:	"",
			radius:		0
		},
		
		constructor: function(chart, kwArgs){
			this.opt = dojo.clone(this.defaultParams);
			du.updateWithObject(this.opt, kwArgs);
			du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
			this.run = null;
		},
		clear: function(){
			this.dirty = true;
			return this;
		},
		setAxis: function(axis){
			// nothing
			return this;
		},
		addSeries: function(run){
			this.run = run;
			return this;
		},
		calculateAxes: function(dim){
			// nothing
			return this;
		},
		getRequiredColors: function(){
			return this.run ? this.run.data.length : 0;
		},
		render: function(dim, offsets){
			if(!this.dirty){ return this; }
			this.dirty = false;
			this.cleanGroup();
			var s = this.group, color, t = this.chart.theme;

			// calculate the geometry
			var rx = (dim.width  - offsets.l - offsets.r) / 2,
				ry = (dim.height - offsets.t - offsets.b) / 2,
				r  = Math.min(rx, ry),
				taFont = "font" in this.opt ? this.opt.font : t.axis.font,
				taFontColor = "fontColor" in this.opt ? this.opt.fontColor : t.axis.fontColor,
				sum = df.foldl1(this.run.data, "+"), start = 0, step,
				slices = dojo.map(this.run.data, function(x){ return x / sum; }),
				shift, size, labelR;
			if(this.opt.labels){
				var labels = dojo.map(slices, function(x){
					return this._getLabel(x * 100) + "%";
				}, this);
				shift = df.foldl1(dojo.map(labels, df.pluck("length")), "x, y -> Math.max(x, y)");
				size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0;
				shift = Math.max(shift * labelFudgeFactor, 1) / 2 * size;
				if(this.opt.labelOffset < 0){
					r = Math.min(rx - 2 * shift, ry - size) + this.opt.labelOffset;
				}
				labelR = r - this.opt.labelOffset;
			}
			if("radius" in this.opt){
				r = this.opt.radius;
				labelR = r - this.opt.labelOffset;
			}
			var	circle = {
					cx: offsets.l + rx,
					cy: offsets.t + ry,
					r:  r
				};
			
			if(!this.run || !this.run.data.length){
				return this;
			}else if(this.run.data.length == 1){
				// need autogenerated color
				color = new dojo.Color(t.next("color"));
				s.createCircle(circle).
					setFill(dc.augmentFill(t.run.fill, color)).
					setStroke(dc.augmentStroke(t.series.stroke, color));
				if(this.opt.labels){
					var shift = 4,
						taFont = "font" in this.opt ? this.opt.font : t.axis.font,
						taFontColor = "fontColor" in this.opt ? this.opt.fontColor : t.axis.fontColor,
						size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0;
					shift = Math.max(shift * labelFudgeFactor, 1) / 2 * size;
					// draw the label
					var elem = da.createText[this.opt.htmlLabels ? "html" : "gfx"]
									(this.chart, s, circle.cx, circle.cy + size / 2, "middle",
										"100%", taFont, taFontColor);
					if(this.opt.htmlLabels){ this.htmlElements.push(elem); }
					/*
					s.createText({x: circle.cx, y: circle.cy + size / 2, align: "middle", text: "100%"}).
						setFont(taFont).setFill(taFontColor);
					*/
				}
				return this;
			}
			// draw slices
			dojo.forEach(slices, function(x, i){
				// calculate the geometry of the slice
				var end = start + x * 2 * Math.PI;
				if(i + 1 == slices.length){
					end = 2 * Math.PI;
				}
				var	step = end - start,
					x1 = circle.cx + r * Math.cos(start),
					y1 = circle.cy + r * Math.sin(start),
					x2 = circle.cx + r * Math.cos(end),
					y2 = circle.cy + r * Math.sin(end);
				// draw the slice
				color = new dojo.Color(t.next("color"));
				s.createPath({}).
					moveTo(circle.cx, circle.cy).
					lineTo(x1, y1).
					arcTo(r, r, 0, step > Math.PI, true, x2, y2).
					lineTo(circle.cx, circle.cy).
					closePath().
					setFill(dc.augmentFill(t.series.fill, color)).
					setStroke(dc.augmentStroke(t.series.stroke, color));
				start = end;
			});
			// draw labels
			if(this.opt.labels){
				start = 0;
				dojo.forEach(slices, function(x, i){
					// calculate the geometry of the slice
					var end = start + x * 2 * Math.PI;
					if(i + 1 == slices.length){
						end = 2 * Math.PI;
					}
					var	labelAngle = (start + end) / 2,
						x = circle.cx + labelR * Math.cos(labelAngle),
						y = circle.cy + labelR * Math.sin(labelAngle) + size / 2;
					// draw the label
					var elem = da.createText[this.opt.htmlLabels ? "html" : "gfx"]
									(this.chart, s, x, y, "middle",
										labels[i], taFont, taFontColor);
					if(this.opt.htmlLabels){ this.htmlElements.push(elem); }
					/*
					s.createText({x: x, y: y, align: "middle", text: labels[i]}).
						setFont(taFont).setFill(taFontColor);
					*/
					start = end;
				}, this);
			}
			return this;
		},
		
		// utilities
		_getLabel: function(number){
			return this.opt.fixed ? number.toFixed(this.opt.precision) : number.toString();
		}
	});
})();
