/**
 * @author mbarry
 * @version 1.1
 * @since 2010-10-07
 */
var Pens;
$(function() {
	
	if ($('html')[0].style['pointerEvents'] === undefined) {
		return;
	}
	
	var drawingMode = false,
	draw = false,
	holdingPen = false, 
	canvasCreated = false,
	canvas = null,
	ctx = null,
	currentPen = null,
	contentMiddle = $("#content_middle"),
	pos = {},
	prev = {
		x: null,
		y: null
	},
	overContentMiddle = false,
	animatedPen = false,
	drawingArea = {},
	penOffsetX = 2,
	penOffsetY = 28,
	canvasWidthOffset = -23,
	canvasHeightOffset = -9;
	
	updateContentBottomPosition();
	updateDrawingArea();
	$(window).bind("resize", updateDrawingArea);
	
	$("#blue_pen").data("drawing_color", "#1370ab");
	$("#green_pen").data("drawing_color", "#239a2e");
	$("#red_pen").data("drawing_color", "#ff4000");
	$("#yellow_pen").data("drawing_color", "#ffbb00");
	
	$(document).bind("mousedown", function(evt) {
		return docMouseDown(evt);
		
	}).bind("mouseup", function(evt) {
		return docMouseUp(evt);
		
	}).bind("mousemove", function(evt) {
		return docMouseMove(evt.pageX, evt.pageY, evt);
		
	}).bind("keyup", function(evt) {
		if (evt.keyCode == 27) {
			clearCanvas();
		};
	}).each(function() {
		this.addEventListener("touchstart", function(evt) {
			if (evt.touches.length == 1) {
				var returnVal = docMouseDown(evt);
				if (returnVal === false) {
					evt.preventDefault();
				};
			}
		}, false);
		this.addEventListener("touchmove", function(evt) {
			if (evt.touches.length == 1) {
				var returnVal = docMouseMove(evt.touches[0].pageX, evt.touches[0].pageY, {
					pageX: evt.touches[0].pageX,
					pageY: evt.touches[0].pageY
				});
				if (returnVal === false) {
					evt.preventDefault();
				};
			}
		}, false);
		this.addEventListener("touchend", function(evt) {
			if (evt.touches.length == 0) {
				var returnVal = docMouseUp(evt);
				if (returnVal === false) {
					evt.preventDefault();
				};
				
				prev = {
					x: null,
					y: null
				}
			}
		}, false);
	});
	
	// pens
	$("#content_bottom img").css({
		zIndex: 4000,
		cursor: 'move'
	}).bind("mousedown", function(evt) {
		// opera doesn't have layerX
		return penMouseDown.call(this, evt.layerX || evt.offsetX, evt.layerY || evt.offsetY);
		
	}).each(function() {
		this.addEventListener("touchstart", function(evt) {
			if (evt.touches.length == 1) {
				evt.preventDefault();
				
				// var penPos = $(evt.touches[0].target).offset();
				// evt.touches[0].pageX - penPos.left, evt.touches[0].pageY - penPos.top
				
				// I think it's less confusing if the pen tip is where you're pressing
				penMouseDown.call(this, penOffsetX, penOffsetY);
			}
		}, false);
	});
	
	function docMouseDown(evt) {
		if (drawingMode) {
			if (!canvasCreated) {
				createCanvas();
				canvasCreated = true;
			};
			draw = true;
			// prevent text selection
			return false;
		};
	}
	
	function docMouseUp(evt) {
		if (!drawingMode) {
			holdingPen = false;
			currentPen = null;
			$("#content_bottom img").css("pointerEvents", 'all');
			$('#content_middle *:not(canvas)').css("pointerEvents", 'all');
		};
		draw = false;
	}
	
	function docMouseMove(pageX, pageY, evt) {
		if (holdingPen && penTipOverContentMiddle(evt)) {
			if (!animatedPen) {
				$(currentPen).stop().animate({
					rotate: '-30deg'
				}, 100);
				var drawPoints = getDrawPoints(evt);
				prev.x = drawPoints.x;
				prev.y = drawPoints.y;
				drawingMode = true;
				animatedPen = true;
			}
			
		} else if (animatedPen) {
			$(currentPen).stop().animate({
				rotate: '0deg'
			}, 100);
			drawingMode = false;
			animatedPen = false;
		}
		var drawPoints = getDrawPoints(evt);
		if (holdingPen) {
			// match the tip of the pen
			var offsetX = $(currentPen).data("offsetX");
			var offsetY = $(currentPen).data("offsetY");
			var posX = pageX - pos.left - (offsetX === undefined ? 0 : offsetX);
			var posY = pageY - pos.top - (offsetY === undefined ? 0 : offsetY);
			
			$(currentPen).css({
				left: posX,
				top: posY
			});
			if (drawingMode && draw && prev.x !== null && prev.y !== null) {
				drawLine(prev.x, prev.y, drawPoints.x, drawPoints.y, $(currentPen).data("drawing_color"));
			};
		};
		prev.x = drawPoints.x;
		prev.y = drawPoints.y;
	}
	
	function penMouseDown(layerX, layerY) {
		 // opera fix, looks to still be receiving events despite pointer-events being set to none
		if (currentPen === this)
			return true;
		currentPen = this;
		$(currentPen).data("offsetX", layerX);
		$(currentPen).data("offsetY", layerY);
		
		// turn of mouse events for the pen and content_middle's children
		$('#content_middle *').css("pointerEvents", 'none');
		$("#content_bottom img").css('zIndex', 4000);
		$(currentPen).css({
			"zIndex": 4001,
			"pointerEvents": 'none'
		});
		// recalculate content_bottom's position
		updateContentBottomPosition();
		holdingPen = true;
		return false;
	}
	
	function getDrawPoints(evt) {
		var offsetX = $(currentPen).data("offsetX");
		var offsetY = $(currentPen).data("offsetY");
		var drawPoints = {
			x: evt.pageX - drawingArea.left - (offsetX === undefined ? 0 : offsetX) + penOffsetX,
			y: evt.pageY - drawingArea.top - (offsetY === undefined ? 0 : offsetY) + penOffsetY
		}
		return drawPoints;
	}
	
	function createCanvas() {
		if (canvas === null) {
			canvas = document.createElement("canvas");
			canvas.id = 'drawing_canvas';
			contentMiddle[0].appendChild(canvas);
			
			$(canvas).css({
				pointerEvents: 'none',
				position: 'absolute',
				top: 10,
				left: 11,
				zIndex: 3000
			});
			ctx = canvas.getContext('2d');
			setCanvasSize();
		};
	}
	
	function setCanvasSize() {
		if (canvas !== null) {
			var canvasImage = new Image();
			canvasImage.onload = function() {
				ctx.drawImage(this, 0, 0);
			}
			var canvasData = canvas.toDataURL();
			canvas.width = contentMiddle.width() + canvasWidthOffset;
			canvas.height = contentMiddle.height() + canvasHeightOffset;
			updateDrawingArea();
			updateContentBottomPosition();
			canvasImage.src = canvasData;
		};
	}
	
	function drawLine(startX, startY, endX, endY, color) {
		if (ctx !== null) {
			ctx.save();
			var distance = Math.sqrt(((endX - startX) * (endX - startX)) + ((endY - startY) * (endY - startY)));
			ctx.beginPath();
			ctx.strokeStyle = color || '#ff0000';
			ctx.lineCap = "round";
			var lineWidth = (3 / (!isNaN(distance) && (distance !== 0) ? distance : 3)) + 5;
			ctx.lineWidth = ((isNaN(lineWidth) || !isFinite(distance)) ? 5.5 : lineWidth);
			ctx.moveTo(startX, startY);
			ctx.lineTo(endX, endY);
			ctx.stroke();
			ctx.closePath();
			ctx.restore();
		};
	}
	
	function clearCanvas() {
		$(canvas).animate({
			opacity: 0
		}, 500, function() {
			ctx.clearRect(0, 0, canvas.width, canvas.height);
			$(this).css("opacity", 1);
		});
	}
	
	function updateDrawingArea() {
		drawingArea = $.extend({}, contentMiddle.offset(), {
			w: contentMiddle.outerWidth(),
			h: contentMiddle.outerHeight()
		});
		return drawingArea;
	}
	
	function penTipOverContentMiddle(evt) {
		var offsetX = $(currentPen).data("offsetX");
		var offsetY = $(currentPen).data("offsetY");
		var penX, penY;
		var leewayX = 10;
		var leewayY = 10;
		
		if (evt.touches && evt.touches.length == 1) {
			penX = evt.touches[0].pageX - (offsetX === undefined ? 0 : offsetX) + penOffsetX;
			penY = evt.touches[0].pageY - (offsetY === undefined ? 0 : offsetY) + penOffsetY;
			
		} else {
			penX = evt.pageX - (offsetX === undefined ? 0 : offsetX) + penOffsetX;
			penY = evt.pageY - (offsetY === undefined ? 0 : offsetY) + penOffsetY;
		}
		
		var isOver = drawingArea.left - leewayX <= penX && 
		drawingArea.left + drawingArea.w + leewayX >= penX && 
		drawingArea.top - leewayY <= penY && 
		drawingArea.top + drawingArea.h + leewayY >= penY;
		
		return isOver;
	}
	
	function updateContentBottomPosition() {
		pos = $("#content_bottom").offset();
		return pos;
	}
	
	Pens = {
		setCanvasSize: setCanvasSize
	}
});
