(function ($, win, doc) {
	
	/*
	 * Width of slideshow item
	 */
	var ITEM_WIDTH = 1700;
	var ITEM_OFFSET = (ITEM_WIDTH - 1000) / 2
	var ITEM_POS_FIX = 50;
	
	/*
	 * Default content positions
	 */
	var CONTENT_POSITIONS = [ITEM_OFFSET + 393, ITEM_OFFSET + 76, ITEM_OFFSET + 557];
	
	var SlideShow = win.SlideShow = {
		
		/**
		 * Animation duration
		 */
		duration: 750,
		
		/**
		 * Animation easing function
		 */
		easing: 'easeInOutCubic',
		
		/**
		 * Button which triggers slideshow to open
		 */
		button: [],
		
		/**
		 * head element
		 */
		head: [],
		
		/**
		 * Contents elements
		 */
		contents: [],
		
		/**
		 * Slideshow navigation element
		 */
		navigation: [],
		
		/**
		 * Number of slideshow items
		 * @type {Number}
		 */
		length: 0,
		
		/**
		 * Current item index
		 * @type {Number}
		 */
		current: 0,
		
		/**
		 * Content visibility state
		 * @type {Boolean}
		 */
		content_visible: true,
		
		/**
		 * Window width
		 * @type {Number}
		 */
		win_width: 0,
		
		/**
		 * head height when slideshow is visible
		 * @type {Number}
		 */
		height: 484,
		
		/**
		 * Hide slideshow
		 */
		hide: function () {
			this.slide(null, 1);
		},
		
		/**
		 * Show slideshow
		 */
		show: function () {
			var height = typeof this.height == 'function' ? this.height() : this.height;
			var current_height = this.head.height();
			var callback = true;
			
			if (this.content_visible || current_height >= height) {
				this._afterShow();
				callback = false;
			}
			
			if (current_height != height) {
				if (Page.loading) {
					//If called on page load
					//delay head height animation
					//for nicer effect
					setTimeout($.proxy(function () {
						Page.setheadHeight(height);
						this.animateHeight();
					}, this), this.duration / 2);
					
					if (callback) this._afterShow();
				} else {
					Page.setheadHeight(height);
					this.animateHeight(callback ? this._afterShow : null);
				}
			}
		},
		
		animateHeight: function (callback) {
			var height = typeof this.height == 'function' ? this.height() : this.height;
			this.head.stop().animate(
				{ 'height': height + 'px' },
				this.duration,
				this.easing,
				typeof callback == 'function' ? $.proxy(this._afterShow, this) : null
			);
		},
		
		/**
		 * After height is animated, show content + navigation
		 */
		_afterShow: function () {
			this.slide(this.current ? this.current : 0, 1);
		},
		
		updateSlider: function (index) {
			var parent = this.navigation.find('a.prev').parent();
				
			if (index <= 0) {
				parent.addClass('first');
			} else {
				parent.removeClass('first');
			}
			
			if (index >= this.length - 1) {
				parent.addClass('last');
			} else {
				parent.removeClass('last');
			}
		},
		
		/**
		 * Slide in next item
		 */
		slideNext: function () {
			var index = this.current + 1;
			if (index >= this.length) return;
			
			this.updateSlider(index);
			this.slide(index, 1);
		},
		
		/**
		 * Slide in previous item
		 */
		slidePrev: function () {
			var index = this.current - 1;
			if (index < 0) return;
			
			this.updateSlider(index);
			this.slide(index, -1);
		},
		
		/**
		 * Slide in background and containers
		 * 
		 * @param {Number} index Index of slide
		 * @param {Number} direction Direction, -1 backward, 1 forward
		 */
		slide: function (index, direction) {
			if (index === null && this.content_visible) {
				this.slideOutAll();
				this.content_visible = false;
			} else if (index !== null && !this.content_visible) {
				this.slideInAll(index, direction);
				this.current = index;
				this.content_visible = true;
			} else if (index !== null) {
				this.slideInContent(index, direction);
				this.current = index;
				this.content_visible = true;
			}
		},
		
		/**
		 * slide-in contents + navigation
		 * @param {Object} index
		 * @param {Object} direction
		 */
		slideInAll: function (index, direction) {
			this.slideInContent(index, direction);
			this._slideInItem(this.navigation, -direction);
		},
		
		/**
		 * Slide-out contents + navigation
		 */
		slideOutAll: function () {
			if (!this.content_visible) return;
			
			this.slideOutContent(-1);
			this._slideOutItem(this.navigation, 1);
		},
		
		/**
		 * Slide-in contents
		 * 
		 * @param {Number} index Index of slide
		 * @param {Number} direction Direction, -1 backward, 1 forward
		 */
		slideInContent: function (index, direction) {
			if (index < 0 || index >= this.length) return;
			if (this.content_visible) this.slideOutContent(direction);
			direction = direction >=0 ? 1 : -1;
			
			//Animate item inside the view
			var node = this.contents.eq(index);
			this._slideInItem(node, direction);
			
			//Animate individual nodes
			var nodes = [node.find('div.light'), null, node.find('div.dark')];
			for(var i=0;i<3;i+=2) {
				nodes[i].stop(true, true)
						.css({'left': CONTENT_POSITIONS[i] + direction * (900 - i * 450) + 'px'})
						.animate({'left': CONTENT_POSITIONS[i] + 'px'}, this.duration * (0.6 - i * 0.2), this.easing);
			}
		},
		
		/**
		 * Slide-out contents
		 * 
		 * @param {Number} direction Direction, -1 backward, 1 forward
		 */
		slideOutContent: function (direction) {
			if (!this.content_visible) return;
			direction = direction >=0 ? 1 : -1;
			
			//Animate item out of view
			var node = this.contents.eq(this.current);
			this._slideOutItem(node, direction);
			
			//Animate individual nodes
			var nodes = [node.find('div.light'), null, node.find('div.dark')];
			for(var i=0;i<3;i+=2) {
				nodes[i].stop(true, true)
						.animate({'left': CONTENT_POSITIONS[i] - direction * (900 - i * 450) + 'px'}, this.duration * (0.6 - i * 0.2), this.easing);
			}
		},
		
		/**
		 * Slide-in node
		 * 
		 * @param {Object} node Node which will be animated
		 * @param {Number} direction Direction, -1 backward, 1 forward
		 */
		_slideInItem: function (node, direction, delay) {
			var delay = delay || 0,
				duration = this.duration - Math.abs(delay);
			
			node.stop(true, true);
			
			if (delay > 0) {
				node.animate({'x': 1}, Math.abs(delay));
			}
			
			node.css({
					'margin-left': this._getBackgroundPos(direction >= 0 ? 1 : -1) + 'px'
				})
				.removeClass('hidden')
				.animate({
					'margin-left': this._getBackgroundPos(0) + 'px'
				}, duration, this.easing);
		},
		
		/**
		 * Slide-out node
		 * 
		 * @param {Object} node Node which will be animated
		 * @param {Number} direction Direction, -1 backward, 1 forward
		 */
		_slideOutItem: function (node, direction, delay) {
			var delay = delay || 0;
			var duration = this.duration - Math.abs(delay);
			
			node.stop(true, true);
			
			if (delay > 0) {
				node.animate({'x': 1}, Math.abs(delay));
			}
			
			node.animate({
					'margin-left': this._getBackgroundPos(direction >= 0 ? -1 : 1) + 'px'
				}, duration, this.easing, this._slideOutComplete);
		},
		
		/**
		 * Returns background position for:
		 *   -1  left
		 *    0  center
		 *    1  right
		 *    
		 * @param {Number} position Place for which background position will be returned
		 * @return Background position
		 * @type {Number}
		 */
		_getBackgroundPos: function (position) {
			var width = ITEM_WIDTH;
			switch(position) {
				case -1:
					return ~~(- this.win_width / 2 - width);
				case 1:
					return ~~(this.win_width / 2 + 1);
				default:
					return ~~(-width / 2) - ITEM_POS_FIX;
			}
		},
		
		/**
		 * Slide-out complete event
		 * Hide background and contents which were animated 
		 */
		_slideOutComplete: function () {
			$(this).addClass('hidden');
		},
		
		/**
		 * On window resize update properties
		 */
		_onResize: function () {
			this.win_width = $(win).width();
		},
		
		/**
		 * Slide-in next/previous slide on key press
		 * @param {Object} event
		 */
		_onKeyDown: function (event) {
			if (!this.content_visible) return;
			
			switch(event.keyCode) {
				case 37:
					this.slidePrev(); break;
				case 39:
					this.slideNext(); break;
			}
		},
		
	 	/**
	 	 * @constructor
	 	 */
		init: function () {
			this.button = $('#buttonSlideShow');
			this.head = $('#head');
			this.contents = this.head.children('div.content');
			this.navigation = this.head.children('div.slideshow-navigation');
			this.length = this.contents.length;
			
			//Keys: LEFT - previous slide, RIGHT - next slide
			var node = $(window);
			if ($.browser.msie) node = $(document.body)
			node.keys($.proxy(this._onKeyDown, this), [37, 39]);
			
			//Bind to next/prev arrows
			this.navigation.find('a.prev').click($.proxy(this.slidePrev, this));
			this.navigation.find('a.next').click($.proxy(this.slideNext, this));
			
			//On resize update window width property
			$(win).bind('resize', $.proxy(this._onResize, this));
			this._onResize();
			
			//Show illustrations when button is clicked
			this.button.click($.proxy(Page.openHomePage, Page));
		}
	};
	
})(jQuery, window, document);

