/*
JavaScript Scroller with image preloader
Adrian Hope-Bailie (November 2007)
adrian@hopebailie.com
http://adrian.hopebailie.com
Sine function is borrowed although I'm not sure where from?
*/

var Scroller = Class.create();
Scroller.prototype = {
	Frame: null,
	Content: null,
	CurrentSection: 0,
	ForwardScroller: null,
	BackwardScroller: null,
	ID: '',
	Options: {
			rewind: true, 
			ajax: {URL: null, callback: null, param: 'section', loader: null, maxSections: null}, 
			direction: 'horizontal',
			tabbed: false,
			imageLoader: {src: null, selector: 'img'},
			nocontent: null,
			debug: false
		},
	SectionClassname: '',
	Animator: {time:0, begin:0, change:0.0, duration:0.0, element:null, timer:null},

	initialize: function(frame,  backwardScroller, forwardScroller) {

		this.Options = Object.extend(this.Options, arguments[3] || {});

		this.ForwardScroller = $(forwardScroller);
		this.BackwardScroller = $(backwardScroller);		

		//Build Scroller
		var dimensions = $(frame).getDimensions();
//		Position.relativize(frame);
		$(frame).style.overflow = 'hidden';
		$(frame).innerHTML = '<div style="overflow: hidden;">' + 
			(this.Options.tabbed ? $(frame).innerHTML : '<div>'+$(frame).innerHTML+'</div>') +
			'</div>';
		this.ID = ($(frame).id !== '') ? $(frame).id : Math.random()*9999;
		this.Frame = $(frame).firstDescendant();
		this.Frame.style.width = dimensions.width + 'px';
		this.Frame.style.height = dimensions.height + 'px';
		
		this.SetContent(this.Frame.firstDescendant());

		this.ScrollForward = this.Scroll.bindAsEventListener(this, 'forward');
		this.ScrollBackward = this.Scroll.bindAsEventListener(this, 'backward');
		this.ProcessNewSection = this._processNewSection.bindAsEventListener(this);
		
		Event.observe(this.ForwardScroller, 'click', this.ScrollForward);
		Event.observe(this.BackwardScroller, 'click', this.ScrollBackward);		

	},// function initialize
	
	Unbind: function(){
		Event.stopObserving(this.ForwardScroller, 'click', this.ScrollForward);
		Event.stopObserving(this.BackwardScroller, 'click', this.ScrollBackward);
	},
	
	SetContent: function(contentElement){
		this.Content = $(contentElement);
		var currentSections = this.Content.immediateDescendants().size();
		
		var maxSections = (null !== this.Options.ajax.maxSections) ? this.Options.ajax.maxSections : currentSections;
		if(this.Options.direction == 'horizontal'){
			this.Content.style.width = (this.Frame.getWidth() * (maxSections + 1)) + 'px';
		} else {
			this.Content.style.height = (this.Frame.getHeight() * (maxSections + 1)) + 'px';
		}
		if(false === this.Options.rewind || currentSections < 2){
			//this.BackwardScroller.hide();
		}
		if(currentSections > 0){
			this.SectionClassname = this.Content.firstDescendant().className;
			this.Content.immediateDescendants().each(function(section){
					this._processNewSection(section);
				}.bind(this));
			if(currentSections > 1){
				this.ForwardScroller.show();
			} else {
				this.ForwardScroller.show();
			}
		} else {
			//var html = '<div>empty</div>';
			//this.ForwardScroller.hide();
			if(null !== this.Options.nocontent) {
				if($(this.Options.nocontent)){
					html = '<div>'+$(this.Options.nocontent).innerHTML+'</div>';
				} else {
					html = '<div>'+this.Options.nocontent+'</div>';
				}
			}
			this.Content.innerHTML = html;
		}
		this.ScrollTo(0, this.BackwardDir);
		this.Content.show();
	},
	
	Scroll: function(event, direction) { 
		var Sections = this.Content.immediateDescendants();
		
		if (direction == "backward") {
			if (this.CurrentSection - 1 < 0) { //Already at the beginning
				if(this.Options.rewind){
					this.ScrollTo(Sections.length - 1);
				} else {
					//this.BackwardScroller.hide();
				}
			} else {
				this.ScrollTo(this.CurrentSection - 1);
				if(this.CurrentSection  <= 0){
					//this.BackwardScroller.hide();
				}
			}
			if(Sections.size() > 1){
				this.ForwardScroller.show();
			}
		} else {
			if ((this.CurrentSection + 1) > (Sections.length - 1)) { //Already at the end
				if(this.Options.rewind){
						this.ScrollTo(0);
				} else {
					//this.ForwardScroller.hide();
				}
			} else {
				this.ScrollTo(this.CurrentSection + 1);
				if(this.AddSection(this.CurrentSection + 1) == false){
					//this.ForwardScroller.hide();
				}
			}
			if(this.CurrentSection  > 0){
				this.BackwardScroller.show();
			}
		}
	}, //function Scroll

	AddSection: function(number){
		//Max # of sections already loaded
		if(null !== this.Options.ajax.maxSections && number >= this.Options.ajax.maxSections){
			return false;
		}
		//No ajax URL defined for fetching new sections
		if(null === this.Options.ajax.URL){
			return false;
		}
		var Sections = this.Content.immediateDescendants();
		//Section already exists
		if(number < Sections.length){
			return true;
		}
		//Insert loader
		var tag, html;
		var loaderId = this.ID+'-section-loader-'+number;
		try{
			tag = $(this.Options.ajax.loader).tagName.toLowerCase();
			html = ($(this.Options.ajax.loader).innerHTML || '');
		} catch (e){
			tag = 'div';
			html = 'Loading...';
		}
		
		html = '<'+tag+' id="'+loaderId+'" class="'+this.SectionClassname+'" '+
				((this.Options.direction == 'horizontal') ? ' style="float: left;" ' : '') +
				((html != '') ? '>'+html+'</'+tag+'>' : '/>');
		new Insertion.Bottom(this.Content, html);

		//Increase size of content div ?
		if(null === this.Options.ajax.maxSections){
			if(this.Options.direction == 'horizontal'){
				this.Content.style.width = (this.Frame.getWidth() * (Sections.size() + 2)) + 'px';
			} else {
				this.Content.style.height = (this.Frame.getHeight() * (Sections.size() + 2)) + 'px';
			}
		}
		
		//Execute ajax
		var ajaxParams = new Hash();
		ajaxParams[(this.Options.ajax.param || 'section')] = number;
		new Ajax.Request(
			this.Options.ajax.URL, {
			   method:'get',
			   onSuccess: this._ajaxCallback.bindAsEventListener(this, number),
			   parameters: ajaxParams
		});
		return true;
	}, //function AddSection

	_ajaxCallback: function(transport, number){
		if(transport.responseText === ''){
			if(this.Options.rewind === false){
				this.ForwardScroller.hide();
			}
			$(this.ID+'-section-loader-'+number).remove();
			if(this.Options.ajax.maxSections > number){
				this.Options.ajax.maxSections = number;
			}
			if(this.CurrentSection > (this.Options.ajax.maxSections - 1)){
				this.ScrollTo(this.Options.ajax.maxSections - 1);
			}
		} else {
			$(this.ID+'-section-loader-'+number).replace(transport.responseText);
			var Sections = this.Content.immediateDescendants();
			this.ProcessNewSection(Sections[number]);
		}
	},

	_processNewSection: function(section){
		if(this.Options.direction == 'horizontal'){
			section.setStyle({cssFloat: "left"});
		}
		if(null !== this.Options.imageLoader.src){
			var images = $(section).getElementsBySelector(this.Options.imageLoader.selector);
			images.each(function(img){
				var preloader = new Image();
				var finalSrc = img.src + '';
//				new Ajax.Request(
//					final, {method:'get', onSuccess: function(transport, src){this.src = src}.bindAsEventListener(img, final)});
				Event.observe(preloader, 'load', function(e, src){this.src = src;}.bindAsEventListener(img, finalSrc));
				img.src = this.Options.imageLoader.src;
				preloader.src = finalSrc + '';
			}.bind(this));	
		}
		if(typeof(this.Options.ajax.callback) == "function"){
			this.Options.ajax.callback(section);
		}
	},
	
	ScrollTo: function(number){
		this.CurrentSection = number;
		var Sections = this.Content.immediateDescendants();
		targetPos = Position.cumulativeOffset(Sections[number]);
		offsetPos = Position.cumulativeOffset(Sections[0]);
		if(this.Options.direction == "horizontal"){
			endPos = targetPos[0] - offsetPos[0];
		} else {
			endPos = targetPos[1] - offsetPos[1];
		}
		this.ScrollStart(endPos);
	}, //function ScrollTo

	ScrollStart: function(end, direction){
		
		if (this.Animator.timer !== null) {
			this.Animator.timer.stop();
			this.Animator.timer = null;
		}
		this.Animator.time = 0;
		this.Animator.begin = this.Frame.scrollLeft;
		this.Animator.change = end - this.Frame.scrollLeft;
		this.Animator.duration = 25;
		this.Animator.timer = new PeriodicalExecuter(this.Animate.bindAsEventListener(this), 0.01);
	}, //function ScrollStart

	Animate: function(){
		if (this.Animator.time > this.Animator.duration) {
			this.Animator.timer.stop();
			this.Animator.timer = null;
		}
		else {
			move = this._sineInOut(this.Animator.time, this.Animator.begin, this.Animator.change, this.Animator.duration);
			if(this.Options.direction == "horizontal"){
				this.Frame.scrollLeft = move;
			} else {
				this.Frame.scrollTop = move;
			}
			this.Animator.time++;
		}
	}, //function Animate
	
	_sineInOut: function(t, b, c, d){
		return (-c/2) * (Math.cos(Math.PI*t/d) - 1) + b;
	} //function SineInOut
	
};//Object Scroller