/**************************************
// requires Prototype + Scriptaculous (effects)
// call after dom is loaded:
//    document.observe("dom:loaded", function() { ... });
//
// USAGE
//
// EXAMPLE 1 - Scrolling a div filled with text

var scrollArea; //define this in the global scope

document.observe("dom:loaded", function() {
	
	// set block size to line height
	blockSize = parseFloat($('content').getStyle('line-height'));
	
	scrollArea = new ScrollArea('content',
		{ "blockSize": blockSize,
			"blocksPreservedPerPage": 1,
			"width": 200,
			"height": 310,
			"scrollDirection": "x"
		});

	listPages();

});

function listPages() {
	$('pagination').update('');
	for(var i=0; i<scrollArea.totalPages; i++) {
		//assumes the existence of a div with id="pagination"
		$('pagination').insert('<a href="javascript:scrollArea.setPage('+i+');">'+(i+1)+'<\/a> ');
	}
}

//*************************************/

var ScrollArea = Class.create({

	initialize: function(target, paramsObj) {
		
		this.computing = true;
		
		this.target = $(target);
		
		if(this.target.getStyle('top') == null) this.target.setStyle({'top': '0px'});
		if(this.target.getStyle('left') == null) this.target.setStyle({'left': '0px'});
		
		//first, set up defaults for params
		this.blockSize = 1;
		this.blocksPreservedPerPage = 0;
		this.wrapper = undefined;
		this.width = 100;
		this.height = 100;
		this.scrollDirection = "y"; //can be "x" or "y"; this must be set "y" by default for the code below to work
		this.minDiffForScroll = 5;
		
		//next, load any params that exist in the definition
		if(paramsObj.blockSize) this.blockSize = parseFloat(paramsObj.blockSize);
		if(this.blockSize == 0) this.blockSize = 1;
		if(paramsObj.blocksPreservedPerPage) this.blocksPreservedPerPage = paramsObj.blocksPreservedPerPage;
		if(paramsObj.wrapper) this.wrapper = $(paramsObj.wrapper);
		if(paramsObj.width) this.width = paramsObj.width;
		if(paramsObj.height) this.height = paramsObj.height;
		if(paramsObj.scrollDirection == "x") this.scrollDirection = "x"; //only allows "y", set above, or "x", set here
		
		//set up defaults for properties that cannot be specified in params
		this.page = 0;
		this.totalPages = 1;
		
		//initialize
		
		if(paramsObj.totalTargetHeight) {
			this.targetHeight = paramsObj.totalTargetHeight;
		} else {
			this.targetHeight = this.target.getHeight();
		}

		this.targetWidth = this.target.getWidth();
		
		if(this.wrapper == undefined) {
			this.wrapper = Element.wrap(target, 'div', {id: "wrapper", style: "overflow: hidden; width: "+this.width+"px; height: " + this.height + "px;border:0px;padding:0px;margin:0px;"});
		}
		
		this.wrapper.absolutize().relativize();
		this.setWidth(this.width);
		this.setHeight(this.height);
		this.reduceWrapperDimensionToMultipleOfBlockSize();
		this.calculateTotalPages();
		
		this.computing = false;
		
	},
	
	getInnerDimensionOfWrapper: function() {
		if(this.scrollDirection == "x") {
			return this.wrapper.getWidth() - 
				parseFloat(this.wrapper.getStyle('border-left-width')) -
				parseFloat(this.wrapper.getStyle('border-right-width'));
		} else {
			return this.wrapper.getHeight() - 
				parseFloat(this.wrapper.getStyle('border-top-width')) -
				parseFloat(this.wrapper.getStyle('border-bottom-width'));
		}
	},
	
	reduceWrapperDimensionToMultipleOfBlockSize: function() {
	
		if(this.calculateTotalPages() == 1) return;
	
		// adjust wrapper dimension to be smaller, if necessary, so that partial blocks do not show
		if(this.scrollDirection == "x") {
			this.setWidth(this.getInnerDimensionOfWrapper() - this.getInnerDimensionOfWrapper()%this.blockSize);
			return this.width;
		} else {
			this.setHeight(this.getInnerDimensionOfWrapper() - this.getInnerDimensionOfWrapper()%this.blockSize);
			return this.height;
		}
	},
	
	calculateTotalPages: function() {
		// calculate the total number of pages necessary.
		// note that this is a 2-step process, because the number of pages does not (and cannot) initially
		// consider the added length of the summed offsets
		
		var targetDimension = this.targetHeight;
		if(this.scrollDirection == "x")
			targetDimension = this.targetWidth;
		
		//alert("calc: " + targetDimension + "::" + this.getInnerDimensionOfWrapper() );
		if( targetDimension <= this.getInnerDimensionOfWrapper() ) return 1;
		
		var totalPages = 0;
		totalPages = Math.ceil( targetDimension / this.getInnerDimensionOfWrapper() );
		totalPages = Math.ceil( ( targetDimension + (totalPages * this.blockSize * this.blocksPreservedPerPage) ) / this.getInnerDimensionOfWrapper() );
		
		this.totalPages = totalPages;
		return this.totalPages;
	},
	
	scroll: function(target, params) {
		new Effect.Move(target, params);
	},
	
	//GETTERS & SETTERS
	
	// WIDTH
	setWidth: function(width) {
		this.width = parseFloat(width);
		this.wrapper.setStyle({
			"width" : this.width + 'px'
		});
		
		if(!this.computing) {
			this.computing = true;
			this.reduceWrapperDimensionToMultipleOfBlockSize();
			this.calculateTotalPages();
			this.computing = false;
		}
		
		return this.width;
	},
	
	getWidth: function() {
		return this.width;
	},
	
	// HEIGHT
	setHeight: function(height) {
		this.height = parseFloat(height);
		this.wrapper.setStyle({
			"height" : this.height + 'px'
		});
		
		if(!this.computing) {
			this.computing = true;
			this.reduceWrapperDimensionToMultipleOfBlockSize();
			this.calculateTotalPages();
			this.computing = false;
		}
		
		return this.height;
	},
	
	getHeight: function() {
		return this.height;
	},
	
	// PAGES
	setPage: function(n, animateScroll) {
	
		if(animateScroll != false)animateScroll=true;
		
		n = parseInt(n);
		
		var isScrollingToNextPage = (n > this.page);
	
		if(n <= this.totalPages) {

			this.page = n;
			
			if(this.scrollDirection == "x") {
			
				var diff = -1 *
					(parseFloat(this.target.getStyle('left')) + 
					(
					this.page * 
						(
						this.getInnerDimensionOfWrapper() - 
						(this.blockSize * this.blocksPreservedPerPage)
						)
					))
					
					var targetRight = parseFloat(this.target.getStyle('left')) + this.target.getWidth();
					
					//$('output').insert("<br />"+targetRight + "," + (targetRight+diff) + "," + this.getInnerDimensionOfWrapper());
					
					if( (targetRight+diff) < this.getInnerDimensionOfWrapper() ) {
						diff = diff + (this.getInnerDimensionOfWrapper()-(targetRight+diff) );
						if(diff < this.minDiffForScroll) diff = 0;
					}
				if(diff != 0) {
					if(animateScroll) {
						this.scroll(this.target, {"x": diff, "y": 0, "duration": 0.6});
					} else {
						this.target.setStyle({left: diff + "px", position: "relative"});
					}
				} else {
					if(this.page > 0) this.page = n-1;
				}

			} else {
			
				var diff = -1 *
					(parseFloat(this.target.getStyle('top')) + 
					(
					this.page * 
						(
						this.getInnerDimensionOfWrapper() - 
						(this.blockSize * this.blocksPreservedPerPage)
						)
					))

				this.scroll(this.target, {"x": 0, "y": diff, "duration": 0.3});
			}
			
		}

		//no return
		
	},
	
	getPage: function() {
		return this.page;
	},
	
	gotoNextPage: function() {
		if((this.page+1) < this.totalPages) {
			this.setPage(this.page+1);
		}
	},
	
	gotoPreviousPage: function() {
		if(this.page > 0) {
			this.setPage(this.page-1);
		}
	}

});
