/**
 * The Pager class
 * 
 * @author Karl Shea	kshea@matharts.com
 */
var Pager = new Class({
	
	/**
	 * Initializes the Pager object
	 * 
	 * Should pass an argument array with viewport, transition, pager_caption, pager_prev, pager_next and optionally step specified
	 * 
	 * @constructor
	 */
	initialize: function(args) {
		// Set the viewport
		this._viewport = args.viewport;
		
		// Set the previous and next links
		this._pager_prev = args.pager_prev;
		this._pager_next = args.pager_next;
		
		// Set the element to hide if there is only one page
		this._hide_if_single = args.hide_if_single;
		
		// If there is a step argument, set it
		this._step = args.step == null ? 1 : args.step;
		
		// Set up the scrolling function
		this._scrollFun = new Fx.Scroll(this._viewport, {
			transition: args.transition,
			wait: false
		});
		
		// Set the viewport fix height flag
		this._viewport_fix_height = args.viewport_fix_height;
		this._viewport_fix_height_transition = args.viewport_fix_height_transition;
		
		// Set up the viewport fix height transition function
		this._fixHeightFun = new Fx.Style(this._viewport, 'height', {
			transition: args.viewport_fix_height_transition == null ?
							args.transition : args.viewport_fix_height_transition,
			wait: false
		});
		
		// Set up the onScroll function if it exists
		if(args.on_scroll) {
			this._onScroll = args.on_scroll;
		}
		
		// Get the caption and set the template text
		this._caption = args.pager_caption;
		this._caption_tmpl = this._caption.getText();
		
		// Find the array of items
		this._items = $$('#' + this._viewport.id + ' .scroll-item');

		// Set the initial index
		this._currentIndex = 0;
		
		// Set the initial caption
		this._setCaption();
		
		// Make sure the viewport is pointing at the current index
		this._moveTo(this._currentIndex);
		
		// Set visibility
		this._setVisibility();
	},
	
	/**
	 * Focuses on the element
	 * 
	 * @param {Object} element
	 */
	focusOn: function(element) {
		// Find the element in the items index
		var elementIndex = this._items.indexOf(element);
		// Find the index given the number of steps
		var moveIndex = elementIndex - (elementIndex % this._step);
		// Roll the correct number of steps to focus on the element
		this._roll(this._currentIndex + moveIndex);
	},
	
	/**
	 * Injects a link that calls the given JavaScript function when clicked, 
	 * using the item's text as the link text
	 * 
	 * @param {Element} el		The element to inject the link into
	 * @param {Function} fun	The function the link should call when clicked
	 */
	injectLink: function(el, fun) {
		// Get the inner html and empty the element
		var html = el.innerHTML;
		el.empty();
		
		// Construct the link
		var link = new Element('a', {
			'href': 'javascript:void(0)',
			'events': {
				'click': fun
			}
		});
		
		// Set the link's HTML to the old element HTML
		link.setHTML(html);
		
		// Inject the link into the element
		link.injectInside(el);
	},
	
	/**
	 * Step forwards
	 */
	stepForwards: function() {
		this._roll(this._step);
	},
	
	/**
	 * Step backwards
	 */
	stepBackwards: function() {
		this._roll(this._step * -1);
	},
	
	/**
	 * Rolls the item the specified number of steps, forwards or backwards
	 * 
	 * @param {int} steps	The number of steps to roll. Can be a positive or negative number
	 */
	_roll: function(steps) {
		var newIndex = this._currentIndex + steps;
		
		// Bounds check
		if(newIndex < 0 || newIndex >= this._items.length) {
			return;
		}
		
		// Set the new index
		this._currentIndex = newIndex;
		
		// Move the viewport to point to the new item by index
		this._moveTo(this._currentIndex);
		
		// Set the caption
		this._setCaption();
		
		// Set visibility
		this._setVisibility();
		
		// Run the onScroll function if it exists
		if(this._onScroll) {
			this._onScroll(this._items[this._currentIndex]);
		}
	},
	
	/**
	 * Sets the caption of the scroller
	 */
	_setCaption: function() {
		current = this._currentIndex + 1;
		
		if (this._step > 1) {
			current_end = this._currentIndex + this._step > this._items.length ? 
				this._items.length : 
				this._currentIndex + this._step;
				
			current = current + '&ndash;' + current_end;
		}
		
		this._caption.setHTML(
			this._caption_tmpl.
				replace(/{current}/, current).
				replace(/{total}/, this._items.length)
		);
	},
	
	/**
	 * Sets the visibility of the arrows
	 */
	_setVisibility: function() {
		
		// Hide the specified element if there is only one page
		if(this._items.length <= 1 && this._hide_if_single != null) {
			this._hide_if_single.setStyle('display', 'none');
		}
		
		if (this._currentIndex == 0) {
			this._pager_prev.className = 'hidden';
		} else {
			this._pager_prev.className = 'visible';
		}

		if (this._currentIndex + this._step >= this._items.length) {
			this._pager_next.className = 'hidden';
		} else {
			this._pager_next.className = 'visible';
		}
	},


	/**
	 * Moves the viewport to point at the given index
	 * @param {Object} index
	 */
	_moveTo: function(index) {
		// Stop any currently running transition
		this._scrollFun.stop();
		
		// Point the viewport to the new item
		this._scrollFun.toElement(this._items[index]);
		
		// If the viewport_fix_height flag is set, fix the viewport 
		// height based on the height of the current scroll item
		if(this._viewport_fix_height) {
			this._fixHeightFun.stop();
			this._fixHeightFun.start(this._items[index].getStyle('height'));
		}
	}
});
