/**
 * @projectDescription
 * Подсвечивает ссылки навигации при ховере ссылок контента, анимирует масштабирование
 * картинок при ховере.
 *
 * @author Vlad Yakovlev (scorpix@design.ru)
 * @copyright Art.Lebedev Studio (http://www.artlebedev.ru)
 * @version 0.1 (21.11.2008)
 * @requires jQuery 1.2
 * @requires jTweener 0.2
 * @requires hoverNavigation
 */

/**
 * Аниматор ховеров ссылок.
 * @param {Object} inOptions Настройки:
 * <ul>
 *  <li><code>imageSrc</code> - путь к изображениям,</li>
 *  <li><code>sections</code> - параметры изображений в секциях:
 *   <ul>
 *    <li><code>left</code> - смещение изображения в файле изображения от левого края в пикселях,</li>
 *    <li><code>height</code> - высота изображения в пикселях,</li>
 *    <li><code>width</code> - ширина изображения в пикселях,</li>
 *   </ul>
 *  </li>
 *  <li><code>animationTime</code> - время анимации масштабирования изображения в секундах (по умолчанию - <code>0.6</code>, необязательный параметр),</li>
 *  <li><code>className</code> - название html класса Canvas/VML элемента (по умолчанию - <code>shape</code>, необязательный параметр),</li>
 *  <li><code>hoverColor</code> - цвет ссылок навигации при ховере (по умолчанию - <code>#fff</code>, необязательный параметр),</li>
 *  <li><code>parentClassName</code> - название html класса блока-родителя Canvas/VML элемента после добавления (по умолчанию - <code>parent_shape</code>, необязательный параметр),</li>
 *  <li><code>scale</code> - процент масштабирования изображений при ховере, полный размер равен <i>100 + <code>scale</code></i> (по умолчанию - <code>15</code>, необязательный параметр).</li>
 * </ul>
 */
var pageLinks = (function(inOptions) {

	/**
	 * Настройки объекта. Сначала в нем хранятся настройки по умолчанию. В дальнейшем модифицируется.
	 */
	var options = {
		animationTime: 0.6,
		className: 'shape',
		hoverColor: '#fff',
		parentClassName: 'parent_shape',
		scale: 15
	};

	/**
	 * jQuery элементы.
	 */
	var blocks = {};

	/**
	 * Сопоставляет адрес ссылки с индексом из списка элементов навигации.
	 */
	var linksByHref = {};

	/**
	 * Сопоставляет адрес ссылки главной навигации с типом секции.
	 */
	var sectionsByHref = {};

	/**
	 * Хранит информацию обо всех секциях:
	 * <ul>
	 *  <li><code>links</code> - jQuery объект ссылки,</li>
	 *  <li><code>animator</code> - объект аниматора.</li>
	 * </ul>
	 */
	var sections = {};

	/**
	 * Флаг загрузки файла изображения с изображениями секций.
	 */
	var isImageLoaded = false;

	/**
	 * Флаг загрузки документа.
	 */
	var isDocumentLoaded = false;

	loadOptions();

	/**
	 * Объект изображения.
	 */
	var image = new Image();

	image.onload = function() {
		isImageLoaded = true;

		if (isDocumentLoaded) {
			init();
		}
	}
	image.src = options.imageSrc;

	// В IE для VML надо добавить схему и стили.
	if ($.browser.msie && !document.namespaces['v']) {
		document.namespaces.add('v', 'urn:schemas-microsoft-com:vml');
		var ss = document.createStyleSheet();
		ss.cssText = 'v\\:* {behavior:url(#default#VML);display:block;}';
	}

	$(function() {
		blocks = {
			sections: $('#content .section'),
			navLinks: $('#main_navigation li a')
		};

		blocks.navLinks.each(function(index) {
			linksByHref[$(this).attr('href')] = index;
		});

		isDocumentLoaded = true;

		if (isImageLoaded) {
			init();
		}
	});

	/**
	 * Заменяет настройки по умолчанию настройками из входных данных.
	 */
	function loadOptions() {
		for (var name in inOptions) {
			options[name] = inOptions[name];
		}
	}

	/**
	 * Инициализация работы объекта. Запускается после загрузки документа и изображения.
	 */
	function init() {
		blocks.sections.each(function() {
			/** @type {String} */
			var type = getType($(this).attr('class'));
			/** @type {Object} */
			var params;

			// Если есть параметры изображения, значит, оно будет масштабироваться.
			if (options.sections[type]) {
				params = {
					animationTime: options.animationTime,
					className: options.className,
					image: image,
					imageParams: options.sections[type],
					parent: $(this).find('.image'),
					parentClassName: options.parentClassName,
					scale: (100 + options.scale) / 100
				};
			}

			sections[type] = {
				link: $(this).find('a'),
				animator: params ? new Animator(params) : null
			};

			/** @type {String} */
			var href = sections[type].link.attr('href');

			sectionsByHref[href] = type;

			// События для ховера на ссылке секции
			sections[type].link.hover(function() {
				if (sections[type].animator) {
					sections[type].animator.hoverIn();
				}

				if (undefined !== linksByHref[href]) {
					hoverNavigation.show(href);
					blocks.navLinks.eq(linksByHref[href]).css('color', options.hoverColor);
				}
			}, function() {
				if (sections[type].animator) {
					sections[type].animator.hoverOut();
				}

				if (undefined !== linksByHref[href]) {
					hoverNavigation.hide(href);
					blocks.navLinks.eq(linksByHref[href]).css('color', '');
				}
			});
		});

		blocks.navLinks.each(function() {
			/** @type {String} */
			var href = $(this).attr('href');

			if (undefined !== sectionsByHref[href]) {
				/** @type {String} */
				var type = sectionsByHref[href];

				// События для ховера на ссылке главной навигации
				$(this).hover(function() {
					if (sections[type].animator) {
						sections[type].animator.hoverIn();
					}
				}, function() {
					if (sections[type].animator) {
						sections[type].animator.hoverOut();
					}
				});
			}
		});
	}

	/**
	 * Возвращает тип секции по ее html классу.
	 * @param {String} classesPlain Классы элемента в виде строки.
	 * @return {String} Тип секции.
	 */
	function getType(classesPlain) {
		/** @type {Array} */
		var classes = classesPlain.split(' ');

		return classes[1] ? classes[1] : '';
	}

	/**
	 * Объект анимации масштабирования изображений.
	 * @param {Object} options Настройки:
	 * <ul>
	 *  <li><code>animationTime</code> - время анимации масштабирования в секундах,</li>
	 *  <li><code>className</code> - название html класса Canvas/VML элемента,</li>
	 *  <li><code>image</code> - объект изображения,</li>
	 *  <li><code>imageParams</code> - параметры изображения:
	 *   <ul>
	 *    <li><code>left</code> - смещение изображения в файле изображения от левого края в пикселях,</li>
	 *    <li><code>height</code> - высота изображения в пикселях,</li>
	 *    <li><code>width</code> - ширина изображения в пикселях,</li>
	 *   </ul>
	 *  </li>
	 *  <li><code>parent</code> - блок-родитель для Canvas/VML элемента,</li>
	 *  <li><code>parentClassName</code> - название html класса блока-родителя Canvas/VML элемента после добавления,</li>
	 *  <li><code>scale</code> - коэффициент масштабирования изображения (>1).</li>
	 * </ul>
	 * @return {Animator}
	 */
	function Animator(options) {
		var params = {
			animationTime: options.animationTime,
			className: options.className,
			image: options.image,
			imageParams: options.imageParams,
			parent: options.parent,
			parentClassName: options.parentClassName,
			scale: options.scale
		};

		/**
		 * Адаптер для Canvas и VML.
		 * @type {CanvasAdapter|VmlAdapter}
		 */
		var adapter = $.browser.msie ? new VmlAdapter(params) : new CanvasAdapter(params);

		/**
		 * Ширина (<code>width</code>) и высота (<code>height</code>) немасштабированного изображения (пришло-то типо масштабированное уже).
		 */
		var normalSize = {
			height: Math.round(options.imageParams.height / options.scale),
			width: Math.round(options.imageParams.width / options.scale)
		};


		/**
		 * Событие при наведении курсора мыша на ссылку. Анимирует масштабирование изображения.
		 */
		this.hoverIn = function() {
			jTweener.removeTween(options.parent);

			/** @type {Object} */
			var startSize = adapter.getCanvasSize();
			var finishSize = {
				height: options.imageParams.height,
				width: options.imageParams.width
			};

			jTweener.addTween(options.parent, {
				time: options.animationTime,
				moveX: function(value) {
					var curSize = {
						height: Math.round(startSize.height + value * (finishSize.height - startSize.height)),
						width: Math.round(startSize.width + value * (finishSize.width - startSize.width))
					};
					var pos = {
						left: Math.round((normalSize.width - curSize.width) / 2),
						top: normalSize.height - curSize.height
					};

					adapter.step({
						height: curSize.height,
						left: pos.left,
						top: pos.top,
						width: curSize.width
					});
				}
			});
		};

		/**
		 * Событие при отведении :) курсора мыша на ссылку. Анимирует масштабирование изображения.
		 */
		this.hoverOut = function() {
			jTweener.removeTween(options.parent);

			/** @type {Object} */
			var startSize = adapter.getCanvasSize();
			var finishSize = {
				height: normalSize.height,
				width: normalSize.width
			};

			jTweener.addTween(options.parent, {
				time: options.animationTime,
				moveX: function(value) {
					var curSize = {
						height: Math.round(startSize.height + value * (finishSize.height - startSize.height)),
						width: Math.round(startSize.width + value * (finishSize.width - startSize.width))
					};
					var pos = {
						left: Math.round((normalSize.width - curSize.width) / 2),
						top: normalSize.height - curSize.height
					};

					adapter.step({
						height: curSize.height,
						left: pos.left,
						top: pos.top,
						width: curSize.width
					});

					if (0 == Math.floor(Math.random() * 5) % 4) {
						$('#scroller').css('visibility', 'hidden').css('visibility', '');
					}
				},
				onComplete: function() {
					$('#scroller').css('visibility', 'hidden').css('visibility', '');
				}
			});
		};
	}

	/**
	 * Vml адаптер для аниматора.
	 * @param {Object} options Настройки:
	 * <ul>
	 *  <li><code>animationTime</code> - время анимации масштабирования в секундах,</li>
	 *  <li><code>className</code> - название html класса Canvas/VML элемента,</li>
	 *  <li><code>image</code> - объект изображения,</li>
	 *  <li><code>imageParams</code> - параметры изображения:
	 *   <ul>
	 *    <li><code>left</code> - смещение изображения в файле изображения от левого края в пикселях,</li>
	 *    <li><code>height</code> - высота изображения в пикселях,</li>
	 *    <li><code>width</code> - ширина изображения в пикселях,</li>
	 *   </ul>
	 *  </li>
	 *  <li><code>parent</code> - блок-родитель для Canvas/VML элемента,</li>
	 *  <li><code>parentClassName</code> - название html класса блока-родителя Canvas/VML элемента после добавления,</li>
	 *  <li><code>scale</code> - коэффициент масштабирования изображения (>1).</li>
	 * </ul>
	 * @return {VmlAdapter}
	 */
	function VmlAdapter(options) {

		/**
		 * Ширина (<code>width</code>) и высота (<code>height</code>) немасштабированного изображения (пришло-то типо масштабированное уже).
		 */
		var normalSize = {
			height: Math.round(options.imageParams.height / options.scale),
			width: Math.round(options.imageParams.width / options.scale)
		};

		/**
		 * Ширина (<code>width</code>) и высота (<code>height</code>) полного изображения.
		 */
		var imageSize = {
			height: options.image.height,
			width: options.image.width
		};

		/** @type {jQuery} */
		var canvas = document.createElement('v:image');

		canvas.style.width = normalSize.width + 'px';
		canvas.style.height = normalSize.height + 'px';
		canvas.src = options.image.src;
		canvas.cropleft = options.imageParams.left / imageSize.width;
		canvas.croptop = 0;
		canvas.cropright = (imageSize.width - options.imageParams.left - options.imageParams.width) / imageSize.width;
		canvas.cropbottom = (imageSize.height - options.imageParams.height) / imageSize.height;
		canvas = $(canvas);
		canvas.appendTo(options.parent);
		options.parent.addClass(options.parentClassName).find('img').remove();


		/**
		 * Возвращает размеры Vml блока.
		 * @return {Object} Ширина (<code>width</code>) и высота (<code>height</code>) блока.
		 */
		this.getCanvasSize = function() {
			return {
				height: parseInt(canvas.css('height')),
				width: parseInt(canvas.css('width'))
			};
		};

		/**
		 * Модификация блока за один шаг анимации.
		 * @param {Object} params Параметры изображения:
		 * <ul>
		 *  <li><code>left</code> - смещение от левой границы в пикселях,</li>
		 *  <li><code>top</code> - смещение от верхней границы в пикселях,</li>
		 *  <li><code>height</code> - высота изображения,</li>
		 *  <li><code>width</code> - ширина изображения.</li>
		 * </ul>
		 */
		this.step = function(params) {
			canvas.css({
				width: params.width,
				height: params.height
			});
			options.parent.css({
				marginLeft: params.left,
				marginTop: params.top
			});
		};
	}

	/**
	 * Canvas адаптер для аниматора.
	 * @param {Object} options Настройки:
	 * <ul>
	 *  <li><code>animationTime</code> - время анимации масштабирования в секундах,</li>
	 *  <li><code>className</code> - название html класса Canvas/VML элемента,</li>
	 *  <li><code>image</code> - объект изображения,</li>
	 *  <li><code>imageParams</code> - параметры изображения:
	 *   <ul>
	 *    <li><code>left</code> - смещение изображения в файле изображения от левого края в пикселях,</li>
	 *    <li><code>height</code> - высота изображения в пикселях,</li>
	 *    <li><code>width</code> - ширина изображения в пикселях,</li>
	 *   </ul>
	 *  </li>
	 *  <li><code>parent</code> - блок-родитель для Canvas/VML элемента,</li>
	 *  <li><code>parentClassName</code> - название html класса блока-родителя Canvas/VML элемента после добавления,</li>
	 *  <li><code>scale</code> - коэффициент масштабирования изображения (>1).</li>
	 * </ul>
	 * @return {CanvasAdapter}
	 */
	function CanvasAdapter(options) {

		/**
		 * Ширина (<code>width</code>) и высота (<code>height</code>) немасштабированного изображения (пришло-то типо масштабированное уже).
		 */
		var normalSize = {
			height: Math.round(options.imageParams.height / options.scale),
			width: Math.round(options.imageParams.width / options.scale)
		};

		/** @type {jQuery} */
		var canvas = $('<canvas class="' + options.className + '"></canvas>').appendTo(options.parent);

		var ctx = canvas.get(0).getContext('2d');

		canvas.attr({
			height: normalSize.height,
			width: normalSize.width
		});

		ctx.drawImage(options.image, options.imageParams.left, 0, options.imageParams.width, options.imageParams.height, 0, 0, normalSize.width, normalSize.height);
		options.parent.addClass(options.parentClassName).find('img').remove();


		/**
		 * Возвращает размеры Canvas блока.
		 * @return {Object} Ширина (<code>width</code>) и высота (<code>height</code>) блока.
		 */
		this.getCanvasSize = function() {
			return {
				height: canvas.attr('height'),
				width: canvas.attr('width')
			};
		};

		/**
		 * Модификация блока за один шаг анимации.
		 * @param {Object} params Параметры изображения:
		 * <ul>
		 *  <li><code>left</code> - смещение от левой границы в пикселях,</li>
		 *  <li><code>top</code> - смещение от верхней границы в пикселях,</li>
		 *  <li><code>height</code> - высота изображения,</li>
		 *  <li><code>width</code> - ширина изображения.</li>
		 * </ul>
		 */
		this.step = function(params) {
			canvas.attr({
				width: params.width,
				height: params.height
			}).css({
				left: params.left,
				top: params.top
			});
			ctx.drawImage(options.image, options.imageParams.left, 0, options.imageParams.width, options.imageParams.height, 0, 0, params.width, params.height);
		};
	}
});