/**
 * @author Sergey Chikuyonok (serge.che@gmail.com)
 * @link http://chikuyonok.ru
 */
 
var shadow = {
	min: Number.POSITIVE_INFINITY,
	max: Number.NEGATIVE_INFINITY,
	lines: {},
	degs: []
};

var cv_rect;
 
/**
 * Преобразует массивоподобный объект в массив
 * @param {Object} ar
 * @return {Array}
 */
function toArray(ar) {
	return Array.prototype.slice.call(ar, 0);
}

/**
 * Добавляет линию, описывающую тень
 * @param Массив точек
 */
function addLine() {
	var points = toArray(arguments);
	// считаем угол наклона линии
	var first = points[0],
		last = points[points.length - 1];
	
	var deg = -Math.atan2(last.y - first.y, last.x - first.x) / Math.PI * 180;
	
	
	shadow.degs.push(deg);
	shadow.lines[deg] = points;
	if (deg < shadow.min)
		shadow.min = deg;
		
	if (deg > shadow.max)
		shadow.max = deg;
}

/**
 * Точка
 * @param {Number} x
 * @param {Number} y
 * @return {Object}
 */
function p(x, y) {
	return {x: x, y: y};
}

/**
 * Кривая Безье
 * @param {Number} cp1x
 * @param {Number} cp1y
 * @param {Number} cp2x
 * @param {Number} cp2y
 * @param {Number} x
 * @param {Number} y
 * @return {Object}
 */
function bz(cp1x, cp1y, cp2x, cp2y, x, y) {
	return {
		cp1x: cp1x,
		cp1y: cp1y,
		cp2x: cp2x,
		cp2y: cp2y,
		x: x,
		y: y
	};
}

/**
 * Адаптер для рисования через canvas
 */
function CanvasAdapter(width, height, id, parent_id) {
	/** Элемент холста, на котором рисуются линии */
	this.canvas = document.createElement('canvas');
	
	if (parent_id)
		document.getElementById(parent_id).appendChild(this.canvas);
	
	if (window.G_vmlCanvasManager)
		G_vmlCanvasManager.initElement(this.canvas);
	
	this.canvas.width = width;
	this.canvas.height = height;
	
	if (id)
		this.canvas.id = id;
	
	/** @type {CanvasRenderingContext2D} Контекст рисования */
	this.ctx = this.canvas.getContext('2d');
	this.ctx.lineWidth = 13;
	this.ctx.save();
}

CanvasAdapter.prototype = {
	/**
	 * Полностью очищает холст
	 */
	clear: function() {
		this.ctx.restore();
		this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
		this.ctx.beginPath();
		this.ctx.save();
	},
	
	/**
	 * Перемещает указатель рисования в указанную точку
	 * @param {p()} point Точка
	 */
	moveTo: function(point) {
		this.ctx.moveTo(Math.round(point.x), Math.round(point.y))
	},
	
	/**
	 * Рисует линию в указанную точку
	 * @param {p()} point Точка
	 */
	lineTo: function(point) {
		this.ctx.lineTo(Math.round(point.x), Math.round(point.y));
	},
	
	/**
	 * Рисует кривую Безье в указанную точку
	 * @param {bz()} bezier Кривая Безье
	 */
	bezierTo: function(bezier){
		this.ctx.bezierCurveTo(bezier.cp1x, bezier.cp1y, bezier.cp2x, bezier.cp2y, bezier.x, bezier.y);
	},
	
	/**
	 * Рисует линию
	 */
	draw: function() {
		this.ctx.stroke();
	},
	
	/**
	 * Возвращает элменент холста, на котором все рисуется
	 * @return {Element}
	 */
	getElement: function() {
		return this.canvas;
	},
	
	width: function() {
		return this.canvas.width;
	},
	
	height: function() {
		return this.canvas.height;
	},
	
	translate: function(x, y) {
		this.ctx.translate(x, y);
	}
};

/**
 * Проверяет, являются ли два числа одинакового знака (плюс/минус)
 * @param {Number} a
 * @param {Number} b
 * @return {Boolean}
 */
function sameSigns(a, b) {
	return ((a ^ b) > 0);
}

/**
 * Bщет пересечение двух линий
 * @param {Number} x1
 * @param {Number} y1
 * @param {Number} x2
 * @param {Number} y2
 * @param {Number} x3
 * @param {Number} y3
 * @param {Number} x4
 * @param {Number} y4
 * @return {p}
 */
function lineIntersection(x1, y1, x2, y2, x3, y3, x4, y4) {
	var a1, a2, b1, b2, c1, c2,
		r1, r2, r3, r4;

	a1 = y2 - y1;
	b1 = x1 - x2;
	c1 = x2 * y1 - x1 * y2;

	r3 = a1 * x3 + b1 * y3 + c1;
	r4 = a1 * x4 + b1 * y4 + c1;

	if (r3 && r4 && sameSigns(r3, r4))
		return false;

	a2 = y4 - y3;
	b2 = x3 - x4;
	c2 = x4 * y3 - x3 * y4;

	r1 = a2 * x1 + b2 * y1 + c2;
	r2 = a2 * x2 + b2 * y2 + c2;

	if (r1 && r2 && sameSigns(r1, r2))
		return false;

	var denom = a1 * b2 - a2 * b1;
	if (denom == 0)
		return false;

	var offset = denom < 0 ? -denom / 2 : denom / 2;

	var num = b1 * c2 - b2 * c1;
	var x = Math.floor((num < 0 ? num - offset : num + offset) / denom);

	num = a2 * c1 - a1 * c2;
	var y = Math.floor((num < 0 ? num - offset : num + offset) / denom);

	return p(x, y);
}

/**
 * Высчитывает параметры линии для указанного угла
 * @param {Number} deg
 * @return {Array}
 */
function calculateLine(deg) {
	deg = Math.min(shadow.max, Math.max(shadow.min, deg));
	
	var result = [], d1, d2, coeff;
	for (var i = 1; i < shadow.degs.length; i++) {
		d1 = shadow.degs[i - 1];
		d2 = shadow.degs[i];
			
		if (deg >= d1 && deg <= d2) {
			coeff = 1 -(deg - d1) / (d2 - d1);
			break;
		}
	}
	
	if (coeff !== null) {
		var l1 = shadow.lines[d1],
			l2 = shadow.lines[d2];
		
		for (var j = 0; j < l1.length; j++) {
			var p1 = l1[j],
				p2 = l2[j],
				point = {};
			for (var p in p1) if (p1.hasOwnProperty(p)) {
				point[p] = p2[p] + (p1[p] - p2[p]) * coeff;
			}
			
			result.push(point);
		}
	}
	
	return result;
}

//shadow.degs.sort();




$(function(){
	var ca1 = new CanvasAdapter(770, 290, 'cv-masked', 'shadow1');
	var ca2 = new CanvasAdapter(770, 290, 'cv-line', 'shadow2');
	
	var shadow_cutter = $('.shadow-cutter');
	
	ca1.ctx.globalAlpha = 0.4;
	ca1.ctx.fillStyle = '#4c4c4c';
	ca1.ctx.save();
	
	ca2.ctx.fillStyle = '#7f7f7f';
	ca2.ctx.strokeStyle = '#7f7f7f';
	ca2.ctx.save();
	
	if (!$.browser.opera)
		drawMask();
	
	
	/**
	 * Рисует на холсте маску по контуру лошади
	 */
	function drawMask() {
		ca1.moveTo(horse_mask[0]);
		for (var i = 1; i < horse_mask.length; i++) {
			ca1.lineTo(horse_mask[i]);
		}
		
		ca1.ctx.closePath();
		ca1.ctx.clip();
		if (!$.browser.opera)
			ca1.ctx.save();
	}
	
	/**
	 * Рисует тень
	 * @param {Number} mx X-координата курсора мышки
	 * @param {Number} my Y-координата курсора мышки
	 */
	function drawShadowLine(mx, my) {
		var cx = (cv_rect.right - cv_rect.left) / 2;
		var cy = (cv_rect.bottom - cv_rect.top) / 2;
		
		var x = mx - (cv_rect.left + cx);
		var y = 100;
		
		// считаем угол наклона линии
		var deg = (Math.atan2(y, x) + Math.PI / 4 * 3) % (Math.PI * 2);
		var d = Math.min(shadow.max, Math.max(shadow.min, 315 - deg / Math.PI * 180));
		
		// линия, которую нужно нарисовать
		var line = calculateLine(d);
		
//		ca1.moveTo(line[0]);
//		ca1.lineTo(line[line.length - 1]);
//		ca1.draw();
//		
//		return;
		
		ca1.clear();
		ca2.clear();
		
		// у гребаной Оперы конкретно сносит башню, если пытаемся очистить canvas
		// у которого задана маска. Приходится каждый раз ее заново рисовать
		if ($.browser.opera)
			drawMask();
		
		ca1.moveTo(line[0]);
		ca2.moveTo(line[0]);
		for (var i = 1; i < line.length; i++) {
			var p = line[i];
			if ('cp1x' in p) {
				ca1.bezierTo(p)
			} else {
				ca1.lineTo(p);
			}
		}
		ca2.lineTo(line[line.length - 1]);
		ca1.draw();
		ca2.draw();
		
//		return;
		
		// рисуем перекладину
		var last_point = line[line.length - 1],
			first_point = line[0];
		
		var line_y = 105;
		var line_x = (cv_rect.bottom - line_y) / (d / 180 * Math.PI);
		
		var intersection = lineIntersection(0, line_y, 1000, line_y, last_point.x, last_point.y, first_point.x, first_point.y);
			
		var ca = ca2;
		
		if ($.browser.msie) {
			ca = ca1;
			ca.ctx.save();
			ca.ctx.globalAlpha = 1;
		} else {
			ca.ctx.save();
		}
			
		ca.ctx.transform(1, 0, (d - 90) / 50, 1, intersection.x - 125, intersection.y);
		ca.ctx.fillRect(0, 0, 250, 10);
		ca.ctx.restore();
		
		shadow_cutter.height(last_point.y + 10);
	}
	
	$(window).resize(function(){
		cv_rect = $(ca1.getElement()).offset();
		cv_rect.right = cv_rect.left + ca1.width();
		cv_rect.bottom = cv_rect.top + ca1.height();
	}).resize();


	$(document).mousemove(function(/* Event */ evt) {
		drawShadowLine(evt.pageX, evt.pageY);
		evt.stopPropagation();
	});
	
	drawShadowLine(0, 400);
});


