/**
 * @author trixta
 */
(function($){
/*
if($.support.borderRadius && !window.devBorderRadius) {
	$.fn.borderRadius = function(){return this;};
	return;
}
*/

function getColor(elem, attr) {
		var color;

		do {
				color = $.curCSS(elem, attr);
					
				// Keep going until we find an element that has color, or we hit the body
				if ( color !== '' && color != 'transparent' || $.nodeName(elem, "body") )
						break;

				attr = "backgroundColor";
		} while ( elem = elem.parentNode );
		color = (color === 'transparent') ? '#fff' : color;
		return color;
}
		
var ie6 = ($.browser.msie && parseInt($.browser.version, 10) < 7),
	pos = {
		tl: function(elem, border, container){
			elem.css({
				top: 0 - border,
				left: 0 - border
			});
		},
		tr: function(elem, border, rC, tC){
			elem.css({
				marginRight: rC,
				top: 0 - border,
				right: 0 - border
			});
		},
		bl: function(elem, border, rC, tC){
			elem.css({
				marginBottom: tC,
				bottom: 0 - border,
				left: 0 - border
			});
		},
		br: function(elem, border, rC, tC){
			
			elem.css({
				marginRight: rC,
				marginBottom: tC,
				bottom: 0 - border,
				right: 0 - border
			});
		}
	};	
	
		
	function drawCTXCorner(ctx, type, radius, bgColor, borderSize, borderColor, drwaType){
		
		function drawCorner(x1, y1, cpx1, cpy1, x2, y2, x3, y3, x4, y4){
			ctx.beginPath();
			ctx.moveTo( x1, y1 );

			ctx.quadraticCurveTo( cpx1, cpy1, x2, y2);
			
			if(borderColor && borderSize){
				ctx.strokeStyle = borderColor;
				ctx.lineWidth = borderSize + (borderSize);
				ctx.stroke();
				
			}
			
			ctx.lineTo(x3, y3);
			ctx.lineTo(x4, y4);
			ctx.fillStyle = bgColor;
			ctx.fill();
			

		}
		
		switch (type) {
			case "tl":
				((drwaType == 'substract') ? 
					drawCorner(0, radius, 0, 0, radius, 0, radius * -1, radius * -1, radius * -1, 0) :
					drawCorner(borderSize, radius, borderSize, borderSize, radius, borderSize, radius, radius, borderSize, radius));
				break;
			case "tr":
				((drwaType == 'substract') ? 
					drawCorner(0, 0, radius, 0, radius, radius, radius, 0, radius * -1, radius * -1) :
					drawCorner(0, borderSize, radius, 0, radius-borderSize, radius, 0, radius, 0, 0));
				break;
			case "bl":
				((drwaType == 'substract') ? 
					drawCorner(0, 0, 0, radius, radius, radius,  radius * -1, radius, 0, 0) :
					drawCorner(borderSize, 0, borderSize, radius, radius, radius-borderSize, radius, 0, borderSize, 0));
				break;
			case "br":
				((drwaType == 'substract') ? 
					drawCorner(0, radius, radius, radius, radius, 0, radius, radius, 0, radius) :
					drawCorner(0, radius-borderSize, radius, radius, radius-borderSize, 0, 0, 0, 0, radius-borderSize));
				break;
			default:
			break;
		}
	}
			
				
	$.fn.borderRadius = function (opts){
		if($.support.borderRadius && !window.devBorderRadius && !opts.forceCanvasRadius){return this;}
		opts = $.extend({}, $.fn.borderRadius.defaults, opts);
		
		var corners = ['tl', 'tr', 'bl', 'br'];
		if(opts.radius){
			$.each(corners, function(i, corner){
				opts[corner+'radius'] = opts.radius;
				opts[corner+'bgColor'] = opts[corner+'bgColor'] ||
					opts.bgColor;
			});
		}
				
		function addCanvas(elem, type, radius){
			elem.style.position = 'relative';
			var radiusElement = $(document.createElement(opts.containerElement))
					.addClass('border-radius-corner-reset')
					.attr({style: 'position: absolute; width: '+ radius +'px; height: '+ radius +'px; overflow: hidden; lineHeight: 0px; fontSize: 0px; fontSize: 0px'})
					,
				
				canvas = $('<canvas style="width: '+ radius +'px; height: '+ radius+' px" />')
					.attr({
						width: radius,
						height: radius
					}),
				shim = false
			;	
			radiusElement[0].appendChild(canvas[0]);
			
			return {
				radiusElement: radiusElement,
				radius: radius
			};
			
		}
		
		function changeRowStyle(jElm, side, realBorderColor, borderSize, bgColor){
			var borderCSS = {}, css = {
				backgroundColor: bgColor
			};
			if(realBorderColor && borderSize){
				borderCSS['border'+side+'Style'] = 'solid';
				borderCSS['border'+side+'Width'] = borderSize;
				borderCSS['border'+side+'Color'] = realBorderColor;
				css = $.extend(css, borderCSS);
				
			}
			jElm.css(css);
		}
		
		function drawRow(jElm, innerElem, type, lRadius, rRadius, bgColor, realBorderColor, borderSize){
			var maxRadius = Math.max(lRadius, rRadius),
				css = {
						position: 'relative',
						display: 'block',
						height: maxRadius-borderSize+'px',
						marginLeft: lRadius+'px',
						marginRight: rRadius+'px',
						overflow: 'hidden',
						lineHeight: '0px',
						fontSize: '0px'
					},
				insertAction = 'appendTo',
				paddingSide = 'paddingBottom',
				side = 'Bottom';
				
			if(type == 'top'){
				insertAction = 'prependTo';
				side = 'Top';
				css = $.extend(css, {
					marginTop: 0
				});
				paddingSide = 'paddingTop';
			} else {
				css = $.extend(css, {
					marginBottom: 0
				});
			}
			
			
			
			innerElem
				.css(paddingSide, parseFloat(innerElem.css(paddingSide), 10) + parseFloat(jElm.css(paddingSide), 10) - maxRadius);
			jElm
				.css(paddingSide, 0);
			
			var rowElement = $(document.createElement(opts.containerElement))
					.css(css)
					.addClass('border-radius-row-reset')
					[insertAction](jElm[0]);
				
			changeRowStyle(rowElement, side, realBorderColor, borderSize, bgColor);
			return rowElement;
		}
		
		function getBgColor(jElm, drawType){
			if(drawType === 'add'){
				return jElm.css('backgroundColor');
			} else {
				return getColor(jElm.parent()[0], 'backgroundColor');
			}
		}
		
		$[ ($.lazyEach) ? 'lazyEach' : 'each' ](this, function(i, elem){
			var jElm 			= $(elem), 
				realBorderSize 	= parseFloat(jElm.css('borderLeftWidth'), 10), 
				realBorderColor = jElm.css('borderLeftColor'),
				bottomCorrect 	= 0, 
				rightCorrect 	= 0, 
				canvasContext 	= $.data(elem, 'borderRadius') || {drawType: opts.drawType},
				drawType 		= canvasContext.drawType,
				bgColor 		= opts.bgColor || getBgColor(jElm, drawType)
			;
			
			opts.containerElement = (jElm.is('div, li')) ? 'div' : 'span';
			
			if(isNaN(realBorderSize)){
				realBorderSize = 0;
			}
			
			var len = corners.length;
			if(ie6){
				rightCorrect = (jElm.innerWidth() % 2) ?
						'-1px' :
						'';
				bottomCorrect = (jElm.innerHeight() % 2) ?
						'-1px' :
						'';
			}
			
			if(drawType == 'add'){
				var innerElem = jElm;
				
				if(!canvasContext.topRow || !canvasContext.bottomRow){
					var jElm = $('<div style="overflow: hidden; zoom: 1;" />');
				
					$(elem).wrap(jElm[0]);
				}
				jElm = $(elem).parent();
				
				if (!canvasContext.topRow || !canvasContext.bottomRow) {
					var transferStyles = {
						marginTop: '0px',
						marginLeft: '0px',
						marginRight: '0px',
						marginTop: '0px',
						marginBottom: '0px',
						width: 'auto',
						'float': 'none'
					};
					
					$.each(transferStyles, function(transferStyle, resetStyle){
						var css = innerElem.css(transferStyle);
						if (css !== 'auto' && transferStyle === 'width') {
							css = innerElem.outerWidth();
						}
						
						if (css) {
							jElm.css(transferStyle, css);
						}
						if (resetStyle) {
							innerElem.css(transferStyle, resetStyle);
						}
					});
					
					innerElem[0].style.borderTopStyle = 'none';
					innerElem[0].style.borderBottomStyle = 'none';
					
					canvasContext.topRow = drawRow(jElm, innerElem, 'top', opts.tlradius, opts.trradius, bgColor, realBorderColor, realBorderSize);
					canvasContext.bottomRow = drawRow(jElm, innerElem, 'bottom', opts.blradius, opts.brradius, bgColor, realBorderColor, realBorderSize);
				} else {
					changeRowStyle(canvasContext.topRow, 'Top', realBorderColor, realBorderSize, bgColor);
					changeRowStyle(canvasContext.bottomRow, 'Bottom', realBorderColor, realBorderSize, bgColor);
				}
				
			}
			try{
				var radiusElements 	= [],
					typeOrder 		= [];
				while(len--){
					var type 			= corners[len],
						radius 			= opts[type+'radius'],
						known 			= canvasContext[type] && canvasContext[type].radius
					;
					if(radius || canvasContext[type]) {
						
						if(!canvasContext[type]){
							canvasContext[type] = addCanvas(jElm[0], type, radius);	
						} else {
							radius = radius || canvasContext[type].radius;
							canvasContext[type].canvas.clearRect(0, 0, radius, radius);
						}
						radiusElements.push(canvasContext[type].radiusElement);
						typeOrder.push(type);
					}
					
				}
				
				if(!known) {
					$(radiusElements).appendTo(elem);
				}
				len = typeOrder.length;
				
				while(len--){
					var type 	= typeOrder[len],
						radius 	= opts[type+'radius']
					;
					
					if (!known) {
						var canvas = $(canvasContext[type].radiusElement).find('canvas');
						
						
						if (canvas[0] && !canvas[0].getContext && typeof G_vmlCanvasManager != 'undefined') {
							canvas = $(G_vmlCanvasManager.fixDynamicElement(canvas[0]));
						}
						
						canvasContext[type].canvas = canvas[0].getContext('2d');
						pos[type](canvasContext[type].radiusElement, (drawType !== 'add') ? realBorderSize : 0, rightCorrect, bottomCorrect);
						
					}
					if(radius || (canvasContext[type] && canvasContext[type].canvas)) {
						radius = radius || canvasContext[type].radius;
						drawCTXCorner(canvasContext[type].canvas, type, radius, opts[type+'bgColor'] || bgColor, realBorderSize, realBorderColor, drawType);
					}
				}
			} catch(e){}
			$.data((innerElem && innerElem[0]) ? innerElem[0] : jElm[0], 'borderRadius', canvasContext);
		});
		return this;
	};
	
	$.fn.borderRadius.defaults = {
		containerElement: 'div',
		bgColor: false,
		drawType: 'substract',
		forceCanvasRadius: false
	};
	
})(jQuery);
