/**
 * @projectDescription
 * Производит сортировку списка квартир и анимирует ее, а также следит за тем, чтобы панель
 * выбора сортировки всегда была в верхней части окна браузера.
 *
 * @author Vlad Yakovlev (scorpix@design.ru)
 * @copyright Art.Lebedev Studio (http://www.artlebedev.ru)
 * @version 0.1 (01.11.2008)
 * @requires jQuery 1.2
 * @requires jTweener 0.2
 * @requires ImageSelector
 */
$(function() {

	/**
	 * Элементы jQuery.
	 * @type {Object}
	 */
	var blocks = {
		win: $(window),
		scroller: $('#scroller'),
		scrollerContainer: $('#scroller_container'),
		flatsBlock: $('#flats .list'),
		flats: $('#flats .list .row'),
		// Исходный блок панели сортировок.
		sectionsBlockRoot: $('#flats .flats_sort'),
		// Исходные блоки типов сортировки.
		sectionsRoot: $('#flats .flats_sort li.corner'),
		// Скопированный в body блок панели сортировок.
		sectionsBlock: null,
		// Скопированные в body блоки типов сортировки.
		sections: null
	};

	/**
	 * Массив объектов, каждый из которых хранит jQuery экземпляр квартирного блока и значения,
	 * по которым производится сортировка.
	 */
	var flats = [];

	/**
	 * Массив типов сортировки (заполняется из блоков <code>blocks.sectionsRoot</code>).
	 */
	var sortTypes = [];

	/**
	 * Хранит позиции квартир всех сортировок.
	 */
	var sortPositions = {};

	/**
	 * "Отмеченная" сортировка.
	 */
	var curType = '';

	/**
	 * Смещение исходной панели фильтров от верха документа в пикселях.
	 * @type {Number}
	 */
	var offsetTop;

	/**
	 * Высота окна браузера в пикселях.
	 */
	var winHeight;

	/**
	 * Префикс типа сортировки для html атрибута <code>class</code>.
	 */
	var prefixType = 'type_';

	/**
	 * Namespace для jTweener. Необходим для сортировки группы объектов.
	 */
	var ns = 'flatsAnimating';

	/**
	 * Флаг видимости новой (фиксированной) панели фильтров.
	 */
	var isVisible = false;

	/**
	 * Флаг анимации. Не дышать.
	 */
	var isAnimate = false;

	blocks.win.load(function() {
		onResize();
		onScroll();
	}).resize(onResize);
	blocks.scroller.scroll(onScroll);

	init();

	/**
	 * Инициализация скрипта для осуществления сортировки.
	 */
	function init() {
		// Копируем блок панели сортировок в <code>body</code> для возможности ее показа при вертикальном скроллинге.
		blocks.sectionsBlock = blocks.sectionsBlockRoot.clone();
		blocks.sectionsBlock.appendTo('body').addClass('hidden');
		blocks.sections = blocks.sectionsBlock.find('li.corner');

		fillFlats();
		jTweener.addNSAction({ onComplete: finishAnimateSort }, ns);

		// Вешаем события выбора способа сортировки на обе панели.
		blocks.sections.click(onChangeType);
		blocks.sectionsRoot.click(onChangeType);
	}

	/**
	 * Заполняет переменные данными из html для осуществления сортировок.
	 */
	function fillFlats() {
		// Заполняем массив типов сортировки.
		blocks.sectionsRoot.each(function() {
			/** @type {String} */
			var type = getType($(this).attr('class'));

			sortTypes.push(type);

			if ($(this).hasClass('selected')) {
				curType = type;
			}
		});

		for (var i = 0; i < sortTypes.length; i++) {
			sortPositions[sortTypes[i]] = [];
		}

		// Заполняем массив объектов квартир.
		blocks.flats.each(function(index) {
			var params = { block: $(this) };

			for (var i = 0; i < sortTypes.length; i++) {
				params[sortTypes[i]] = getFloat($(this).find('.sort_data .' + prefixType + sortTypes[i]).text());
				sortPositions[sortTypes[i]].push(index);
			}

			flats.push(params);
		});

		// Сортируем индексы квартир в зависимости от типа сортировки по квартирам.
		for (var i = 0; i < sortTypes.length; i++) {
			/** @type {String} */
			var sortType = sortTypes[i];

			for (var ii = sortPositions[sortType].length - 1; ii > 0; ii--) {
				for (var iii = 0; iii < ii; iii++) {
					if (flats[sortPositions[sortType][iii]][sortType] > flats[sortPositions[sortType][iii + 1]][sortType]) {
						/** @type {Number} */
						var tempVar = sortPositions[sortType][iii];
						sortPositions[sortType][iii] = sortPositions[sortType][iii + 1];
						sortPositions[sortType][iii + 1] = tempVar;
					}
				}
			}
		}
	}

	/**
	 * Событие при изменении размеров окна браузера.
	 */
	function onResize() {
		winHeight = blocks.win.height();
		blocks.sectionsBlock.width(blocks.scrollerContainer.width());
		offsetTop = blocks.sectionsBlockRoot.offset().top - blocks.scrollerContainer.offset().top;
	}

	/**
	 * Событие при скролировании окна браузера.
	 */
	function onScroll() {
		/** @type {Number} */
		var scrollTop = blocks.scroller.scrollTop();

		if (scrollTop > offsetTop && !isVisible) {
			blocks.sectionsBlock.removeClass('hidden');
			isVisible = true;
		} else if (scrollTop < offsetTop && isVisible) {
			blocks.sectionsBlock.addClass('hidden');
			isVisible = false;
		}
	}

	/**
	 * Событие при выборе способа сортировки.
	 */
	function onChangeType() {
		if (isAnimate) {
			return;
		}

		/** @type {String} */
		var type = getType($(this).attr('class'));

		// Данный способ сортировки является текущим - сортировать нечего.
		if (curType == type) {
			return;
		}

		// В панели способов сортировки меняем текущую сортировку.
		blocks.sections.filter('.' + prefixType + curType).removeClass('selected');
		blocks.sectionsRoot.filter('.' + prefixType + curType).removeClass('selected');
		blocks.sections.filter('.' + prefixType + type).addClass('selected');
		blocks.sectionsRoot.filter('.' + prefixType + type).addClass('selected');

		// Поехали :)
		animateSort(curType, type);
		curType = type;
	}

	/**
	 * Сортирует квартиры в зависимости от пожелния юзера.
	 * @param {String} oldType Текущий тип сортировки.
	 * @param {String} newType Тип сортировки, которую выбрал юзер.
	 */
	function animateSort(oldType, newType) {
		isAnimate = true;

		/** @type {Number} */
		var flatsBlockHeight = blocks.flatsBlock.outerHeight();
		/** @type {Number} */
		var flatHeight = blocks.flats.eq(0).outerHeight();
		/** @type {Number} */
		var flatsBlockOffsetTop = blocks.flatsBlock.offset().top;

		/**
		 * Минимальный (<code>min</code>) и максимальный (<code>max</code>) индексы анимируемых квартир.
		 */
		var visibleFlats = {
			min: 0 > flatsBlockOffsetTop ? Math.floor(-flatsBlockOffsetTop / flatHeight) : 0,
			max: Math.ceil((winHeight - flatsBlockOffsetTop) / flatHeight)
		};

		if (visibleFlats.max > blocks.flats.size()) {
			visibleFlats.max = blocks.flats.size();
		}

		/**
		 * Хранит в свойствах индекс <code>flats</code>, а в значении - индекс из массива <code>sortPositions</code>.
		 */
		var oldIndexes = {};
		/**
		 * Хранит в свойствах индекс <code>flats</code>, а в значении - индекс из массива <code>sortPositions</code>.
		 */
		var newIndexes = {};

		for (var i = 0; i < sortPositions[oldType].length; i++) {
			oldIndexes[sortPositions[oldType][i]] = i;
		}

		for (var i = 0; i < sortPositions[newType].length; i++) {
			newIndexes[sortPositions[newType][i]] = i;
		}

		/**
		 * Массив индексов анимируемых квартир.
		 */
		var animateIndexes = [];

		for (var i = 0; i < flats.length; i++) {
			if (!(
				(oldIndexes[i] < visibleFlats.min && newIndexes[i] < visibleFlats.min) ||
				(oldIndexes[i] > visibleFlats.max && newIndexes[i] > visibleFlats.max)
			)) {
				animateIndexes.push(i);
			}
		}

		// Выставляем высоты для блока квартир и самих квартир, позиционируем квартиры абсолютно для перемения.
		blocks.flatsBlock.css('height', flatsBlockHeight);

		for (var i = sortPositions[oldType].length - 1; i >= 0; i--) {
			var curIndex = sortPositions[oldType][i];

			flats[curIndex].block.css({
				position: 'absolute',
				height: flatHeight,
				top: i * flatHeight
			});
		}

		for (var i = 0; i < animateIndexes.length; i++) {
			var flatIndex = animateIndexes[i];

			jTweener.addTween(flats[flatIndex].block, {
				top: newIndexes[flatIndex] * flatHeight,
				delay: Math.random() * 0.2,
				time: 0.6,
				transition: 'easeinoutcubic',
				namespace: ns // По окончании нам еще надо переместить html блоки и убрать абсолютное позиционирование.
			});
		}
	}

	/**
	 * Производит действия по завершении анимации сортировки.
	 */
	function finishAnimateSort() {
		// Перемещаем html блоки в таком порядке, в котором они отсортировались.
		for (var i = 0; i < sortPositions[curType].length; i++) {
			/** @type {Number} */
			var curIndex = sortPositions[curType][i];

			blocks.flatsBlock.append(flats[curIndex].block);
		}

		// Очищаем выставленные css свойства.
		blocks.flats.css({
			position: '',
			height: '',
			top: ''
		});
		blocks.flatsBlock.css('height', '');

		isAnimate = false;
	}

	/**
	 * Возвращает тип сортировки, фильтруя его из названия класса.
	 * @param {String} classesPlain Значение html атрибута <code>class</code>.
	 * @return {String} Идентификатор способа сортировки.
	 */
	function getType(classesPlain) {
		/** @type {Array} */
		var classes = classesPlain.split(' ');

		for (var i = 0; i < classes.length; i++) {
			if (prefixType == classes[i].substr(0, prefixType.length)) {
				return classes[i].substr(prefixType.length);
			}
		}

		return '';
	}

	function getFloat(str) {
		return parseFloat(str.replace(',', '.'));
	}
});

var flatsSelector = (function() {
	var prefix = 'flat_';

	var floorSelectorParams = [];

	$('#flats .list .row').each(function() {
		var el = $(this);
		var params = getParams(el.attr('class'));
		params.container = el.find('.house_icon');

		floorSelectorParams.push(params);
	});

	floorSelector(floorSelectorParams);

	function getParams(classesPlain) {
		var classes = classesPlain.split(' ');

		for (var i = 0; i < classes.length; i++) {
			if (prefix == classes[i].substr(0, prefix.length)) {
				var params = classes[i].substr(prefix.length).split('_');

				return {
					building: parseInt(params[0]),
					floor: parseInt(params[1])
				};
			}
		}

		return false;
	}
});
