/**
 * @fileOverview Provides a method of presenting a series of feature stories in a splashpod style with paging controls.
 * @author David Jessup <david.jessup@sydney.edu.au>
 * @author Alex Motyka <alex.motyka@sydney.edu.au>
 * @author Greg Poole <gregory.poole@sydney.edu.au>
 * @version 3.2.1
 */

var HighlightConsole = new Class( /** @lends HighlightConsole.prototype */ {
	
	Implements : [ Options ],
	
	options :  {
		duration : 1.0,
		frequency: 3,
		placeControls : 'bottom left',
		controlTitles : false,
		autoGlide : false
	},

	/**
	 * Creates and controls a highlight console using an existing wrapper with child .story elements.
	 * @constructs
	 * @param {string|Element} wrapper A selector or element reference for the element which will contain the highlight stories.
	 * @param {object} [options] Console configuration.
	 * @config {number} [duration] The length (seconds) of the transition effect between slides.
	 * @config {number} [frequency] The delay between slide changes when autoGlide is on.
	 * @config {boolean} [autoGlide] Whether to automatically change slides. Defaults to false.
	 * @config {boolean} [controlTitles] Whether to use text titles for the slide controls instead of numeric. Defaults to false.
	 * @config {string} [placeControls] In the format "pos pos" where pos is either "top", "bottom", "left" or "right". Defaults to "bottom left".
	 * @config {string} [initialSection] Selector for the first slide to show (i.e. '#story1') or "random" for a random slide. Defaults to the first slide.
	 */
	initialize : function(wrapper, options){
		var self = this;
		this.setOptions(options);
	    this.wrapper    = $(wrapper);
	    this.stories    = this.wrapper.getElements('div.story');
	    this.controls   = this.wrapper.getElement('#controls') || new Element('div', { 'class' : 'controls' });

	    if(this.controls.get('id') == 'controls')
	    	this.controls.set('id', '').addClass('controls');

	    this.controls.set('title', 'Slide controls');
	    this.wrapper.adopt(this.controls);

	    // Position the controls on the overlay
    	function hasPos(p) { return self.options.placeControls.indexOf(p) != -1; }

    	if(hasPos('left')) {
    		this.controls.setStyle('left', 0);
    	} else if(hasPos('right')) {
    		this.controls.setStyle('right', 0);
    	}
    	if(hasPos('top')) {
    		this.controls.setStyle('top', 0);
    	} else if(hasPos('bottom')) {
    		this.controls.setStyle('bottom', 0);
    	}

    	this.controls.setStyle('position', 'absolute');
	    
	    this.stories.each(function(story, index) {
	    	story._index = index; 
	    	story.setStyles({
		    	position : 'absolute',
		    	top : '0',
		    	width : self.wrapper.getCoordinates().width
		    }); 
	    	story.myFx = new Fx.Tween(story, { 
	    		duration: this.options.duration * 1000,
	    		property: 'opacity'
			});

	    	if (index != 0) {
	    		story.setStyles({
	    			opacity : 0,
	    			display : 'none'
	    		});
	    	}

	    	var controlText = index + 1;
	    	if(this.options.controlTitles) {
	    		var title = story.getElements('h2,h3,h4,h5,h6')[0];
	    		if(title) {
	    			controlText = title.get('text');
	    		} else if(story.get('title')) {
	    			controlText = story.get('title');
	    		}
	    	}

	    	storyControl = new Element('a', { text : controlText, href : '#', title : 'Go to slide ' + controlText });
	    	storyControl.addEvent('click', function() {
	    		 this.stop();
	    		 this.moveTo(story);
	    		 return false;
	    	}.bind(this));
	    	story.control = storyControl;
	    	this.controls.adopt(storyControl);
	    }, this);
	   
		if(this.options.initialSection) {
			var next;
			if (this.options.initialSection == 'random') next = this.stories.getRandom();
			else next = this.wrapper.getElement(this.options.initialSection);

			this.moveTo(next, true);
		} else {
			this.moveTo(this.stories[0], true);
		}
		
		if(this.options.autoGlide)
			this.start();
	},	

	/**
	 * Change the currently displaying story to the one specified.
	 * @function
	 * @param {string|Element} element The .story element to display.
	 * @private
	 */
	moveTo : function(element, instant) {
		var self = this;
		element = $(element);
		if (this.current === element) return;
		
		this.element = element;
		
		this.controls.getElements('a').each(function(control) {
			control.removeClass('active');
		});
		this.element.control.addClass('active');

		if(!instant) {
			if(this.current) {
				var current = this.current;
				current.myFx.cancel().start(1, 0).chain(function() {
					current.setStyles({ opacity : 1, display : 'none' });
				});
			}
			
			this.element.myFx.cancel();
			this.element.myFx.start(0,1).chain(
				function() {
					if (Browser.ie) {
						if (this.subject.getStyle('opacity') == 1) this.subject.style.removeAttribute('filter');
						else this.subject.style.filter = 'alpha(opacity=' + opacity * 100 + ')';
					}
				}
			);
			this.element.setStyles({ display: 'block', opacity : 0 });
		} else {
			this.element.setStyles({ opacity : 1, display : 'block' });
		}
	
		this.current = this.element;
    	return false;
	},
	
	/**
	 * Move to the next available slide (or wrap around to the first if displaying the last one).
	 * @private
	 */
	moveNext : function() {
		var nextIndex, currentIndex;
	    if (this.current) {
	      currentIndex = this.current._index;
	      nextIndex = (this.stories.length - 1 == currentIndex) ? 0 : currentIndex + 1;      
	    } else {
		    nextIndex = 1;
		}
	    this.moveTo(this.stories[nextIndex]);
	},
	
	/**
	 * Move to the previous available slide (or wrap around to the last if displaying the first one).
	 * @private
	 */
	movePrevious : function() {
		var prevIndex, currentIndex;
	    if (this.current) {
	      currentIndex = this.current._index;
	      prevIndex = (currentIndex == 0) ? this.sections.length - 1 : 
	      currentIndex - 1;
	    } else {
		    prevIndex = this.stories.length - 1;
		}
	    this.moveTo(this.stories[prevIndex]);
	},

	/**
	 * Move to the next slide in response to user interaction. Stops auto-gliding.
	 */
  	next : function() {
  		this.stop();
	  	this.moveNext();
	},

  	/**
  	 * Move to the previous slide in response to user interaction. Stops auto-gliding.
  	 */
	previous : function() {
		this.stop();
		this.movePrevious();
	},

	/*
	 * Stop automatically changing slides.
	 */
	stop : function() {
		clearTimeout(this.timer);
		delete this.timer;
	},	

	/**
	 * Begin automatically changing slides.
	 */
	start : function() {
		if(this.timer) {
			clearTimeout(this.timer);
			delete this.timer;
		}
		this.timer = this.moveNext.periodical(this.options.frequency * 1000, this);
	}
});
