Function.prototype.extend = function(method, fn){
	if (!this[method]) {
		this.prototype[method] = function() {
			return fn.apply(this, arguments);
		}
	}
}


Array.extend("contains", function(x){
	if (!arguments.length) return false;
	for (var i = 0, l = this.length; i < l; ++i) {
		if (this[i] === x) {
			return true;
		}
	}
	return false;
});


/**
 * @include "ictinus-0.3-src.js"
 * @include "niftyplayer.js"
 */

function _empty() {
};
 
if (!Array.prototype.trim) {
	Array.prototype.trim = function() {
		while (!this[0] && this.length) {
			this.shift();
		}
		return this;
	}
}

/**
 * Управление качеством интерполяции изображения
 * 
 * @type Object 
 */
var Grader = {
	/**
	 * SetImageQuality
	 * @param {HTMLImageElement} image
	 * @param {String} quality
	 */
	setImgQ : (function () {
		var fn = function() {};
		switch (true) {
			case $.browser.msie : {
				fn = function(image, quality) {
					image.style.msInterpolationMode = quality;
				}
				break;
			}
			
			default : {
				fn = function(image, quality) {
					image.style.imageRendering = quality;
				}
			}
		}
		return fn;
	})(),
	
	Q_LOW : (function() {
		switch (true) {
			case $.browser.msie : {
				return "nearest-neighbor";
				break;
			}
			
			default : {
				return "optimizeSpeed";
			}
		}
	})(),
	
	Q_HIGH : (function() {
		switch (true) {
			case $.browser.msie : {
				return "bicubic";
				break;
			}
			
			default : {
				return "optimizeQuality";
			}
		}
	})()
}

var clog = window.console && console.log || _empty;

/**
 * Site Helper
 * Реализует то что нельзя, сложно или не хочется реализовывать праведным путем
 * 
 * @constructor
 */
var DolinaHelper = function () {
	var
		T = this,
		viewport = document.getElementById("viewport"),
		frameContainer = document.getElementById("frames"),
		$frameContainer = $(frameContainer),
		$frames = $(".frame", frameContainer),
		$frameBgImages = $(".bg", $frames),
		$window = $(window),
		currentSlide = 0,
		/** @type EventProxy */
		areaProxy,
		state = {animating: false},
		title = "Лариса Долина",
		mouseCoords = {x:0, y:0},
		activeWidget = null,
		overlayContainer = $(".overlays"),
		imgDecorator = null,
		player = null
	;
	
	this.urlFilters = [];
	
	/**
	 * Показ слайда с номерм x
	 * 
	 * @param {String} frameId Идентификатор слайда
	 */
	function showSlide(slideId) {
		var newpos = -viewport.offsetWidth * slideId,
			titleSuffix = $frames[slideId].getAttribute("doc-title") || ""; 
		currentSlide = slideId;
		if (titleSuffix) {
			titleSuffix = " - " + titleSuffix;
		}

		document.title = title + (titleSuffix || "");
		
		$frameContainer.stop();
		$frameContainer.animate({"left" : newpos}, 200, function() {
			state.animating = false;
		});
		state.animating = true;
	}
	
	function updatePPControls() {
		window.ppc = $(".play").add($(".pause"));
	}
	
	/**
	 * Показ оверлея
	 * 
	 * @param {String} overlayId
	 */
	function showWidget(overlayId) {
		var widget = $(document.getElementById(":" + location.pathname + overlayId));
		if (widget.length) { // если есть виджет для отображения
			activeWidget = widget;
			var	bg = $(".background", widget),
				content = $(".overlay-content", widget),
				bgc = $(".bgc", bg),
				animTime = 450;
				overlayContainer.show();
			if (bg.length) {
				content.hide();
				widget.show();
			}
			
			bg.css({
				left: mouseCoords.x,
				top: mouseCoords.y,
				width: 10,
				height: 10
			}).show().animate({
				left: 0,
				top: 0,
				width: "100%",
				height: "100%"
			}, animTime, function(){
				content.css({"visibility": "hidden", "display": "block"});
				if (imgDecorator) {
					$(".puke").each(function(){
						
						//console.log($(this).attr("src").indexOf('image_t.php?image'));
						if (($(this).attr("src").indexOf('image_t.php?image') == -1))
						{
							$(this).attr("src", "http://larisadolina.com/test_pic/image_t.php?image="+$(this).attr("src")+"&w="+$(this).attr("width")+"&h="+$(this).attr("height"));
						}
							
						//$(this).load(function () {
						//	imgDecorator.decorate(this);
						//	});
						//imgDecorator.decorate(this);//old
					});
				}
				$(".photogallery", widget).each(function(){
					new PhotoScroller(this);//old
				});
				content.css({"visibility": "visible", "display": "none"});
				content.fadeIn(animTime);
				syncActiveWidget();
				updatePlayLists();
			})
			bgc.css({
				opacity: 1
			}).animate({
				opacity: 0.84
			}, animTime)
		}
	}
	
	/**
	 * Скрывает активный оверлей
	 */
	function hideActiveWidget() {
		if (activeWidget) {
			if ($.browser.msie | true) {
				var movies = activeWidget.hide().find("object");
				movies.each(function(){
					var newMovie = this.cloneNode(true);
					var parent = this.parentNode; 
					parent.removeChild(this);
					parent.appendChild(newMovie);
				});
				overlayContainer.hide();
			} else {
				activeWidget.fadeOut(function(){
					overlayContainer.hide();
				});
			}
			activeWidget = null;
		}
	}
	
	function runAction(slide, widget, parameters) {
		var prefix = "frame-";
		for (var i = 0, frame; frame = $frames[i]; ++i) {
			if (frame.getAttribute("id") == prefix + slide) {
				showSlide(i);
				break;
			}
		}
		
		if (activeWidget) {
			if (activeWidget.attr("id") != ":/" + widget) {
				// показываем другой виджет
				hideActiveWidget();
				if (parameters && parameters.length > 0) {
					showWidget(widget + "/" + parameters.join("/"));
				} else {
					showWidget(widget);
				}
			} else {
				if (widget == "the-first/smi" || widget == "the-first/news") {
					hideActiveWidget();
					if (parameters && parameters.length > 0) {
						showWidget(widget + "/" + parameters.join("/"));
					} else {
						showWidget(widget);
					}
				}
			}
		} else {
			if (parameters && parameters.length > 0) {
				showWidget(widget + "/" + parameters.join("/"));
			} else {
				showWidget(widget);
			}
		}
		updatePPControls();
	}
	
	/**
	 *  Переключение режима интерполяции фоновых картинок. Я на самом деле
	 *  считаю дизайнера этого сайта полным придурком. Пусть рисует комиксы
	 *  
	 *  @description Устанавливает режим, начиная с текущего показанного слайда
	 */
	function setBgImagesInterpolationMode(mode) {
		var imageIndex = currentSlide,
			imagesCount = $frameBgImages.length,
			i = imagesCount;
		while (i--) {
			Grader.setImgQ($frameBgImages[imageIndex++ % imagesCount], mode);
		}
	}
	
	/**
	 * Размещает слайды относительно viewport 
	 */
	function syncFrames() {
		// останавливаем анимацию если меняются размеры
		if (state.animating) {
			$frameContainer.stop();
		}
		var width = viewport.offsetWidth,
			height = viewport.offsetHeight,
			windowHeight = window.clientHeight || document.documentElement.offsetHeight,
			px = new String("px"); // странная бага в Chrome 5 dev, без new String не работает
		
		frameContainer.style.height = height + px;
		frameContainer.style.width = width * $frames.length + px;
		frameContainer.style.left = -width * currentSlide + px; 

		var top = parseInt((windowHeight - height) / 2);
		viewport.style.top = top > 0 ? top + px : 0;
		
		for (var i = 0, frame, top; frame = $frames[i]; ++i) {
			frame.style.width = width + px;
			frame.style.height = height + px;
			frame.style.left = width * i + px;
		}
	}
	
	/**
	 * Синхронизация активных областей с размером области просмотра
	 */
	function syncAreas() {
		if (areaProxy instanceof EventProxy) {
			var defaultWidth = 1000,
				factor = viewport.offsetWidth / defaultWidth; 
			areaProxy.notifyAll("scale", [factor]);
		}
	}
	
	function syncActiveWidget() {
		if (activeWidget) {
			var scrollPane = $(".scrolled .pane", activeWidget);
			scrollPane.jScrollPane();
		}
	}
	
	function trackMouse(evt) {
		mouseCoords.x = evt.clientX;
		mouseCoords.y = evt.clientY;
	}
	
	/**
	 * Поиск плейлиста в ноде
	 * @param node {Node}
	 */
	function updatePlayLists(node) {
		/**
		 * Фильтр для добавления в плейлист
		 */
		function filter(x) {
			return x;
		}
		
		if (!node) {
			node = document;
		}
		var playlists = $(".playlist", node);
		playlists.unbind("click.play");
		playlists.bind("click.play", function(evt){
			if (evt.target.tagName !== "A") {
				return false;
			}
			var entries = $("a", this),
				playlist = [],
				currentTrackIndex = 0,
				trackNumber = 0;
			for (var i = 0, link, href; link = entries[i]; ++i) {
				href = link.href;
				if (filter(href)) {
					playlist.push(href);
					if (link === evt.target) {
						currentTrackIndex = trackNumber;
					}
					++trackNumber;
				}
			}
			player.playPlaylist(currentTrackIndex, playlist);
			return false;
		});
	}
	
	function applyFilters() {
		for (var filter, i = 0, l = T.urlFilters.length; i < l; ++i) {
			filter = T.urlFilters[i];
			if (filter instanceof Function) {
				filter.apply(activeWidget, arguments);
			}
		}
	}
	
	/**
	 * Инициализация помощника
	 */
	function init() {
		setBgImagesInterpolationMode(Grader.Q_HIGH);
		
		
		$window.resize(function() {
			syncFrames();
			syncAreas();
			syncActiveWidget();
		});
		
		$(window).bind("hashchange", function(evt) {
			T.navigateTo(evt.fragment);
		})
		.trigger("hashchange")
		.bind("keydown", function(evt){
			if (27 === evt.keyCode) {
				// TODO менять hash для скрытия оверлея.
			}
		});
		
		$(document).mousemove(function(evt){
			trackMouse(evt);
		});
		
		$frames.show();
		syncFrames();
		
		// XXX Непонятно зачем это тут:
		// T.navigateTo(location.hash.replace(/^#/, ""));
		if (currentSlide == 0) {
			// TODO тут нужно что-то сделать для красоты
			//document.location.hash = "#/the-first";
		}
		
	}
	
	
	//region public methods
	this.updatePlayLists = updatePlayLists;

	this.getCurrentSlide = function() {
		return currentSlide;
	}
	
	this.syncFrames = function() {
		syncFrames();
	}
	
	/**
	 * @param {EventProxy} areaProxy
	 */
	this.setAreaProxy = function(areaProxyObj) {
		areaProxy = areaProxyObj;
		syncAreas();
	}
	
	this.setImageDecorator = function(obj) {
		if (obj instanceof DolinaImageDecorator) { // зачем это тут?
			imgDecorator = obj;
		}
	}
	
	/**
	 * @param {playerObj} Player()
	 */
	this.setPlayer = function(playerObj){
		var hideTimeout, controls, volDrag;
		if (playerObj instanceof Player) {
			player = playerObj;
			updatePlayLists();
		}
		
		var defaultPlaylist = [];
		$(".playlist:first a").each(function(){
			defaultPlaylist.push(this.href);
		});
		
		player.setPlaylist(defaultPlaylist);
		
		var actions = {
			"prev": function(){
				player.playPrev();
			},
			
			"play": function(){
				player.playToggle();
				$(this).removeClass("play").addClass("pause");
			},
			
			"next": function(){
				player.playNext();
			},
			
			"pause": function() {
				player.playToggle();
				$(this).removeClass("pause").addClass("play");
			}
		};
		
		
		controls = $(".player-controls")
		.unbind("click.player_control")
		.bind("click.player_control", function(evt){
			
			var target = evt.target,
				commands = target.className.split(/\s+/);
			
			for (var fn, i = 0, l = commands.length; i < l; ++i) {
				if (fn = actions[commands[i]]) {
					fn.apply(target);
				}
			}
			
			return false;
		});
		
		controls.each(function(){
			var t = $(this);
			if (t.hasClass("hoverable")) {
				t
					.css({opacity: 0.3})
					.unbind("mouseover.player_control")
					.unbind("mouseout.player_control")
					.bind("mouseover.player_control", function(e){
						clearTimeout(hideTimeout);
						$(this)
							.stop()
							.animate({opacity: 1}, 200);
					})
					.bind("mouseout.player_control", function(e){
						var t = $(this); 
						hideTimeout = setTimeout(function(){
							t.stop()
								.animate({opacity: 0.3}, 500);
							}, 5000);
					})
			}
		});
		
		controls.each(function(){
			with ($(this).find(".volume")) {
				bind("mouseover", function(){
					find(".scroll").show();
				});
				bind("mouseout", function(){
					find(".scroll").hide();
				});
				
				with (find(".scroll")) {
					bind("mousedown", function(evt){
						volDrag = true;
						return false;
					});
					bind("mouseup mouseout", function(){
						volDrag = false;
					});
					
					var track = find(".track"),
						_track = track[0];
					
					bind("mousemove.playser_control", function(evt){
						if (!volDrag) return true;
						var top = (evt.layerY || evt.offsetY) - 9;
						
						var maxH = attr("offsetHeight") - _track.offsetHeight;
						if (evt.target == _track) {
							top += _track.offsetTop - 1;
						}
						
						if (top < 0 || isNaN(top)) {
							top = 0;
						}
						if (top > maxH) {
							top = maxH;
						}
						
						var volume = Math.round((maxH - top) / maxH * 100);
						player.setVolume(volume);
						track.css({top: top});
						evt.preventDefault();
						evt.stopPropagation();
						return false;
					});
					
					bind("mouseout", function(){
						hide();
					});
				}
			}
		});
		
	}
	
	/**
	 * Навигация внутри сайта #/slide/widget
	 */
	this.navigateTo = function(path) {
		if (!path) {
			return false;
		}
		var pathElements = path.split(/\/+/), slide, widget, l;
		pathElements.trim();
		l = pathElements.length;
		var parameters;
		if (l > 0) {
			slide = pathElements.shift();
			if (l > 1) {
				widget = slide + "/" + pathElements.shift();
				parameters = pathElements;
			}

			applyFilters(slide, widget, parameters);
			return runAction(slide, widget, parameters);
		} else {
			return false;
		}
	}
	
	this.registerFilter = function(){
		
	}
	
	this.getDecorator = function () {
		return imgDecorator;
	}
	//endregion
	
	this.init = function () { 
		init();
	}
}

var ImageDecorator = function () {
	this.decorate = function () {console.error("This is abstract method :-)")}
}

var DolinaImageDecorator = function (imageUrl, offset, radius) {
	//console.log(imageUrl+'fdf');
	ictinus.roundCorners.RADIUS = radius || 10;
	ictinus.roundCorners.DRAW_PARAMS = {
		strokeWidth: 0,
		strokeColor: "#81756e"
	};
	var decor = new Image();
	var offset = offset || 5;
	decor.src = imageUrl;
	
	this.decorate = function(img) {		
		setTimeout(function(){			
			//console.log(this.offsetHeight);
			ictinus.roundCorners(img);
			var canvas;
			if ((canvas = img.previousSibling).tagName === "CANVAS") {
				var ctx = canvas.getContext("2d");
				var w2 = offset,
					h2 = offset,
					w1 = canvas.width - w2,
					h1 = canvas.height - h2;					
				ctx.drawImage(decor, w2, h2, w1-w2, h1-h2, 0, 0, w1, h1);
				ctx.drawImage(decor, 0, 0, w2, h2, w1, h1, w2, h2);
				ctx.drawImage(decor, w2, 0, w1, h2, 0, h1, w1, h2);
				ctx.drawImage(decor, 0, h2, w2, h1, w1, 0, w2, h1);
			}					
		}, 250);			
	}
}

DolinaImageDecorator.prototype = new ImageDecorator();

/**
 * Рассылает оповещения зарегистрированным подписчикам
 * @constructor
 */
var EventProxy = function() {
	var elements = [];

	/**
	 * Регистрация объекта для уведомлений о событиях
	 * @param {Object} element
	 */
	this.register = function(element) {
		elements.push(element);
	}
	
	/**
	 * Удаление элемента по индексу
	 * 
	 * @param {Number} index
	 */
	function unregisterByIndex(index) {
		return elements.splice(index, 1);
	}

	/**
	 * Поиск элемента простым сравнением и удаление первого найденного
	 * 
	 * @param {Object} element
	 */
	function unregisterBySearch(element) {
		for (var i = 0, el; el = elements[i]; ++i) {
			if (element == el) {
				return unregisterByIndex(i);
				break;
			}
		}
		return [];
	}

	/**
	 * Очищение всех зарегистрированных объектов
	 */
	function clear() {
		elements = [];
	}

	/**
	 * Удаление объекта из реестра. Удаление возможно по номеру, либо по
	 * указателю на объект
	 * 
	 * @param {Object, Number} element
	 * @return {Array} 
	 */
	this.unregister = function(element) {
		if (arguments.length == 0) {
			return clear();
		}
		var type = typeof element;
		switch (type) {
			case "number" : {
				return unregisterByIndex(element);
				break;
			}
			default : {
				return unregisterBySearch(element);
				break;
			}
		}
	}
	
	/**
	 * Уведомление объектов о событии
	 * 
	 * @param {String} event Имя метода
	 * @param {Array} args Аргументы
	 */
	this.notifyAll = function(event, args) {
		for (var i = 0, el, m; el = elements[i]; ++i) {
			m = el[event] || _empty;
			if (typeof args !== "array") {
				args = [args];
			}
			m.apply(m, args);
		}
	}
};

/**
 * Область, реагирующая на мышь и динамически изменяющая координаты
 * 
 * @constructor
 * @param {HTMLAreaElement} area
 * @param {Number} defaultWidth Ширина по умолчанию для инциализации.
 */
var ExtraArea = function(area, defaultWidth) {
	var	elmArea = area,
		$area = $(area),
		strCoords = area.coords,
		arrCoords = [],
		resizable = false,
		hoverable = false,
		hoverImgId,
		hoverImg;
	
	if (strCoords.length) {
		arrCoords = strCoords.split(/,\s*/);
	}
	
	if (elmArea.getAttribute("resizable")) {
		resizable = true;
	}
	
	if (hoverImgId = elmArea.getAttribute("hover-img")) {
		hoverImg = document.getElementById(hoverImgId); 
		if (hoverImg) {
			hoverable = true;
			Grader.setImgQ(hoverImg, Grader.Q_HIGH);
		}
	}
	
	if (hoverable) {
		$area.mouseover(function() {
			hoverImg.style.display = "block";
		}).mouseout(function() {
			hoverImg.style.display = "none";
		});
	}
	
	/**
	 * Масштабирование координат активной области
	 * 
	 * @param {Number} factor
	 */
	this.scale = function(factor) {
		if (!resizable) { return false; }
		if (!factor) { factor = 1; }
		var newCoords = [], cl = arrCoords.length, i = 0;
		for (; i < cl; ++i) {
			newCoords[i] = Math.floor(arrCoords[i] * factor);
		}
		area.setAttribute("coords", newCoords.join(","));
		return true;
	}
};

$(function(){
	$(".xclose").live("click", function(evt) {
		evt.stopPropagation();
		evt.preventDefault();
		var hash = location.hash,
			new_hash = "",
			last_index,
			last_item;
			
		new_hash = hash.replace("photolib", "photo");
		new_hash = new_hash.replace("photodetail", "photolib");
		new_hash = new_hash.replace("videodetail", "video");
		hash_path = new_hash.split("/");
		hash_path.pop();
		
		location.hash = hash_path.join("/");
		return false;
	});
	
	if (location.hash.toString().replace("#", "") == "") {
		location.hash = "#/the-first";
	}
	var areaProxy = new EventProxy;
	$("area").each(function() {
		areaProxy.register(new ExtraArea(this));
	});
	
	SiteHelper = new DolinaHelper();
	SiteHelper.setAreaProxy(areaProxy);
	SiteHelper.setImageDecorator(new DolinaImageDecorator("/i/puke.png", 17, 12));

	
	SiteHelper.urlFilters.push(function (slide, widget, parameters) {
		var base = "/",
			container = $("#blogdyncontent");
		
		if ("blog" != slide) {
			return true;
		}
		
		if (widget == slide + "/") {
			widget += "index";
		} else if (widget == slide) {
			widget += "/index";
		}
		
		var requestUrl = base + widget;
		
		if (parameters && parameters.length > 0) {
			for (var i = 0, l = parameters.length; i < l; ++i) {
				parameters[i] = encodeURIComponent(parameters[i]);
			}
			requestUrl += "/" + parameters.join("/");
		}
		$.get(requestUrl, function (data) {
			container.html(data);
			container.jScrollPane();
		});
	});

	SiteHelper.urlFilters.push(function (slide, widget, parameters) {
		var base = "/",
			container = $("#newsdyncontent");
		
		if ("the-first/news" != widget) {
			return true;
		}
		
		if (widget == slide + "/") {
			widget += "index";
		} else if (widget == slide) {
			widget += "/index";
		}
		
		var requestUrl = base + widget + "/" + parameters.join("/");
		var decorator = SiteHelper.getDecorator();
		$.get(requestUrl, function (data) {
			container.html(data);
			$(".puke", container).each(function () {
				decorator.decorate(this);
			});
			container.jScrollPane();
		});
	});

	SiteHelper.urlFilters.push(function (slide, widget, parameters) {
		var url = "";
		
		if (slide == "blog") {
			return;
		}
		
		if (widget) {
			url += location.pathname + widget;
		}
		if (parameters && parameters.length > 0) {
			 url += "/" + parameters.join("/");
		}
		
		var widgetElement = document.getElementById(":" + url);
		
		if (url && !widgetElement) {
			var template = '<div class="overlay widget" id=":' + url + '">\
				<div class="background">\
					<div class="overlay-content">\
						<a href="#/the-first" class="xclose"></a>\
						{HTML}\
					</div>\
					<div class="bgc"></div>\
				</div>\
			</div>';
			var html = $.ajax({
				url: url,
				async: false
			}).responseText;
			$(template.replace("{HTML}", html)).appendTo(".widgets");
		}
	});
	
	SiteHelper.urlFilters.push(function (slide, widget, parameters) {
		if (typeof DolinaPlayer == "undefined") {
			return false;
		}
		
		if (/videodetail/.test(widget)) {
			if (["playing"].contains(DolinaPlayer.getPlayingState())) {
				DolinaPlayer.setAutopause();
			}
		} else {
			DolinaPlayer.removeAutopause();
		}
	});
	
	SiteHelper.init();
	
	$("#frame-blog .scrolled .pane").jScrollPane();
	
	new PlayerWatcher();
});

var PlayerWatcher = function () {
	var state = "",
		prev_state = "unknown",
		tick = function () {
			if (typeof DolinaPlayer == "undefined") {
				return;
			};
			
			state = DolinaPlayer.getPlayingState() || "unknown";
			if (state !== prev_state) {
				prev_state = state;

				if (state === "playing") {
					window.ppc.removeClass("play").addClass("pause");
				} else {
					window.ppc.removeClass("pause").addClass("play");
				}
			}
		};
		
	setInterval(tick, 500);
}

var IETitleCorrector = function() {
	var last_valid_title = "",
		timer = null;
	
	function watch() {
		var title = document.title;
		if (/^#/.test(title)) {
			document.title = last_valid_title;
		} else {
			last_valid_title = title;
		}
	}
	
	timer = setInterval(function(){
		watch();
	}, 100);
};

if ($.browser.msie) {
	IETitleCorrector();
}

$(window).bind("load", function(){
	window.DolinaPlayer = new Player();
	SiteHelper.setPlayer(DolinaPlayer);
});





















