/**
 * @author Vlad Yakovlev (scorpix@design.ru)
 * @copyright Art.Lebedev Studio (http://www.artlebedev.ru)
 * @version 0.1
 * @date 2009-09-09
 * @requires jQuery
 * @requires jTweener
 * @requires swfobject 2.1
 * @requires jCommon
 */

/**
 * Объект для анимации видео-роликов.
 */
function VideoManager() {

	var
		/** Максимальные ограничения в пикселях для блоков для хаоса. */
		assumption = { x: 20, y: 20 },
		/** Расстояния, на которые разлетаются блоки, если рядом выбрано видео. */
		fly = { x: 50, y: 50 },
		/** Границы флэш-плеера. */
		playerBorder = { x: 0, y: 53 },
		/** Количество рядов. */
		cols = 3,

		animateNs = 'video_animate',

		tweenParams = {
			time: 1,
			namespace: animateNs
		},
		/**
		 * Блок видео.
		 * @type {jQuery}
		 */
		rootBlock,
		/** @type {jQuery} */
		pictures,
		/** @type {jQuery} */
		itemBlocks,
		/** Объекты, хранящие характеристики видео-блоков. */
		items = [],
		/**
		 * Ширина маленького блока.
		 * @type {Number}
		 */
		itemSmallWidth,
		/**
		 * Высота маленького блока.
		 * @type {Number}
		 */
		itemSmallHeight,
		/**
		 * Ширина большого блока.
		 * @type {Number}
		 */
		itemWidth,
		/**
		 * Высота большого блока.
		 * @type {Number}
		 */
		itemHeight,
		/**
		 * Ширина корневого блока.
		 * @type {Number}
		 */
		rootBlockWidth,
		/**
		 * Количество строк.
		 * @type {Number}
		 */
		rows,
		/** Индекс текущего блока. */
		curIndex = -1,
		/** Флаг анимации. */
		isAnimate = false,
		/**
		 * Блок контейнера флэш-плеера.
		 * @type {jQuery}
		 */
		playerContainerBlock,
		/**
		 * Блок флэш-плеера.
		 * @type {Element}
		 */
		playerBlock,
		/**
		 * Путь к флэш-плееру.
		 * @type {String}
		 */
		player,
		/**
		 * Путь к скину флэш-плеера.
		 * @type {String}
		 */
		playerSkin,
		/**
		 * Путь к стилям флэш-плеера.
		 * @type {String}
		 */
		playerCss,
		/**
		 * Путь к плейлисту флэш-плеера.
		 * @type {String}
		 */
		playerXml,

		isPlayerInited = false,

		that = {};

	that.init = function() {
		rootBlock = $('#main_content .video');
		pictures = rootBlock.find('.picture');
		itemBlocks = rootBlock.find('.item');

		// Получаем размеры маленького и большого блока.
		itemWidth = pictures.eq(0).outerWidth();// + playerBorder.x;
		itemHeight = pictures.eq(0).outerHeight();// + playerBorder.y;
		rootBlock.addClass('video_inited');
		itemSmallWidth = pictures.eq(0).outerWidth();
		itemSmallHeight = pictures.eq(0).outerHeight();
		rootBlockWidth = rootBlock.width();

		setPositions();
		playerInit();

		jTweener.addNSAction({
			onComplete: function() {
				isAnimate = false;
			}
		}, animateNs);
	};

	function load() {
		itemBlocks.each(function(index) {
			$(this).click(function() {
				index == curIndex || isAnimate || select(index);
			});
		});
		$('#main_content .opback').fadeOut(500, function() {
			$('#main_content .opback').remove();
		});

		// Показываем ролик.
		var path = location.href.split('#');
		var prefix = 'video';

		if (path[1] && prefix == path[1].substr(0, prefix.length)) {
			var firstIndex = parseInt(path[1].substr(prefix.length));

			if (0 <= firstIndex && firstIndex < items.length - 1) {
				select(firstIndex);
			}
		}
	}

	/**
	 * Инициализирует положение видео-блоков.
	 */
	function setPositions() {

		var
			/** @type {Number} */
			wX = Math.floor(rootBlockWidth / cols),
			/** @type {Number} */
			wY = Math.floor(itemHeight * 6 / 7),
			/**
			 * Количество полных строк по cols рядов.
			 * @type {Number}
			 */
			fullRows = (Math.ceil(itemBlocks.size() / cols / 2) - 1) * 2,
			/**
			 * Количество блоков, которые надо выстраивать пирамидкой.
			 * @type {Number}
			 */
			itemsCount = itemBlocks.size() - fullRows * cols,
			/** Количество элементов в полных строках. */
			countInFullRows = fullRows * cols;

		rows = fullRows;

		if (3 < itemsCount) {
			rows += 3;
		} else if (1 < itemsCount) {
			rows += 2;
		} else {
			rows += 1;
		}

		rootBlock.height(wY * rows);

		for (var i = 0; i < itemBlocks.size(); i++) {
			items.push({
				image: new PictureShape(pictures.eq(i), 10, itemSmallWidth, itemSmallHeight, itemWidth, itemHeight)
			});
		}

		// Задаем положения блоков в виртуальной матрице, чтоб по ним определять,
		// какие блоки куда будут разлетаться.
		for (var i = 0; i < countInFullRows; i++) {
			items[i].posX = (i % cols) * 2 + 1;
			items[i].posY = Math.floor(i / cols) * 2 + 1;
		}

		switch (itemsCount) {
			case 1:
				items[countInFullRows].posX = 3;
				items[countInFullRows].posY = (fullRows) * 2 + 1;

				break;

			case 2:
				items[countInFullRows].posX = 3;
				items[countInFullRows].posY = (fullRows) * 2 + 1;
				items[countInFullRows + 1].posX = 3;
				items[countInFullRows + 1].posY = (fullRows + 1) * 2 + 1;

				break;

			case 3:
				items[countInFullRows].posX = 2;
				items[countInFullRows].posY = (fullRows) * 2 + 1;
				items[countInFullRows + 1].posX = 4;
				items[countInFullRows + 1].posY = (fullRows) * 2 + 1;
				items[countInFullRows + 2].posX = 3;
				items[countInFullRows + 2].posY = (fullRows + 1) * 2 + 1;

				break;

			case 4:
				items[countInFullRows].posX = 2;
				items[countInFullRows].posY = (fullRows) * 2 + 1;
				items[countInFullRows + 1].posX = 4;
				items[countInFullRows + 1].posY = (fullRows) * 2 + 1;
				items[countInFullRows + 2].posX = 3;
				items[countInFullRows + 2].posY = (fullRows + 1) * 2 + 1;
				items[countInFullRows + 3].posX = 3;
				items[countInFullRows + 3].posY = (fullRows + 2) * 2 + 1;

				break;

			case 5:
				items[countInFullRows].posX = 2;
				items[countInFullRows].posY = (fullRows) * 2 + 1;
				items[countInFullRows + 1].posX = 4;
				items[countInFullRows + 1].posY = (fullRows) * 2 + 1;
				items[countInFullRows + 2].posX = 2;
				items[countInFullRows + 2].posY = (fullRows + 1) * 2 + 1;
				items[countInFullRows + 3].posX = 4;
				items[countInFullRows + 3].posY = (fullRows + 1) * 2 + 1;
				items[countInFullRows + 4].posX = 3;
				items[countInFullRows + 4].posY = (fullRows + 2) * 2 + 1;

				break;

			case 6:
				items[countInFullRows].posX = 1;
				items[countInFullRows].posY = (fullRows) * 2 + 1;
				items[countInFullRows + 1].posX = 3;
				items[countInFullRows + 1].posY = (fullRows) * 2 + 1;
				items[countInFullRows + 2].posX = 5;
				items[countInFullRows + 2].posY = (fullRows) * 2 + 1;
				items[countInFullRows + 3].posX = 2;
				items[countInFullRows + 3].posY = (fullRows + 1) * 2 + 1;
				items[countInFullRows + 4].posX = 4;
				items[countInFullRows + 4].posY = (fullRows + 1) * 2 + 1;
				items[countInFullRows + 5].posX = 3;
				items[countInFullRows + 5].posY = (fullRows + 1) * 2 + 1;

				break;
		}

		for (var i = 0; i < items.length; i++) {
			/** @type {Number} */
			var cX = 0 == items[i].posX % 2
				? Math.floor(items[i].posX / 2 * wX)
				: Math.floor(wX / 2 + (items[i].posX - 1) / 2 * wX);
			/** @type {Number} */
			var cY = Math.floor(wY / 2 + (items[i].posY - 1) / 2 * wY);

			// Положение больших блоков.
			items[i].x = Math.floor(cX - itemWidth / 2);
			items[i].y = Math.floor(cY - itemHeight / 2);

			if (0 > items[i].x) {
				items[i].x = 0;
			} else if (rootBlockWidth < items[i].x + itemWidth) {
				items[i].x = rootBlockWidth - itemWidth;
			}

			// Положение малых блоков.
			items[i].xSmall = Math.round(cX - itemSmallWidth / 2 - assumption.x + Math.random() * 2 * assumption.x);
			items[i].ySmall = Math.round(cY - itemSmallHeight / 2 - assumption.y + Math.random() * 2 * assumption.y);

			// Текущее положение блоков.
			items[i].xCur = items[i].xSmall;
			items[i].yCur = items[i].ySmall;

			itemBlocks.eq(i).css({
				left: items[i].xCur,
				top: items[i].yCur
			});
		}
	}

	/**
	 * Выбирает новый видео-блок.
	 * @param {Number} index Индекс блока.
	 */
	function select(index) {
		isAnimate = true;

		if (-1 < curIndex) {
			itemBlocks.eq(curIndex).removeClass('selected');
			pause(index);
		} else {
			show(index);
		}

		var oldIndex = curIndex;

		for (var i = 0; i < items.length; i++) {

			var
				startWidth,
				startHeight,
				finishWidth,
				finishHeight;

			var params = {
				delay: Math.random() * 0.2
			};

			if (i == index) {
				// Блок, который выбрал юзер.
				params.left = items[i].x;
				params.top = items[i].y;
				params.onComplete = function() {
					itemBlocks.eq(index).addClass('selected');
					curIndex = index;

					/*-1 < oldIndex && */play(index);
				};
				var func = function(i) {
					return function(value) {
						items[i].image.update(itemSmallWidth + (itemWidth - itemSmallWidth) * value, itemSmallHeight + (itemHeight - itemSmallHeight) * value);
					};
				};

				params.moveX = func(i);
			} else {
				// Положение блока по умолчанию.
				params.left = items[i].xSmall;
				params.top = items[i].ySmall;

				if (
					items[i].posX >= items[index].posX - 2 &&
					items[i].posX <= items[index].posX + 2 &&
					items[i].posY >= items[index].posY - 2 &&
					items[i].posY <= items[index].posY + 2
				) {
					// Если блок находится рядом с выбранным, он должен отлететь.
					if (items[i].posY > items[index].posY) {
						params.top += fly.y;
					} else if (items[i].posY < items[index].posY) {
						params.top -= fly.y;
					}

					if (items[i].posX > items[index].posX) {
						params.left += fly.x;
					} else if (items[i].posX < items[index].posX) {
						params.left -= fly.x;
					}
				}

				if (i == curIndex) {
					var func = function(i) {
						return function(value) {
							items[i].image.update(itemSmallWidth + (itemWidth - itemSmallWidth) * (1 - value), itemSmallHeight + (itemHeight - itemSmallHeight) * (1 - value));
						};
					};

					params.moveX = func(i);
				}
			}

			// Убираем из анимации блоки, которые остаются на месте.
			if (items[i].xCur == params.left && items[i].yCur == params.top && i != index && i != curIndex) {
				continue;
			}

			// Запоминаем координаты блока после анимации.
			items[i].xCur = params.left;
			items[i].yCur = params.top;

			jTweener.removeTween(itemBlocks.eq(i));
			$t(itemBlocks.eq(i), tweenParams).tween(params);
		}
	}

	function playerInit() {
		playerContainerBlock = $('<div id="player_container"><div id="player"></div></div>').appendTo(rootBlock).css({
			left: -10000,
			top: -1000
		});

		setTimeout(function() {
			swfobject.embedSWF(player, 'player', itemWidth + playerBorder.x, itemHeight + playerBorder.y, '9.0.0', null, {
				css: playerCss,
				skin: playerSkin,
				playlist: playerXml,
				autoplay: '0',
				cycle: '1'
			}, {
				allowFullscreen: 'true',
				allowScriptAccess: 'always'
			});
		}, 1/*000*/);
	}

	function play(index) {
		if (!isPlayerInited) {
			playerBlock = $('#player').get(0);
			isPlayerInited = true;
		}

		playerBlock.playFlash();
		playerContainerBlock.css({
			left: items[index].x,
			top: items[index].y
		});
	}

	function pause(index) {
		if (!isPlayerInited) {
			playerBlock = $('#player').get(0);
			isPlayerInited = true;
		}

		playerBlock.pauseFlash();
		playerContainerBlock.css({
			left: -10000,
			top: -1000,
			visibility: 'hidden'
		});
		playerBlock.initFlash(index);
	}

	function show(index) {
		if (!isPlayerInited) {
			playerBlock = $('#player').get(0);
			isPlayerInited = true;
		}

//		playerContainerBlock.css({
//			left: items[index].x,
//			top: items[index].y,
//			visibility: ''
//		});
		playerContainerBlock.css({
			left: -10000,
			top: -1000,
			visibility: 'hidden'
		});
		playerBlock.initFlash(index);
	}

	function PictureShape(rootBlock, radius, minWidth, minHeight, maxWidth, maxHeight) {

		var
			/** @type {jQuery} */
			canvas,
			/** @type {CanvasRenderingContext2D} */
			ctx,
			/** @type {Image} */
			image,

			isLoaded = false,

			curWidth = minWidth,

			curHeight = minHeight;

		init();

		function init() {
			var urlRegExp = /^url\([\"\']?([^\'\"]*)[\"]?\)$/i;

			image = new Image();
			image.onload = onLoad;
			image.src = rootBlock.css('background-image').replace(urlRegExp, "$1");

			rootBlock.css('background-image', '');
		}

		function onLoad() {
			jCommon.isCanvas ? createCanvas() : createVml();

			isLoaded = true;
		}

		function createCanvas() {
			canvas = $('<canvas class="shape"></canvas>').appendTo(rootBlock);
			ctx = canvas.get(0).getContext('2d');
			updateCanvas(curWidth, curHeight);
		}

		function updateCanvas(width, height) {
			var curRadius = Math.round((1 - (width - minWidth) / (maxWidth - minWidth)) * radius);

			canvas.attr({
				height: curHeight,
				width: curWidth
			});
			//ctx.globalCompositeOperation = 'source-over';
			ctx.beginPath();

			if (0 < curRadius) {
				ctx.moveTo(curRadius, 0);
				ctx.lineTo(width - curRadius, 0);
				ctx.arc(width - curRadius, curRadius, curRadius, -Math.PI / 2, 0, false);
				ctx.lineTo(width, height - curRadius);
				ctx.arc(width - curRadius, height - curRadius, curRadius, 0, Math.PI / 2, false);
				ctx.lineTo(curRadius, height);
				ctx.arc(curRadius, height - curRadius, curRadius, Math.PI / 2, Math.PI, false);
				ctx.lineTo(0, curRadius);
				ctx.arc(curRadius, curRadius, curRadius, Math.PI, Math.PI * 3 / 2, false);
			} else {
				ctx.moveTo(0, 0);
				ctx.lineTo(width, 0);
				ctx.lineTo(width, height);
				ctx.lineTo(0, height);
				ctx.lineTo(0, 0);
			}

			ctx.clip();
			ctx.closePath();
			//ctx.globalCompositeOperation = 'source-in';
			ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, width, height);
		}

		function createVml() {
			canvas = document.createElement('v:shape');
			$(canvas).addClass('shape vml');
			canvas.style.width = minWidth;
			canvas.style.height = minHeight;
			canvas.coordsize = minWidth + ',' + minHeight;
			canvas.stroked = 'False';

			var fillShape = document.createElement('v:fill');
			$(fillShape).addClass('vml');
			fillShape.color = '#000000';
			fillShape.src = image.src;
			fillShape.type = 'frame';
			$(fillShape).appendTo(canvas);

			canvas = $(canvas).appendTo(rootBlock);
			updateVml(curWidth, curHeight);
		}

		function updateVml(width, height) {
			width = Math.round(width);
			height = Math.round(height);
			var curRadius = Math.round((1 - (width - minWidth) / (maxWidth - minWidth)) * radius);

			canvas.css({
				height: height,
				width: width
			});
			canvas.get(0).coordsize = width + ',' + height;

			if (0 < curRadius) {
				canvas.get(0).path = 'm ' + curRadius + ',0 l ' + (width - curRadius) + ',0 qx ' + width + ',' + curRadius + ' l ' + width + ',' + (height - curRadius) + ' qy ' + (width - curRadius) + ',' + height + ' l ' + curRadius + ',' + height + ' qx 0,' + (height - curRadius) + ' l 0,' + curRadius + ' qy ' + curRadius + ',0';
			} else {
				canvas.get(0).path = 'm 0,0 l ' + width + ',0 l ' + width + ',' + height + ' l 0,' + height + ' l 0,0';
			}
		}

		return {
			update: function(width, height) {
				curWidth = width;
				curHeight = height;

				if (isLoaded) {
					jCommon.isCanvas ? updateCanvas(width, height) : updateVml(width, height);
				}
			},
			getSrc: function() {
				return image.src;
			}
		}
	}

	that.setOptions = function(options) {
		player = options.player;
		playerCss = options.playerCss;
		playerSkin = options.playerSkin;
		playerXml = options.playerXml;
	};

	that.load = load;

	return that;
}

videoManager = new VideoManager();

$(function() {
	videoManager.init();
});

function flashIsReady() {
	videoManager.load();
}