/**
 * Scroller
 * Requires: jQuery 1.6+, jQueryUI 1.8+
 * 
 * Params
 * 	String		id					DOM id attribute of scroller
 * 	Int			wait_delay		  	Delay between animation
 * 	Int			animation_delay		Length of animation
 * 	String		animation_type		Type of animation (horizontal, vertical or fade)
 * 	Boolean		show_controls		Display feature controls
 *  Boolean		debug				Stops timeout to enable inspecting DOM after initialise
 */

function Scroller(id, wait_delay, animation_delay, animation_type, show_controls, debug) {
	
	
	// User configurable settings
	this._settings = {
		base_id: id,
		wait_delay: (wait_delay > 0) ? wait_delay : 8000,
		animation_delay: (animation_delay > 0) ? animation_delay : 700,
		animation_type: (animation_type != '') ? animation_type : 'horizontal',
		show_controls: (show_controls) ? show_controls : false,
		debug: (debug) ? debug : false
	};
	
	this._id = null;
	this._num_features = null;
	this._feature_width = null;
	this._feature_height = null;
	this._timeout = null;
	this._current_index = 0;
	this._handles = {
		$container: null,
		$viewport : null, 
		$feature_controls : null, 
		$feature_repository : null, 
		$frame : null
	};
	

	this._id = 'scroller_' + this._settings.base_id;
	this._num_features = $('#' + this._settings.base_id + ' .features .feature').length;
	this._feature_width = $('#' + this._settings.base_id + ' .features .feature:first').width();
	this._feature_height = $('#' + this._settings.base_id + ' .features .feature:first').height();
	
	
	
	// Build required HTML structure, assign necessary handles
	this._handles.$container = $('#' + this._settings.base_id );
	this._handles.$container.addClass(this._settings.animation_type); // Allows styles to be copied, then applied where necessary
	this._handles.$container.append('<div class="feature_viewport"><div class="feature_frame"></div></div><div class="feature_controls"></div>');
	this._handles.$viewport = $('#' + this._settings.base_id + ' .feature_viewport');
	this._handles.$feature_repository = $('#' + this._settings.base_id + ' .features');
	this._handles.$frame = $('#' + this._settings.base_id + ' .feature_viewport .feature_frame');
	this._handles.$frame.append($('#' + this._settings.base_id + ' .features .feature:eq('+this._current_index+')').clone());
	
	if (this._settings.show_controls)
		this._handles.$feature_controls = $('#' + this._settings.base_id + ' .feature_controls');
	
	
	// Hide features
	this._handles.$feature_repository.hide();
	
	
	// Build feature controls
	if (this._settings.show_controls) { 
		for (var i = 0; i < this._num_features; i++) {
			this._handles.$feature_controls.append('<span class="feature_control'+((i==0)?' current':'')+'" data-index="'+i+'">'+(i+1)+'</span>');
		}
		
		if (this._num_features > 1) { 
			// Click handler for controls
			this._handles.$feature_controls.children('.feature_control').click(function() {
				this.scroll_left(parseInt($(this).attr('data-index')));
			});
		}
	}
	
	// > 1 prevents animation from occuring if only one feature is present
	if (this._num_features > 1 && this._settings.debug != true) {	
		this._timeout = setTimeout('window.'+this._id+'.scroll_left(false)', this._settings.wait_delay);		
	}
	
	// Assign object to window as this will not be the context when timeout occurs
	window[this._id] = this;
	

	
};



/* 
 * Default animation action
 */
Scroller.prototype.scroll_left = function(jump_to) {
	var _self = this;	// avoids this context problems
	
	if (jump_to !== false) {
		this._current_index = jump_to;
	} else {
		this._current_index++;
	}
	
	if (this._current_index >= this._num_features) {
		this._current_index = 0;
	}
	
	
			
	// Change current selector
	if (this._settings.show_controls) 
		this.update_current();
	
		
	
	// Animate scroll
	switch (this._settings.animation_type) {
		case 'horizontal':
			this._handles.$frame.width(2 * this._feature_width);
			
			// Select next feature from repository add to feature_frame
			this._handles.$frame.append(this._handles.$feature_repository.children('.feature:eq('+this._current_index+')').clone());
			
			this._handles.$frame.animate({
				left: -1 * this._feature_width
			}, this._settings.animation_delay, function() {
				// Switch alignment edge
				_self._handles.$frame.css({
					'right': 0,
					'left': 'auto'
				});
			
				// Remove previous feature
				_self._handles.$frame.children('.feature:first').remove();
				
				// Switch alignment edge back
				_self._handles.$frame.css({
					'width': 'auto',
					'left': 0,
					'right': 'auto'
				});
				
				// Reset timeout - needed for restarting the timer if trigger by user click
				if (_self._timeout) {
					_self.resetTimeout();
				}
			});
			break;
		case 'vertical':
			this._handles.$frame.height(2 * this._feature_height);
			
			// Select next feature from repository add to feature_frame
			this._handles.$frame.append(this._handles.$feature_repository.children('.feature:eq('+this._current_index+')').clone());
			
			this._handles.$frame.animate({
				top: -1 * this._feature_height
			}, this._settings.animation_delay, function() {
				_self._handles.$frame.css({
					'bottom': 0,
					'top': 'auto'
				});
				
				// Remove previous feature
				_self._handles.$frame.children('.feature:first').remove();
				
				// Switch alignment edge back
				_self._handles.$frame.css({
					'height': 'auto',
					'top': 0,
					'bottom': 'auto'
				});
				
				// Reset timeout - needed for restarting the timer if trigger by user click
				if (_self._timeout) {
					_self.resetTimeout();
				}
			});
			break;
		case 'fade':
			// Fade current feature
			this._handles.$frame.children('.feature:first').animate({
				opacity: 0
			}, this._settings.animation_delay, function() {
				// Remove current feature
				_self._handles.$frame.children('.feature:first').remove();
				
				// Select next feature from repository add to feature_frame
				_self._handles.$frame.append(_self._handles.$feature_repository.children('.feature:eq('+_self._current_index+')').clone());
				// Start invisible
				_self._handles.$frame.children('.feature:first').css('opacity', 0);
				
				// Fade new feature in
				_self._handles.$frame.children('.feature:first').animate({
					opacity: 1
				}, _self._settings.animation_delay, function() {
					
					// Reset timeout - needed for restarting the timer if trigger by user click
					if (_self._timeout) {
						_self.resetTimeout();
					}
				});
			});
			break;
	}
};

/**
 * Scroll opposite direction - not currently in use
 */
Scroller.prototype.scroll_right =  function() {
	var _self = this;	// avoids this context problems
	
	this._current_index--;
	if (this._current_index < 0) {
		this._current_index = this._num_features - 1;
	}
	
	// Switch alignment edge
	this._handles.$frame.css({
		'right': 0,
		'left': 'auto'
	});
	
	// Add next feature to start
	this._handles.$frame.append(this._handles.$feature_repository.children('.feature:eq('+this._current_index+')').clone());
	this._handles.$frame.width(2 * this._feature_width);
	
	// Change current selector
	if (this._settings.show_controls)  
		this.update_current();
	
	// Animate scroll
	this._handles.$frame.animate({
		'right' : -1 * this._feature_width
	}, this._settings.animation_delay, function() {
			// Switch alignment edge
			_self._handles.$frame.css({
				'left' : 0,
				'right' : 'auto'
			});
			
			// Remove previous feature
			_self._handles.$frame.children('.feature:last').remove();
			_self._handles.$frame.css({
				'width': 'auto'
			});
			
			
			
			if (_self._timeout) {
				_self.resetTimeout();
			}
	});
};


/* 
 * Resets timeout delay
 */
Scroller.prototype.resetTimeout = function() {
	clearTimeout(this._timeout);
	this._timeout = setTimeout('window.'+this._id+'.scroll_left(false)', this._settings.wait_delay);
};

/*
 * Switches current class on feature controls
 */
Scroller.prototype.update_current = function () {
	this._handles.$feature_controls.children('.feature_control').removeClass('current');
	this._handles.$feature_controls.children('.feature_control:eq('+this._current_index+')').addClass('current');
};





