/**
 * 
 * Find more about the scrolling function at
 * http://cubiq.org/scrolling-div-on-iphone-ipod-touch/5
 *
 * Copyright (c) 2009 Matteo Spinelli, http://cubiq.org/
 * Released under MIT license
 * http://cubiq.org/dropbox/mit-license.txt
 * 
 * Version 2.3 - Last updated: 2009.07.09
 * Modified to support horizontal scroll by phoenix3200 and rpetrich
 * 
 */
 
function iScroll(wrapper)
{
	window.setTimeout(function(t) { t.init(wrapper); }, 100, this);
}

iScroll.prototype = {
	init: function(wrapper) {
		if (typeof(window.orientation) == "number") {
			this.wrapper = wrapper;
			this.element = wrapper.children[0];
			this.lastIndex = this.element.children.length-1;
			var pipsElement = wrapper.children[1];
			if (pipsElement)
			{
				for (var i=0; i<this.element.children.length; i++) {
					var pip = document.createElement("span");
					pip.className = "pip";
					pip.innerHTML = "&bull;"
					pipsElement.appendChild(pip);
				}
				this.pips = pipsElement.children;
			}
			this._idx = 0;
			this.idx = 0;
			
			this.refreshPadding();
				
			this.position = 0;
			this.vertical = 0;
			this.refresh();
			this.element.style.webkitTransitionTimingFunction = 'cubic-bezier(0, 0, 0.2, 1)';
			this.acceleration = 0.009;
			
			wrapper.style.overflowX = 'hidden';
				
			wrapper.addEventListener('touchstart', this, true);
			window.addEventListener('orientationchange', this, true);
		}
	},

	handleEvent: function(e) {
		switch(e.type) {
			case 'touchstart': this.onTouchStart(e); break;
			case 'touchmove': this.onTouchMove(e); break;
			case 'touchend': this.onTouchEnd(e); break;
			case 'webkitTransitionEnd': this.onTransitionEnd(e); break;
			case 'orientationchange': this.onOrientationChange(e); break;
		}
	},

	get position() {
		return this._position;
	},
	
	set position(pos) {
		this._position = pos;
		this.element.style.webkitTransform = 'translate3d(' + this._position + 'px, 0, 0)';
	},
	
	get idx()
	{
		return this._idx;
	},
	
	set idx(idx)
	{
		if (this.pips) {
			this.pips[this._idx].className = "pip";
			this.pips[idx].className = "selected pip";
		}
		this._idx = idx;
	},
	
	refreshPadding: function() {
		this.wrapper.style.webkitTransform = 'translate3d(0,0,0)';
		var cw = this.wrapper.clientWidth;
		var fc = this.element.children[0];
		this.element.style.width = ((this.lastIndex + 1) * (fc.clientWidth + 10)) + (cw - fc.clientWidth) + 'px';
		this.element.style.paddingLeft = ((cw - fc.clientWidth - 20) / 2) + 'px';
	},
	
	refresh: function() {
		this.element.style.webkitTransitionDuration = '0';

		if( this.element.offsetWidth<this.wrapper.clientWidth )
			this.maxScroll = 0;
		else		
			this.maxScroll = this.wrapper.clientWidth - this.element.offsetWidth;
	},
	
	onOrientationChange: function(e) {
		this.refreshPadding();
		this.refresh();
		window.setTimeout(function(t) { t.refreshPadding(); t.refresh(); }, 100, this);
	},
	
	onTouchStart: function(e) {
		this.element.style.webkitTransitionDuration = '0';	// Remove any transition
		var theTransform = window.getComputedStyle(this.element).webkitTransform;
		theTransform = new WebKitCSSMatrix(theTransform).m41;
		if (theTransform!=this.position)
			this.position = theTransform;

		this.startX = e.targetTouches[0].clientX;
		this.startY = e.targetTouches[0].clientY;
		this.firstMove = true;
		this.scrollStartX = this.position;
		this.scrollStartTime = e.timeStamp;
		this.moved = false;

		this.wrapper.addEventListener('touchmove', this, true);
		this.wrapper.addEventListener('touchend', this, true);
		
		return false;
	},
	
	onTouchMove: function(e) {
		if (this.firstMove) {
			this.firstMove = false;
			this.inMove = Math.abs(e.targetTouches[0].clientX - this.startX) > Math.abs(e.targetTouches[0].clientY - this.startY);
			if (this.inMove)
				this.wrapper.scrollIntoView();
		}
		if (!this.inMove)
			return false;
		e.preventDefault();
		if (e.targetTouches.length != 1)
			return false;
		
		var leftDelta = e.targetTouches[0].clientX - this.startX;
		if (this.position>0 || this.position<this.maxScroll)
			leftDelta/=2;
		this.position = this.position + leftDelta;
		this.startX = e.targetTouches[0].clientX;
		this.moved = true;

		// Prevent slingshot effect
		if (e.timeStamp-this.scrollStartTime>100) {
			this.scrollStartX = this.position;
			this.scrollStartTime = e.timeStamp;
		}

		return false;
	},
	
	onTouchEnd: function(e) {
		
		this.wrapper.removeEventListener('touchmove', this, false);
		this.wrapper.removeEventListener('touchend', this, false);

		// If we are outside of the boundaries, let's go back to the sheepfold
		if( this.position>0 || this.position<this.maxScroll ) {
			this.element.style.webkitTransitionTimingFunction = 'cubic-bezier(0, 0, 0.2, 1)';
			if (this.position > 0) {
				this.scrollTo(0);
				this.idx = 0;
			} else {
				this.scrollTo(this.maxScroll);
				this.idx = this.lastIndex;
			}
			return false;
		}
		
		
		// Lame formula to calculate a fake deceleration
		var scrollDistance = this.position - this.scrollStartX;
		var scrollDuration = e.timeStamp - this.scrollStartTime;

		var newDuration = (2 * scrollDistance / scrollDuration) / this.acceleration;
		var newScrollDistance = (this.acceleration / 2) * (newDuration * newDuration);
		
		if( newDuration<0 ) {
			newDuration = -newDuration;
			newScrollDistance = -newScrollDistance;
		}
		
		var speed = scrollDistance / scrollDuration;
		if(speed < 0)
			speed = -speed;
		
		var ict = this.lastIndex;
		
		this.idx = Math.round(this.position * ict / this.maxScroll);
		var newPosition = this.maxScroll/ict * this.idx;
		if(speed > 0.3) {
			if (this.position - newPosition < 0 && scrollDistance < 0)
				this.idx = this.idx + 1;
			else if (this.position - newPosition > 0 && scrollDistance > 0)
				this.idx = this.idx - 1;
			newPosition = this.maxScroll/ict * this.idx;
			
			var newScrollDistance = newPosition - this.position;
			if(newScrollDistance < 0)
				newScrollDistance = -newScrollDistance;
			
			if(speed < 0.7)
				newScrollDistance = newScrollDistance * speed /50;
			else
				newScrollDistance = newScrollDistance / 500;
			
			this.element.style.webkitTransitionTimingFunction = 'cubic-bezier(0, 0, 0.2, 1)';
			this.scrollTo(newPosition, newScrollDistance + 's'); 
			return false;
		} else {			
			var newScrollDistance = newPosition - this.position;
			if(newScrollDistance < 0)
				newScrollDistance = -newScrollDistance;
			newScrollDistance = newScrollDistance * 5;
			
			this.element.style.webkitTransitionTimingFunction = 'cubic-bezier(0, 0, 0.2, 1)';
			this.scrollTo(newPosition, newScrollDistance + 'ms');
			return false;
		}		

		/*var newPosition = this.position + newScrollDistance;
		
		if (newPosition>this.wrapper.clientWidth/2)
			newPosition = this.wrapper.clientWidth/2;
		else if (newPosition>0)
			newPosition/= 1.5;
		else if (newPosition<this.maxScroll-this.wrapper.clientWidth/2)
			newPosition = this.maxScroll-this.wrapper.clientWidth/2;
		else if (newPosition<this.maxScroll)
			newPosition = (newPosition - this.maxScroll) / 1.5 + this.maxScroll;
		else
			newDuration *= 6;

		this.element.style.webkitTransitionTimingFunction = 'cubic-bezier(0, 0, 0.2, 1)';
		this.scrollTo(newPosition, Math.round(newDuration) + 'ms');

		return false;*/
	},
	
	onTransitionEnd: function() {
		this.wrapper.removeEventListener('webkitTransitionEnd', this, false);
		this.element.style.webkitTransitionTimingFunction = 'cubic-bezier(1, 0.2, 0.2, 1)';
		this.scrollTo( this.position>0 ? 0 : this.maxScroll );
	},
	
	scrollTo: function(dest, runtime) {
		this.element.style.webkitTransitionDuration = runtime ? runtime : '300ms';
		this.position = dest ? dest : 0;

		// If we are outside of the boundaries at the end of the transition go back to the sheepfold
		if( this.position>0 || this.position<this.maxScroll )
			this.wrapper.addEventListener('webkitTransitionEnd', this, true);
	}
};
