/*
 * Скрипты проекта
 * @author Pavel Motorin (pavel.motorin@gmail.com)
 */

(function($){

	// Инициализируем главную страницу
	function initFirstPage()
		{
			// В качестве эксперимента вернемся к старому ООП-подходу.
			// не факт, что это верно в данном случае, так как объект дальше
			// не используется. Но зато сам про себя всё знает.
			var oMainPageScroller = new MainPageScrollerController();

//			$( document ).trigger("scrollerNextStep");
//			var o = CScrollerStep($("#prj_4game"));

			// Хак для тестирования.
		}

		/*******************************************************************************
	 * Сами создаем весь HTML для этого дела.
	 ******************************************************************/
	var oScrollerOptions =
		{
			Speed: 250,
			Speed1: 100,
			Speed2: 300,
			MainData: "#ProjectsListOnMain",
			MainContainer: "#ProjectsSliderContainer",
			id: {
				Scroller: "ProjectScroller",
				WrapContainer: "ProjectScrollerWrapContainer",
				SubWindow: "ProjectScrollerSubWindow",
				Nav: "ProjectScrollerNav",
				Step: "li.Step",
				Cover: "ProjectScrollerCover",
				NextStep: "NextProject",
				PrevStep: "PrevProject",
				CurrentItemCSSClass: "current"
			}
		}

	// Основываемся на том, что у нас UL -- контейнер fix width и overflow: hidden,
	// и мы делаем ему внутри scrollTo к нужному элементу.
	function MainPageScrollerController()
		{
			var that = this;
				// Перестраиваем HTML, как нам надо.
				this.$oScroller				= $("<div>").attr("id", oScrollerOptions.id.Scroller );
				this.$oWrapContainer		= $("<div>").attr("id", oScrollerOptions.id.WrapContainer ).appendTo( this.$oScroller );
				this.$oSubWindow			= $("<div>").attr("id", oScrollerOptions.id.SubWindow ).appendTo( this.$oScroller );
				this.$oStepsContainer		= $( oScrollerOptions.MainData ).appendTo( this.$oWrapContainer );
				this.$oCover				= $("<div>").attr("id", oScrollerOptions.id.Cover).prependTo( this.$oScroller );			// прикрывающая накладка, используется в момент смены шагов для красоты
				this.$oNav					= $("<div>").attr("id", oScrollerOptions.id.Nav );
				this.$oNextStep				= new CScrollerStepNav("NextStep");
				this.$oPrevStep				= new CScrollerStepNav("PrevStep");

				this.iCurrentStep			= 0;
				this.iNewStep				= 0;
				this.aSteps					= [];
				$( oScrollerOptions.id.Step, this.$oStepsContainer ).each( function(i, v)
					{
						that.aSteps[i] = new CScrollerStep( v );
					});

				/**
				 * ПОЕХАЛИ! (с)
				 */
				this.init();
		}
		
		
	// Инициализация, очевидно.
	MainPageScrollerController.prototype.init = function()
		{
			var that = this;
			/**
			 *  Cобытия. Говорим, чо делать, в случае чего.
			 */
			$( document )
				.bind("keyup", "right", function(e) { $( document ).trigger("scrollerNextStep"); })
				.bind("keyup", "left", function(e) { $( document ).trigger("scrollerPrevStep"); })
				.bind("scrollerStartStepSwitching", function(e)
					{
						that.showCover();
						that.checkNav();
						that.disableScroll();
					})
				.bind("scrollerEndStepSwitching", function(e){
						that.hideCover();
						that.enableScroll(); 
					})
				.bind("ShowOutReadyToShow", function(e, $aShowOut )
					{
						that.showOutItems( $aShowOut );
					})
				;
			
			// Обновляем DOM, добавляем всё придуманное на страничку.
			this.$oScroller.appendTo( $( oScrollerOptions.MainContainer ) );
			this.$oPrevStep.$oContainer.appendTo( this.$oNav );
			this.$oNextStep.$oContainer.appendTo( this.$oNav );
			this.$oNav.appendTo( $( oScrollerOptions.MainContainer ));

			// Ну и включаем всю эту котовасью.
			this.enableScroll();

			/**
			 * Меняем ширину UL, чтобы все шаги горизонтально влезали
			 * Раньше нельзя было, так как width был не определен для элементов не вставленных на страничку.
			 * +100 -- надежный запас. Нам не мешает, так как мы скроллим до начала элемента, а удобство есть.
			 * (скажем, если у нас viewport больше элемента, то последний не доедет конца и будет торчать
			 * кусок предыдущего.
			 */
			this.$oStepsContainer.width( this.$oWrapContainer.width() * this.aSteps.length + 100).show();
			
			// скроллим до начала
			this.$oWrapContainer.scrollTo(0, 0);
			
			// Уточняем навигацию
			this.checkNav();
		}
	
	// Дизейблинг клавиш во время анимации
	MainPageScrollerController.prototype.enableScroll = function()
		{
			var that = this;
			$( document )
				.bind("scrollerNextStep", function(e){ that.switchStep( that.iCurrentStep + 1 ); })
				.bind("scrollerPrevStep", function(e){ that.switchStep( that.iCurrentStep - 1 ); })
		}

	MainPageScrollerController.prototype.disableScroll = function ()
		{
			$( document )
				.unbind("scrollerNextStep")
				.unbind("scrollerPrevStep");
		}

	
	// Переключалка шагов
	MainPageScrollerController.prototype.switchStep = function( iWhichStep )
		{
			// Что-то делаем только, если существует вообще нужный шаг
			if( this.aSteps[iWhichStep] )
				{
					var that = this;
					var iOldStep = this.iCurrentStep;
						this.iCurrentStep = iWhichStep;

						$( document ).trigger("scrollerStartStepSwitching");

						this.aSteps[iOldStep].goToHide();			// текущий плавно прячем
						this.aSteps[this.iCurrentStep].goToShow();					// новый плавно показываем
						this.$oWrapContainer.scrollTo( this.aSteps[this.iCurrentStep].$oContainer, oScrollerOptions.Speed,
							{
								onAfter: function() { $( document ).trigger("scrollerEndStepSwitching"); }
							});
				}
		};

	// проверяем, не надо ли спрятать часть навигации
	MainPageScrollerController.prototype.checkNav = function()
		{
			if( this.aSteps[(this.iCurrentStep + 1)] )
				{
					this.$oNextStep.update( this.aSteps[(this.iCurrentStep+1)].title )
					this.$oNextStep.show();
				} else {
					this.$oNextStep.hide();
				}
			if( this.aSteps[(this.iCurrentStep - 1)] )
				{
					this.$oPrevStep.update( this.aSteps[(this.iCurrentStep-1)].title );
					this.$oPrevStep.show();
				} else {
					this.$oPrevStep.hide();
				}
		};

	// показываем накладку
	MainPageScrollerController.prototype.showCover = function()
		{
			if (!$.browser.msie) { // в ie глюки (todo)
				this.$oCover.show();
			}
		};

	// прячем накладку
	MainPageScrollerController.prototype.hideCover = function()
		{
			this.$oCover.hide();
		};

	MainPageScrollerController.prototype.showOutItems	= function( $aShowOut )
		{
			var that = this;
			var iTopOffset = this.$oStepsContainer.offset().top  - this.$oSubWindow.offset().top;
			$aShowOut.each( function()
				{
					$( this ).appendTo( that.$oSubWindow )
						.restrictAnimation("fadeIn", oScrollerOptions.Speed );
				});
		};

	/**
	 * Каждый шаг должен сам про себя почти всё знать.
	 * В частности все свои выносные картинки и другие хитрости.
	 */
	function CScrollerStep( oContainerIn )
		{
			var that = this;
				this.$oContainer	= $( oContainerIn );
				this.aOut			= $(".ShowOut", this.$oContainer);
				this.title			= this.$oContainer.attr("title");
		}

	CScrollerStep.prototype.goToHide = function()
		{
			this.$oContainer.fadeTo( oScrollerOptions.Speed, 0.1);
			if( this.aOut.length > 0 )
				this.aOut.each( function(i, v)
					{
						$(this).restrictAnimation("fadeOut", oScrollerOptions.Speed );
					});
			$( oScrollerOptions.id.Step, this.$oStepsContainer ).removeClass( oScrollerOptions.id.CurrentItemCSSClass );
		};

	CScrollerStep.prototype.goToShow = function()
		{
			this.$oContainer.addClass( oScrollerOptions.id.CurrentItemCSSClass ).css({opacity: 0.1}).delay(100).fadeTo( oScrollerOptions.Speed, 1);
			if( this.aOut.length > 0 )
				{
				this.aOut.each( function(i, v)
					{
						if( !$( this ).data("position") )
							{
								$( this ).data("position", $( this ).position() );
							}
					});
					$( document ).trigger("ShowOutReadyToShow", [this.aOut]);
				}
		};

	/**
	 * Управляющий элемент прокручивания
	 */
	function CScrollerStepNav( sID )
		{
			var that = this;
			this.id				= sID;
			this.iCurrentStep	= -1;
			this.$oContainer	= $("<div>").attr("id", oScrollerOptions.id[this.id] );
			this.$oBtn			= $("<em>").appendTo( this.$oContainer );
			this.$oArrow		= $("<ins>").appendTo( this.$oContainer );

			this.$oBtn.bind({
					mouseenter:	function(){ that.highlight(); },
					mouseleave:	function(){ that.normalize(); },
					click:		function(){ $( document ).trigger("scroller" + that.id); }
				});

		}

	CScrollerStepNav.prototype.update		= function( sData )
		{
			this.$oBtn.text( sData );
		}

	CScrollerStepNav.prototype.highlight	= function()
		{
			this.$oContainer.addClass("Highlighted");
			this.$oArrow.css(restrictAnimation({opacity: 1}));
			this.$oArrow.stop(true).show().animate(restrictAnimation({
					opacity: 1,
					marginLeft: "-30px",
					marginRight: "-30px"
				}),{queue: false, duration: oScrollerOptions.Speed2, easing: "swing"});
		};

	CScrollerStepNav.prototype.normalize	= function()
		{
			this.$oContainer.removeClass("Highlighted");
			this.$oArrow.css(restrictAnimation({opacity: 0.2}));
			this.$oArrow.stop(true).animate(restrictAnimation({
					opacity: 0.2,
					marginLeft: 0,
					marginRight: 0
				}),{queue: false, duration: oScrollerOptions.Speed2,  easing: "swing", complete: function(){ $( this ).hide() }});
		};

	CScrollerStepNav.prototype.hide			= function()
		{
			this.$oContainer.stop(true).restrictAnimation("fadeOut", oScrollerOptions.Speed );
		};

	CScrollerStepNav.prototype.show			= function()
		{
			this.$oContainer.stop(true).restrictAnimation("fadeIn", oScrollerOptions.Speed );
		};

	/*******************************************************************************
	 * Техническая вспомогательная, чтобы error не вылетал приотсутствии console.
	 ******************************************************************/
	function trace( oIn )
		{
			if( window.console )
				console.log( oIn );
		}

	// Подменяет функции, если это IE.
	// В основном для всяких анимаций с прозрачностью
	// Полиморфизм и всё такое, если, конечно уместно  применять этот термин не для классов. :)
	var oRestrictAnimationSettings = {
			isIESmall: ($.browser.msie)
		};
	function restrictAnimation( oIn )
		{
			if( oRestrictAnimationSettings.isIESmall && typeof(oIn) == "object" )
				{
					oIn.filter = '';
				}
			return oIn;
		}
	$.fn.restrictAnimation = function( oIn, iSpeed )
		{
			return this.each( function()
				{
					if( oRestrictAnimationSettings.isIESmall && typeof( oIn ) == "string")
						{
							switch( oIn )
								{
									case "fadeIn":
										oIn = "show";
										iSpeed = 0;
									break;
									case "fadeOut":
										oIn = "hide";
										iSpeed = 0;
									break;
									case "fadeTo":
										oIn = "show";
										iSpeed = 0;
									break;
								}
						}
					$( this )[oIn](iSpeed);
				});
		};
	
	$(document).ready(function() {
		initFirstPage();
	});
})(jQuery);

