/*!
 * jQuery Directory @VERSION
 *
 * Copyright (c) 2011 excentrics.ru
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * Authors: Yarovoy Artem (yarovoy at excentrics dot ru), Maydakov Mikhail (mix at excentrics dot ru)
 *
 * http://www.excentrics.ru
 */

(jQuery.RDiagram || (function($){

	var methods = {
		/* 
		 * Function to initialize diagram
		 *
		 * */	
		init: function(options){
	  
			var settings = $.extend({
					'animate': true,
					'drawObjID': 'paper',
					'drawObjWidth': 680,
					'drawObjHeight': 500,
					'legendSelector': ".legend",
					'titleSelector': ".title",
					'arcSelector': ".arc",
					'tipsSelector': ".tip",
					'totalRange': 28,
					'maxRadius': 210,
					'startTipRadius': 20,
					'startArcRadius': 70,
					'arcDelta': 3,
					'fontSize' : 16,
					'fontColor' : "#f5f5f5",
					'bgColor': "#000",
					'scaleAngles': [0, 90, 180, 270],
					'scaleText': "МБит/с",
					'arc': {'fontSize': 15},
					'tips' : {'fontSize': 12,
							  'moreFontSize': 11,
							  'circleColor1': "#A9A9A9",
							  'circleColor2': "#f5f5f5",
							  'fontColor': "#AAAAAA",
							  'moreFontColor': "#888888"},
							  
					'title' : {	'fontSize' : 27,
								'fontColor':  "#84d1e1",
								'moreFontSize' : 13}
				}, options),
				rDiagram = Raphael( settings.drawObjID, settings.drawObjWidth, settings.drawObjHeight),
				$this = $(this),
				data = $this.data('diagram');
			
			settings.x0 = settings.x0 ? settings.x0 : settings.drawObjWidth/2;
			settings.y0 = settings.y0 ? settings.y0 : settings.drawObjHeight/2;
			
			settings.scale = settings.scale ? settings.scale : {};
			settings.scale.fontSize = settings.scale.fontSize ? settings.scale.fontSize : settings.fontSize; 
			settings.scale.fontColor = settings.scale.fontColor ? settings.scale.fontColor : settings.fontColor;
			settings.scale.graduationColor = settings.scale.graduationColor ? settings.scale.graduationColor : settings.scale.fontColor;
			settings.scale.graduationSize = settings.scale.graduationSize ? settings.scale.graduationSize : 7;
			settings.scale.textIndent = settings.scale.textIndent ? settings.scale.textIndent: 10;
			settings.scale.strokeWidth = settings.scale.strokeWidth ? settings.scale.strokeWidth : 1;
			settings.scale.drawGraduations = settings.scale.drawGraduations ? settings.scale.drawGraduations : false;
			settings.scale.angles = settings.scaleAngles;
			settings.scale.text = settings.scaleText;
			settings.scale.fontFamily = settings.scale.fontFamily ? settings.scale.fontFamily : "tahoma";
			settings.scale.fontWeight =  settings.scale.fontWeight ? settings.scale.fontWeight : "bold";
			
			settings.tips = settings.tips ? settings.tips : {};
			settings.tips.count = $(settings.legendSelector).children(settings.tipsSelector).length;
			settings.tips.startRadius = settings.startTipRadius;
			settings.tips.currentRadius = settings.startTipRadius;
			settings.tips.endRadius = settings.startArcRadius;
			settings.tips.width = settings.tips.width ? settings.tips.width : 1;
			settings.tips.circleSize1 = settings.tips.circleSize1 ? settings.tips.circleSize1 : 2;
			settings.tips.circleSize2 = settings.tips.circleSize2 ? settings.tips.circleSize2 : 2;
			settings.tips.textIndent = settings.tips.textIndent ? settings.tips.textIndent: 7; 
			settings.tips.fontSize = settings.tips.fontSize ? settings.tips.fontSize : settings.fontSize;
			settings.tips.fontFamily = settings.tips.fontFamily ? settings.tips.fontFamily : "tahoma";
			settings.tips.fontWeight =  settings.tips.fontWeight ? settings.tips.fontWeight : "normal";
			settings.tips.fontColor = settings.tips.fontColor ? settings.tips.fontColor : settings.fontColor;
			settings.tips.moreFontSize = settings.tips.moreFontSize ? settings.tips.moreFontSize : settings.fontSize;
			settings.tips.moreFontColor = settings.tips.moreFontColor ? settings.tips.moreFontColor : settings.fontColor;
			settings.tips.moreFontFamily = settings.tips.moreFontFamily ? settings.tips.moreFontFamily : "tahoma";
			settings.tips.moreFontWeight =  settings.tips.moreFontWeight ? settings.tips.moreFontWeight : "normal";
			settings.tips.circleColor1 = settings.tips.circleColor1 ? settings.tips.circleColor1 : undefined;
			settings.tips.circleColor2 = settings.tips.circleColor2 ? settings.tips.circleColor2 : undefined;
			settings.tips.delta = settings.tips.delta ? settings.tips.delta : 
				(settings.tips.endRadius - settings.tips.startRadius 
						- settings.tips.count * settings.tips.width) / (settings.tips.count - 1);

			settings.arc = settings.arc ? settings.arc : {};
			settings.arc.count = $(settings.legendSelector).children(settings.arcSelector).length;
			settings.arc.maxRadius = settings.maxRadius;
			settings.arc.delta = settings.arcDelta;
			settings.arc.strokeWidth =  settings.arc.strokeWidth ? settings.arc.strokeWidth : (settings.arc.maxRadius - settings.startArcRadius 
					- (settings.arc.count + 1 ) * settings.arc.delta) / settings.arc.count;
			settings.arc.startRadius = settings.startArcRadius + settings.arc.delta + settings.arc.strokeWidth / 2;
			settings.arc.currentRadius = settings.arc.startRadius;
			settings.arc.fontSize = settings.arc.fontSize ? settings.arc.fontSize : settings.fontSize;
			settings.arc.fontFamily = settings.arc.fontFamily ? settings.arc.fontFamily : "tahoma";
			settings.arc.fontWeight =  settings.arc.fontWeight ? settings.arc.fontWeight : "normal";
			settings.arc.fontColor = settings.arc.fontColor ? settings.arc.fontColor : settings.fontColor;
			settings.arc.textIndent = settings.arc.textIndent ? settings.arc.textIndent: 7;
			settings.arc.moreFontSize = settings.arc.moreFontSize ? settings.arc.moreFontSize : settings.fontSize;
			settings.arc.moreFontFamily = settings.arc.moreFontFamily ? settings.arc.moreFontFamily : "tahoma";
			settings.arc.moreFontWeight =  settings.arc.moreFontWeight ? settings.arc.moreFontWeight : "normal";
			settings.arc.roundConner = settings.arc.roundConner ? settings.arc.roundConner : true;
			settings.arc.roundPx = settings.arc.roundPx ? settings.arc.roundPx: 5;
			settings.arc.cursor = settings.arc.cursor ? settings.arc.cursor: 'pointer';
			
			settings.title = settings.title ? settings.title : {};
			settings.title.fontSize = settings.title.fontSize ? settings.title.fontSize : settings.fontSize;
			settings.title.fontFamily = settings.title.fontFamily ? settings.title.fontFamily : "tahoma";
			settings.title.fontWeight =  settings.title.fontWeight ? settings.title.fontWeight : "normal";
			settings.title.fontColor = settings.title.fontColor ? settings.title.fontColor : settings.fontColor;
			settings.title.moreFontSize = settings.title.moreFontSize ? settings.title.moreFontSize : settings.fontSize;
			settings.title.moreFontColor = settings.title.moreFontColor ? settings.title.moreFontColor : settings.fontColor;
			settings.title.moreFontFamily = settings.title.moreFontFamily ? settings.title.moreFontFamily : "tahoma";
			settings.title.moreFontWeight =  settings.title.moreFontWeight ? settings.title.moreFontWeight : "normal";
			settings.title.x =  settings.title.x ? settings.title.x : 30;
			settings.title.y =  settings.title.y ? settings.title.y : 58;
			settings.title.textAnchor =  settings.title.textAnchor ? settings.title.textAnchor : "start";
			settings.title.textIndent = settings.title.textIndent ? settings.title.textIndent: 10;
			settings.title.titlelink = settings.title.titlelink ? settings.title.titlelink: "";
			
			settings.animation = settings.animation ? settings.animation : {};
			settings.animation.speed = settings.animation.speed ? settings.animation.speed: 1000;
			settings.animation.opacity = settings.animation.opacity ? settings.animation.opacity: 0.9;
			settings.animation.easing = settings.animation.easing ? settings.animation.easing: "elastic";
			settings.animation.widthKoef = settings.animation.widthKoef ? settings.animation.widthKoef: 1.5;
			// If the plugin hasn't been initialized yet
			if (!data) {
				data = {
					settings: settings,
					rDiagram: rDiagram
				}
										
				$this.data('diagram', data);
			}

			/// Drawing
			methods.drawArc.apply($(this), arguments);
			methods.drawScale.apply($(this), arguments);
			methods.drawTips.apply($(this), arguments);
			methods.drawTitle.apply($(this), arguments);
				
			
		},
		
		/* 
		 * Function to draw Title for diagram
		 *
		 * */		
		drawTitle: function(){
		
			var $this = $(this),
				data = $this.data('diagram'),						
				title = data.settings.title,
				r = data.rDiagram,
				out = r.set();
			
			$(data.settings.legendSelector).children(data.settings.titleSelector).each(function(i){
				
				var currTitle = $(this);
				currTitle.children('.text').each(function(i){
					var titleText = $(this).text(), 
						txt = r.text(title.x, title.y, titleText).attr(
								{"text-anchor": title.textAnchor,
									"fill": title.fontColor,
									"font-size": title.fontSize,
									"font-family": title.fontFamily,
									"font-weight": title.fontWeight,
									"cursor": "pointer"});
					out.push(txt);
					
					title.y = txt.getBBox().y + txt.getBBox().height*1.5;
					});
					
					currTitle.children('.more').each(function(i){
						var titleText = $(this).text(), 
							txt = r.text(title.x, title.y, titleText).attr(
								{"text-anchor": title.textAnchor,
									"fill": title.moreFontColor,
									"font-size": title.moreFontSize,
									"font-family": title.moreFontFamily,
									"font-weight": title.moreFontWeight});
						out.push(txt);
						title.y = txt.getBBox().y + txt.getBBox().height + title.textIndent;
					});
					
				});
			
			out.click(function (event) {
				location.href = title.titlelink;
			});
			
		},
		
		/* 
		 * Function to draw Scale data
		 *
		 * */
		
		drawScale: function(){
			
			var $this = $(this),
				data = $this.data('diagram'),						
				scale = data.settings.scale,
				total = data.settings.totalRange,
				r = data.rDiagram,
				out = r.set(),
				x0 = data.settings.x0,
				y0 = data.settings.y0,
				R = data.settings.maxRadius + scale.textIndent;
			
			if (scale.drawGraduations){
				// Draw with graduations
				var alpha, a, ca, sa, value;
				for (value = 0; value < total; value++) {
                    alpha = 360 / total * value;
                    a = (90 - alpha) * Math.PI / 180;
                    ca = Math.cos(a);
					sa = Math.sin(a);
					out.push(r.path([["M", x0 + R * ca, y0 - R * sa], 
					                        ["L", x0 + (R + scale.graduationSize) * ca, y0 - (R + scale.graduationSize) * sa]]
					                        ).attr({"stroke": scale.graduationColor, "stroke-width": scale.strokeWidth}));
					
					if(scale.angles.indexOf(alpha)!=-1){
						var textAnchor = alpha > 180 ? "end" : "start";
						if ((alpha == 0)||(alpha == 180)){
							textAnchor = "middle";
						} 
						out.push(r.text((x0 + (R + 3*scale.graduationSize) * ca), 
								(y0 - (R + 3*scale.graduationSize) * sa),
								value + " " + scale.text).attr(
										{"text-anchor": textAnchor,
										"fill": scale.fontColor,
										"font-size": scale.fontSize,
										"font-family": scale.fontFamily,
										"font-weight": scale.fontWeight}));
					}
				}
			}else{
				// Draw without graduations
				var alpha, a, value, textAnchor;
				for (var i = 0; i < scale.angles.length; i++){
					alpha = scale.angles[i];
					a = (90 - alpha) * Math.PI / 180;
					value = (alpha * total) / 360;
					textAnchor =  alpha > 180 ? "end" : "start";
					if ((alpha == 0)||(alpha == 180)){
						textAnchor = "middle";
					}
					out.push(r.text((x0 + (R + 3*scale.graduationSize) * Math.cos(a)), 
							(y0 - (R + 3*scale.graduationSize) * Math.sin(a)),
							value + " " + scale.text).attr(
									{"text-anchor": textAnchor,
									"fill": scale.fontColor,
									"font-size": scale.fontSize,
									"font-family": scale.fontFamily,
									"font-weight": scale.fontWeight}));
				}
			}
			
            return out;
		},
		
		/* 
		 * Function to draw Tooltips data
		 *
		 * */
		drawTips: function(){
			var $this = $(this),
				data = $this.data('diagram'),						
				tips = data.settings.tips,
				total = data.settings.totalRange,
				r = data.rDiagram,
				x0 = data.settings.x0,
				y0 = data.settings.y0,
				R = data.settings.maxRadius;
				
			$(data.settings.legendSelector).children(data.settings.tipsSelector).each(function(i){
				var curTip = $(this),
					color = curTip.find('.color').val(),
					value = curTip.find('.value').val(),
					text = curTip.find('.text').text(),
					more = curTip.find('.more').text(),
					out = r.set(),
					alpha = 360 / total * value,
	                a = (90 - alpha) * Math.PI / 180,
					ca = Math.cos(a),
					sa = Math.sin(a),
					curR = tips.currentRadius,
	                x = x0 + curR * ca,
	                y = y0 - curR * sa,
	                x1 = x0 + (R + tips.textIndent) * ca,
            		y1 = y0 - (R + tips.textIndent)* sa,
            		textAnchor = alpha > 180 ? "end" : "start",
	                path;
				//draw first point
				out.push(r.circle(x0, y0 - curR, tips.circleSize1).attr({'fill': tips.circleColor1 ? tips.circleColor1 : color, 'stroke': 'none'}));
				// draw arc path for tip
				if (total == value) {
					path = [["M", x0, y0 - curR], ["A", curR, curR, 0, 1, 1, x0 - 0.01, y0 - curR]];
		        } else {
		        	path = [["M", x0, y0 - curR], ["A", curR, curR, 0, +(alpha > 180), 1, x, y]];
		        }
				
				out.push(r.path(path).attr({'stroke': color, 'stroke-width': tips.width }));
				// draw tip line otside
				out.push(r.path([["M", x, y], ["L", x1, y1]]).attr({'stroke': color, 'stroke-width': tips.width }));
				//  draw second point 
				out.push(r.circle(x1, y1, tips.circleSize2).attr({'fill': tips.circleColor2 ? tips.circleColor2 : color, 'stroke': 'none'}));
				// draw text for tip
									
				var txt1 = r.text((x0 + (R + tips.textIndent * 2) * ca), (y0 - (R + tips.textIndent * 2) * sa), text).attr(
						{"text-anchor": textAnchor,
						"fill": tips.fontColor,
						"font-size": tips.fontSize,
						"font-family": tips.fontFamily,
						"font-weight": tips.fontWeight}),
					txt_bb = txt1.getBBox(),
					txt_x2 = alpha > 180 ? txt_bb.x + txt_bb.width: txt_bb.x,
					txt_y2 = txt_bb.y + txt_bb.height + tips.moreFontSize,
					txt2;
				if (more) {
					txt2 = r.text(txt_x2, txt_y2, "(" + more + ")").attr({
						"text-anchor": textAnchor,
						"fill": tips.moreFontColor,
						"font-size": tips.moreFontSize,
						"font-family": tips.moreFontFamily,
						"font-weight": tips.moreFontWeight
					});
				}
				tips.currentRadius += tips.delta;
				});

		},
		/* 
		 * Function to draw sectors from diagram data
		 *
		 * */
		drawArc: function(){
			var $this = $(this),
				data = $this.data('diagram'),						
				arc = data.settings.arc,
				total = data.settings.totalRange,
				animation = data.settings.animation, 
				r = data.rDiagram,
				x0 = data.settings.x0,
				y0 = data.settings.y0;
											
			$(data.settings.legendSelector).children(data.settings.arcSelector).each(function(i){
				var currArc = $(this), 
					color = currArc.find('.color').val(),
					value = currArc.find('.value').val(),
					text = currArc.find('.text').text(),
					more = currArc.find('.more').text(),
					href = currArc.find('.href').text(),
					alpha = 360 / total * value,
	                a = (90 - alpha) * Math.PI / 180,
	                R = arc.currentRadius,
	                x = x0 + R * Math.cos(a),
	                y = y0 - R * Math.sin(a),
	                path,
	                txt1,
	                txt2,
	                txt_bb;
					
	            if (total == value) {
	            	path = [["M", x0, y0 - R], ["A", R, R, 0, 1, 1, x0 - 0.01, y0 - R]];
	            } else {
	            	path = [["M", x0+5, y0 - R], ["A", R, R, 0, +(alpha > 180), 1, x, y]];
	            }
	            var z = r.path(path).attr({'stroke': color, 'stroke-width': arc.strokeWidth , 'cursor': arc.cursor});
	                  
				if (arc.roundConner){
					var el = r.rect(x0, y0 - R - arc.strokeWidth/2 +1, arc.roundPx * 2, arc.strokeWidth-2, arc.roundPx).attr({'stroke': color, 'fill': color}),
		            	el2 = r.rect(x-5, y - arc.strokeWidth/2+1, arc.roundPx * 2, arc.strokeWidth-2, arc.roundPx).attr({'stroke': color, 'fill': color});
		            el2.rotate(alpha);
				}
	           		 
	            if (more) {
					txt2 = r.text(x0 - arc.textIndent, y0 - R, more).attr({
						"text-anchor": "end",
						"fill": color,
						"font-size": arc.moreFontSize,
						"font-family": arc.moreFontFamily,
						"font-weight": arc.moreFontWeight,
						'cursor': arc.cursor
					});
	            }
	            txt_bb = txt2.getBBox();
	            if (!txt_bb){ 
	            	txt_bb.x = x0 - arc.textIndent;
	            }       
	            if (text) {
					txt1 = r.text(txt_bb.x, y0 - R , text).attr({
						"text-anchor": "end",
						"fill": arc.fontColor,
						"font-size": arc.fontSize,
						"font-family": arc.fontFamily,
						"font-weight": arc.fontWeight,
						'cursor': arc.cursor
					});
	            }
	            
	            var ac = (90 - alpha) * Math.PI / 180 - Math.asin(arc.strokeWidth/(1.2*R)),
	            	xc = x0 + R * Math.cos(ac),
	            	yc = y0 - R * Math.sin(ac),
	            	point = r.circle(xc, yc, arc.strokeWidth/2).attr({'fill': color, 'stroke': 'none', 'cursor': arc.cursor});
	            
	         // Bind Animation functions
	            if(data.settings.animate){
		           var mMouseover = function(){
						var ht = arc.strokeWidth*animation.widthKoef,
							new_a = (90 - alpha) * Math.PI / 180 - Math.asin(arc.strokeWidth/(R));
		                z.animate({ 'stroke-width': ht, opacity: animation.opacity }, animation.speed, animation.easing);
		                if(Raphael.type != 'VML') //solves IE problem
						z.toFront();
		                if (arc.roundConner){
		                	el.stop().animateWith(z, {y: y0 - R - ht/2 + 1, height:  ht -2}, animation.speed, animation.easing);
		                	el.toFront();
		                	el2.stop().animateWith(z, {y: y - ht/2 + 1, height:  ht -2}, animation.speed, animation.easing);
		                	el2.toFront();
						}
		                point.stop().animate({cx: x0 + R * Math.cos(new_a), cy: y0 - R * Math.sin(new_a)}, animation.speed, animation.easing); 
		                if(txt1){ txt1.stop().animateWith(z, {"fill": color, "font-size": arc.fontSize+1});}
					},
					mMouseout = function(){
						z.stop().animate({ 'stroke-width': arc.strokeWidth, opacity: 1 }, animation.speed, animation.easing);
						z.toBack();
						el.stop().animateWith(z, {y: y0 - R - arc.strokeWidth/2 +1, height:  arc.strokeWidth-2, opacity: 1}, animation.speed, animation.easing);
						el.toBack();
						el2.stop().animateWith(z, {y: y - arc.strokeWidth/2+1, height:  arc.strokeWidth-2, opacity: 1}, animation.speed, animation.easing);
						el2.toBack();
						point.stop().animate({cx: xc, cy: yc, opacity: 1});
						point.toBack();
						if(txt1){ txt1.stop().animateWith(z, {fill: arc.fontColor, "font-size": arc.fontSize});}
					};

					z.mouseover(function(){
						mMouseover();
		            }).mouseout(function(){
						mMouseout();
					});
					point.mouseover(function(){
						mMouseover();
		            }).mouseout(function(){
						mMouseout();
					});
					if(txt1){
						txt1.mouseover(function(){
							mMouseover();
						}).mouseout(function(){
							mMouseout();
						});
					}
					if(txt2){
						txt2.mouseover(function(){
							mMouseover();
						}).mouseout(function(){
							mMouseout();
						});	
					}
	            }
	            // Bind Click functions
	            var mClick = function(){ location.href = href; };
				z.node.onclick = mClick;
				point.node.onclick = mClick;
				if(txt1){ txt1.node.onclick = mClick;};
				if(txt2){ txt2.node.onclick = mClick;};
				// set next radius
				arc.currentRadius += arc.strokeWidth + arc.delta;
			});
		
		},
		
		/* 
		 * Function to destroy diagram data
		 *
		 * */		
		destroy: function(){
			return this.each(function(){
				var $this = $(this),
					data = $this.data('diagram');						
				// Namespacing FTW
				$this.removeData('diagram');
			});
		}			
	};
	
	$.fn.RDiagram = function(method){    
		if (methods[method]){
			return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
		} else if (typeof method === 'object' || ! method){
			return methods.init.apply(this, arguments);
		} else {
			$.error('Method ' +  method + ' does not exist on excentrics.rdiagram.jquery');
		}      
	};

})(jQuery));

