﻿/**
* Cornerz 0.8 - Bullet Proof Corners
* Jonah Fox (jonah@parkerfox.co.uk) 2008
* 
* Usage: $('.myclass').curve(options)
* options is a hash with the following parameters. Bracketed is the default
*   radius (10)
*   borderWidth (read from BorderTopWidth or 0)
*   background ("white"). Note that this is not calculated from the HTML as it is expensive
*   borderColor (read from BorderTopColor)
*   corners ("tl br tr bl"). Specify which borders
*   fixIE ("padding") - attmepts to fix IE by incrementing the property by 1 if the outer width/height is odd.

CHANGELIST from  v0.4

0.5 - Now attempts to fix the odd dimension problem in IE 
0.6 - Added semicolons for packing and fixed a problem with odd border width's in IE

*/

; (function($) {

	if ($.browser.msie && document.namespaces["v"] == null) {
		document.namespaces.add("v", "urn:schemas-microsoft-com:vml");
		var ss = document.createStyleSheet().owningElement;
		ss.styleSheet.cssText = "v\\:*{behavior:url(#default#VML);}"
	}

	$.fn.cornerz = function(options) {

		function canvasCorner(t, l, r, bw, bc, bg, inline, o) {
			var sa, ea, cw, sx, sy, x, y, p = 1.57, css = "position:absolute;";

			if (t) {
				sa = -p; sy = r; y = o ? r : 0; css += "top:-" + (o ? r : bw) + "px;";
			}
			else
			{ sa = p; sy = 0; y = o ? 0 : r; css += "bottom:-" + (o ? r : bw) + "px;"; }
			if (l)
			{ ea = p * 2; sx = r + 0; x = o ? r : 0; css += "left:-" + bw + "px;" }
			else {
				ea = 0; sx = 0; x = o ? 0 : r;

				if (inline) {
					css += "left:" + (inline - r - bw) + "px;";
				} else {
					css += "right:" + (-bw) + "px;";
				}
			}

			var canvas = $("<canvas width=" + r + "px height=" + r + "px style='" + css + "' ></canvas>");
			var ctx = canvas[0].getContext('2d');
			ctx.beginPath();
			ctx.lineWidth = bw * 2;

			var nr = o ? r - bw : r
			if (nr < 0) {
				nr = r;
				bg = bc;
				ctx.lineWidth = 0
			}
			ctx.arc(sx, sy, nr, sa, ea, !(t ^ l)); // fails for bw > r
			ctx.strokeStyle = bc;
			ctx.stroke();
			ctx.lineWidth = 0;
			ctx.lineTo(x, y);
			ctx.fillStyle = bg;
			ctx.fill();
			return canvas;
		};

		function canvasCorners(corners, r, bw, bc, bg, inline, outer) {
			var hh = $("<div style='display: inherit' />"); // trying out style='float:left' 
			$.each(corners.split(" "), function() {
				hh.append(canvasCorner(this[0] == "t", this[1] == "l", r, bw, bc, bg, inline, outer));
			});
			return hh;
		};

		function vmlCurve(r, b, c, m, ml, mt, rfix, fill_col) {
			var l = m - ml - rfix;
			var t = m - mt;

			var filled = fill_col ? "True" : "False"

			return "<v:arc filled='" + filled + "' fillcolor='" + fill_col + "' strokeweight='" + b + "px' strokecolor='" + c + "' startangle='0' endangle='361' style=' top:" + t + "px;left: " + l + ";width:" + r + "px; height:" + r + "px' />";
		}


		function vmlCorners(corners, r, bw, bc, w, bg, outer) {
			var h = "<div style='text-align:left; '>";

			$.each($.trim(corners).split(" "), function() {
				var css, ml = 1, mt = 1;
				var rfix = 0;

				if (this.charAt(0) == "t") {
					css = "top:-" + (outer ? r : bw) + "px;";
				}
				else {
					css = "bottom:-" + (outer ? r : bw) + "px;";
					mt = r + 1;
				}
				if (this.charAt(1) == "l")
					css += "left:-" + bw + "px;";
				else {
					css += "right:-" + (bw) + "px; "; // odd width gives wrong margin?
					ml = r;
					rfix = 1;
				}

				h += "<div style='" + css + "; position: absolute; overflow:hidden; width:" + r + "px; height: " + r + "px;'>";
				h += "<v:group  style='width:1000px;height:1000px;position:absolute;' coordsize='1000,1000' >";

				if (!outer)
					h += vmlCurve(r * 3, r + bw, bg, -r / 2, ml, mt, rfix);
				if (bw > 0 || outer)
					h += vmlCurve(r * 2 - bw, bw, bc, Math.floor(bw / 2 + 0.5), ml, mt, rfix, outer ? bg : null);
				h += "</v:group>";
				h += "</div>";
			});
			h += "</div>";

			return h;
		};

		var alterProperty = function(elem, prop, x) {
			var y = parseInt(elem.css(prop)) || 0;

			elem.css(prop, x + y);
		}

		function fixDimensions($$) {
			var ow = $$.innerWidth();
			var oh = $$.innerHeight();

			if (ow % 2 == 1) {
				alterProperty($$, "padding-right", 1);
				alterProperty($$, "margin-right", 1);
			}

			if (oh % 2 == 1) {
				alterProperty($$, "padding-bottom", 1);
				alterProperty($$, "margin-bottom", 1);
			}
		}

		/***** OUTER CORNERZ CODE *****/

		function addTopBot($el, r, bw, bc, bg, cs) {

			var tl = cs.indexOf("tl") != -1;
			var tr = cs.indexOf("tr") != -1;
			var bl = cs.indexOf("bl") != -1;
			var br = cs.indexOf("br") != -1;

			var offsetTop = (tl || tr) ? r : 0;
			var offsetBot = (bl || br) ? r : 0;

			var borderTop = (tl || tr) ? parseInt($el.css("borderTopWidth")) : 0;

			var pt = parseInt($el.css("paddingTop"));
			var pb = parseInt($el.css("paddingTop"));
			var pl = parseInt($el.css("paddingLeft"))

			var h = $el.height() - r - r + borderTop + borderTop;

			if (h < 0)
				h = 0;

			$el.css("height", h)

			if (!bg)
				bg = $el.css("backgroundColor");
			if (!bw)
				bw = borderTop;
			if (!bc)
				bc = $el.css("borderTopColor");

			$el.css("position", "relative");

			//var cs = o.corners.split(" ");


			$el.wrapInner("<div class=_content style='position: absolute; left: " + pl + "px; top: -" + (offsetTop - borderTop) + "px'  />");

			if (tl || tr) {
				addElement($el, tl, tr, r, bw, bc, bg, "top");
				alterProperty($el, "margin-top", offsetTop);
			}

			if (bl || br) {
				addElement($el, bl, br, r, bw, bc, bg, "bottom");
				alterProperty($el, "margin-bottom", offsetBot);
			}


			//$el.after("<div style='line-height:0px; padding:0px; margin:0px'>&nbsp;</div>")
		}

		function addElement($el, tl, tr, r, bw, bc, bg, type) {
			var elemcss = {};
			elemcss["border-" + type + "-width"] = 0;

			var w = $el.outerWidth();
			var h = r - bw;


			var padding = parseInt($el.css("padding-" + type));

			var new_padding = 0;
			if (h - padding < 0) {
				new_padding = padding - h;
			}
			//elemcss["padding-" + type]  = new_padding;

			var css = { background: bg,
				"position": "absolute"
			}
			var l = 0;

			css["margin-" + type] = -h - bw;
			css[type] = 0;
			var border = bw + "px solid " + bc;
			css["border-" + type] = border;
			if (tl) {
				l += r - bw;
				w -= r + bw;
			} else {
				css["border-left"] = border;
				l -= bw;
			}
			if (tr) {
				l -= 0;
				w -= r + bw;
			} else {
				css["border-right"] = border;
			}

			if (tr && tl) {
				w += bw + bw
			}

			css.left = l;
			css.width = w;
			css.height = h;
			var div = $("<div>").css(css);

			$el.prepend(div)
           .css(elemcss);
		}

		/*************/

		var settings = {
			corners: "tl tr bl br",
			radius: 10,
			background: "white",
			borderWidth: 0,
			fixIE: true,
			outer: false
		};

		$.extend(settings, options || {});

		/********/

		return this.each(function() {
			var $$ = $(this);
			var r = settings.radius * 1.0;
			var bw = (settings.borderWidth || parseInt($$.css("borderTopWidth")) || 0) * 1.0;
			var bg = settings.background;
			var bc = settings.borderColor;
			bc = bc || (bw > 0 ? $$.css("borderTopColor") : bg);

			var cs = settings.corners;


			this.style.zoom = 1;

			if ($$.css("position") != "absolute")
				this.style.position = "relative";


			if (settings.outer) {
				bg = $$.css("backgroundColor");
				addTopBot($$, r, bw, bc, bg, cs);
			}

			if ($.browser.msie) {
				this.innerHTML = vmlCorners(cs, r, bw, bc, $(this).width(), bg, settings.outer) + this.innerHTML;

				if (settings.fixIE && !settings.outer)
					fixDimensions($$)
			}
			else
				$$.prepend(canvasCorners(cs, r, bw, bc, bg, $$.css("display") == "inline" ? $$.outerWidth() : null, settings.outer));


		}

    );

	}
})(jQuery);
