/**
 * Slider Simulator
 * 
 */

if (typeof(AC) == "undefined") AC = {};


AC.Slider = Class.create();
AC.Slider.prototype = {
	orientation: 'horizontal',
	container: null,
	items: null,
	currentPage: 1,
	itemsPerPage: null,
	totalPages: null,
	maskInnerDimension: null,
	isAnimating: false,
	
	initialize: function(containerId, sliderElements) {
		this.items = new Array();
		
		this.container = $(containerId);
		this.populate(sliderElements);
	},
	
	populate: function() {
		this.container.innerHTML = 'The slider requires population with data. You need to call this.render(itemsPerList) from your custom this.populate() function.';
		// ????? throw new TypeError('The slider requires population with data. You need to call this.render(itemsPerList) from your custom this.populate() function.');
	},
	
	render: function(itemsPerList) {
		this.container.innerHTML = '';
		
		// TODO figure out the itemsPerList when it's not specified
		this.itemsPerPage = itemsPerList;

		this.list = Builder.node('ul', this.renderItems() );
		var mask = Builder.node('div', { 'class':'ACSliderMaskDiv' }, [this.list]);
		this.container.appendChild(mask);

		this.positionWithinMask(mask);


		this.totalPages = Math.ceil(this.items.length/this.itemsPerPage);
		
		if (this.items.length > this.itemsPerPage) {
			this.createArrows();
			this.createDots();
		}
	},

	positionWithinMask: function(mask) {
		
		if (this.orientation == 'horizontal') {
			this.maskInnerDimension = Element.getInnerDimensions(mask).width;
			this.list.style.left = -this.maskInnerDimension*this.currentPage +'px';
		} else {
			this.maskInnerDimension = Element.getInnerDimensions(mask).height;
			this.list.style.top = -this.maskInnerDimension*this.currentPage +'px';
		}
	},

	renderItems: function() {
		var list = [];
		var lastPageStart = this.items.length-this.items.length%this.itemsPerPage;
		if (lastPageStart==this.items.length) lastPageStart = this.items.length-this.itemsPerPage;
		var overflowAmount = this.itemsPerPage-this.items.length%this.itemsPerPage;
		if (overflowAmount==this.itemsPerPage) overflowAmount = 0;
		
		var multiplePages = this.items.length > this.itemsPerPage;
		
		// copy the last page before the first page
		if (multiplePages) {
			list.push(this.renderPlaceholderItems(lastPageStart, this.items.length));
			
			// empty nodes as space filler before the all the pages
			for (var i=0; i<overflowAmount; i++) {
				var listItem = Builder.node('li', {'class': 'empty'});
				list.push(listItem);
			}
		}

		// create all the pages
		for (var i=0; i<this.items.length; i++) {
			var listItem = this.items[i].render().cloneNode(true);
			list.push(listItem);
		}

		if (multiplePages) {
			// empty nodes as space filler before the copy of the first page
			for (var i=0; i<overflowAmount; i++) {
				var listItem = Builder.node('li', {'class': 'empty'});
				list.push(listItem);
			}

			// copy the first page after the last page
			list.push(this.renderPlaceholderItems(0, this.itemsPerPage));
		}

		return list;
	},

	renderPlaceholderItems: function(start, finish) {
		var list = [];
		for (var i=start; i<finish; i++) {
			var listItem = this.items[i].render().cloneNode(true);
			// try and retain unique ids
			if (listItem.id) listItem.removeAttribute(id);
			for (var j=0, child; child=listItem.childNodes[j]; j++) {
				if (child.getAttribute('id')) child.removeAttribute('id');
			}
			$(listItem).addClassName('cloned');
			list.push(listItem);
		}
		return list;
	},

	createArrows: function() {
		// previous arrow
		var prevArrow = Builder.node('a', { 'class':'ACSliderPreviousArrow' }, '&lt;');
		$(prevArrow).observe('click', function(evt) {
			Event.stop(evt);
			this.getPrevious();
		}.bind(this));
		this.container.appendChild(prevArrow);
		
		// next arrow
		var nextArrow = Builder.node('a', { 'class':'ACSliderNextArrow' }, '&gt;');
		$(nextArrow).observe('click', function(evt) {
			Event.stop(evt);
			this.getNext();
		}.bind(this));
		this.container.appendChild(nextArrow);
	},

	createDots: function() {
		this.pageNav = Builder.node('ul', { 'class':'ACSliderPageNav' });
		
		for (var i=1; i<=this.totalPages; i++) {
			var navListItemAnchor = (i==this.currentPage) ? Builder.node('a', { 'class':'active' }, i) : Builder.node('a', i);
			$(navListItemAnchor).observe('click', function(evt, pageNumber) {
				Event.stop(evt);
				this.scrolltoPageNumber(pageNumber);
			}.bindAsEventListener(this, i));

			var navListItem = Builder.node('li', [navListItemAnchor]);
			this.pageNav.appendChild(navListItem);
		}
		
		this.container.appendChild(this.pageNav);
	},

	getPrevious: function() {
		var previousPageIndex = this.currentPage - 1;
		this.scrolltoPageNumber(previousPageIndex, 1);
	},
	
	getNext: function() {
		var nextPageIndex = this.currentPage + 1;
		this.scrolltoPageNumber(nextPageIndex, -1);
	},
	
	scrolltoPageNumber: function(toPageNumber, direction) {
		// if we're not going to the current page & we're not already doing something ...
		if (this.currentPage != toPageNumber && !this.isAnimating) {

			// if we don't know the direction, figure it out (-1 is next, 1 is previous)
			if (!direction) var direction = this.currentPage-toPageNumber;

			this.isAnimating = true;
			
			// set the current page to the one we're going to
			this.currentPage = toPageNumber;
			// and fix the number if we're going to before the first page or page after the last page
			this.resetPages();

			// remove the 'active' class on the page nav items
			var pageNavAnchors = this.pageNav.getElementsByTagName('a');
			for (var i=0, anchor; anchor=pageNavAnchors[i]; i++) {
				if (Element.hasClassName(anchor, 'active')) Element.removeClassName(anchor, 'active');
				if (anchor.innerHTML==this.currentPage) Element.addClassName(anchor, 'active');
			}
			// try {console.debug(this.list,"Scrolling to page", toPageNumber);} catch(e) {}
			// do the scroll
			var options = { 
				duration: 0.5,
				queue: { position:'end', scope:'sliderQueue', limit:1 },
				afterFinish: this.afterScroll.bind(this) 
			};
			
			// TODO slider needs to be reworked, pretty inflexible
			//may not always have the mask dimensions prior to this point.
			//probably need to maintain a reference to the mask itself to 
			//recalculate the dimendions if necessary. Only recalculating 
			//if it's 0 right now but could do it more often to aid in
			//flexibile resizing
			if (!this.maskInnerDimension) {
				this.positionWithinMask(this.container);
			}
			
			if (this.orientation == 'horizontal') {
				// try {console.debug("X: ", this.maskInnerDimension*direction);} catch(e) {}
				new Effect.MoveBy(this.list, 0, this.maskInnerDimension*direction, options);
			} else {
				new Effect.MoveBy(this.list, this.maskInnerDimension*direction, 0, options);
			}
		}
	},

	jumptoPageNumber: function(toPageNumber) {
		// if we're not going to the current page & we're not already doing something ...
		if (this.currentPage != toPageNumber && !this.isAnimating) {

			// figure out the direction (-1 is next, 1 is previous)
			var direction = this.currentPage-toPageNumber;

			// set the current page to the one we're going to
			this.currentPage = toPageNumber;
			// and fix the number if we're going to before the first page or page after the last page
			this.resetPages();

			// remove the 'active' class on the page nav items
			var pageNavAnchors = this.pageNav.getElementsByTagName('a');
			for (var i=0, anchor; anchor=pageNavAnchors[i]; i++) {
				if (Element.hasClassName(anchor, 'active')) Element.removeClassName(anchor, 'active');
				if (anchor.innerHTML==this.currentPage) Element.addClassName(anchor, 'active');
			}
			
			var options = {
				duration: 0.0};
			
			// do the scroll
			if (this.orientation == 'horizontal') {
				new Effect.MoveBy(this.list, 0, this.maskInnerDimension*direction, options);
			} else {
				new Effect.MoveBy(this.list, this.maskInnerDimension*direction, 0, options);
			}
		}
	},

	resetPages: function() {
		if (this.currentPage == 0) {
			this.currentPage = this.totalPages;
			this.positionOffset = -this.maskInnerDimension*this.totalPages +'px';
		} else if (this.currentPage == this.totalPages+1) {
			this.currentPage = 1;
			this.positionOffset = -this.maskInnerDimension+'px';
		} else {
			this.positionOffset = false;
		}
	},

	afterScroll: function() {
		// set the position of the list to the actual page number position value
		if (this.positionOffset) {
			if (this.orientation == 'horizontal') {
				this.list.style.left = this.positionOffset;
			} else {
				this.list.style.top = this.positionOffset;
			}
		}

		// reset the animating flag
		this.isAnimating = false;
	},

	jumpToPage: function(toPageNumber) {
	}	
	
};

AC.SliderItem = Class.create();
AC.SliderItem.prototype = {
	html: 'List items must be populated with data; it can be an HTML object or HTML as a string.',

	initialize: function(input) {
		if (input) this.html = input;
		// ???? else throw new TypeError(this.html);
	},
	
	render: function() {
		if (typeof(this.html) == 'string') {
			var li = Builder.node('li');
			li.innerHTML = this.html;
		} else {
			var li = Builder.node('li', [this.html]);
		}
		return li;
	}
};

	
