/**
 * 
 * Find more about the scrolling function at
 * http://cubiq.org/scrolling-div-for-mobile-webkit-turns-3/16
 *
 * Copyright (c) 2009 Matteo Spinelli, http://cubiq.org/
 * Released under MIT license
 * http://cubiq.org/dropbox/mit-license.txt
 * 
 * Version 3.0beta4 - Last updated: 2010.04.02
 * 
 */

function iScroll (el, options) {
	this.element = typeof el == 'object' ? el : document.getElementById(el);
	this.wrapper = this.element.parentNode;
	this.numChildren = $(this.element).children('li').size();
	this.childWidth = $(this.element).children('li').width();

	//this.wrapper.style.overflow = 'hidden';
	this.wrapper.style.position = 'relative';
	this.element.style.position = 'relative';
	this.element.style.webkitTransitionProperty = 'margin-left';
	this.element.style.webkitTransitionTimingFunction = 'cubic-bezier(0,0,0.25,1)';
	this.element.style.webkitTransitionDuration = '0';
	this.element.style.marginLeft = 0 + 'px';

	// Get options
	this.options = {
		bounce: true,
		moveCallback: null,
		endCallback: null,
	};
	
	if (typeof options == 'object') {
		for (var i in options) {
			this.options[i] = options[i];
		}
	}

	this.refresh();
	
	this.element.addEventListener('touchstart', this);
	this.element.addEventListener('touchmove', this);
	this.element.addEventListener('touchend', this);
}

iScroll.prototype = {
	_x: 0,
	_y: 0,

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

	refresh: function () {
		this.scrollWidth = this.wrapper.clientWidth - 208;
		this.maxScrollX = this.scrollWidth - this.element.offsetWidth;
		this.scrollX = true;
	},

	get x() {
		return this._x;
	},

	setPosition: function (x, duration) { 
		this._x = x !== null ? Math.min(x,0) : this._x;
		this._x = Math.max(this._x, -1 * (this.numChildren - 1) * this.childWidth);
		
		if(!duration)
		    duration = 0;
		else
		    duration = parseInt(duration);
		
		
		$(this.element).animate({'marginLeft': this._x + 'px'},{duration: duration, queue: false});
		//this.element.style.marginLeft = this._x + 'px';
		
		try{
		    if(this.options.moveCallback){
		        this.options.moveCallback(this._x, duration);
		    }
		}catch (err){}
	},
		
	onTouchStart: function(e) {
	    if (e.targetTouches.length != 1) {
	        return false;
        }
        
		e.preventDefault();
		e.stopPropagation();
		
		if(this.element.style.marginLeft)
		    this._x = parseInt(this.element.style.marginLeft);
		
		this.element.style.webkitTransitionDuration = '0';
		
		this.touchStartX = e.touches[0].pageX;
		this.scrollStartX = this.x;	

		this.scrollStartTime = e.timeStamp;
		this.moved = false;
	},
	
	onTouchMove: function(e) {
		if (e.targetTouches.length != 1) {
			return false;
		}

		var leftDelta = this.scrollX === true ? e.touches[0].pageX - this.touchStartX : 0;

		if (this.x > 0 || this.x < this.maxScrollX) { 
			leftDelta = Math.round(leftDelta / 4);		// Slow down if outside of the boundaries
		}
		
		this.setPosition(this.x + leftDelta);

		this.touchStartX = e.touches[0].pageX;
		this.moved = true;

		// Prevent slingshot effect
		if( e.timeStamp-this.scrollStartTime > 250 ) {
			this.scrollStartX = this.x;
			this.scrollStartTime = e.timeStamp;
		}
	},
	
	onTouchEnd: function(e) {
		if (e.targetTouches.length > 0) {
			return false;
		}

		if (!this.moved) {
			var theEvent = document.createEvent('MouseEvents');
			theEvent.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null);
			e.changedTouches[0].target.dispatchEvent(theEvent);		
			return false;
		}

		this.scrollTo(this.x);

	},

	resetPosition: function () {
		var resetX = null;
		if (this.x > 0 || this.x < this.maxScrollX) {
			resetX = this.x >= 0 ? 0 : this.maxScrollX;
		}

		if (resetX !== null) {
			this.scrollTo(resetX);
		}
	},

	scrollTo: function (destX) {
		//math to calculate next available slot
		var index = -1 * Math.round(this._x / this.childWidth);
		$('#controls').children('li').removeClass('current');
		$('#controls' + (index + 1)).addClass('current');
		this.setPosition(-1 * index * this.childWidth, 300);
	},

	momentum: function (dist, time, maxDist1, maxDist2) {
		friction = 0.1;
		deceleration = 1.5;

		var speed = Math.abs(dist) / time * 1000;
		var newDist = speed * speed / (20 * friction) / 1000;

		// Proportinally reduce speed if we are outside of the boundaries 
		if (dist > 0 && maxDist1 !== undefined && newDist > maxDist1) {
			speed = speed * maxDist1 / newDist;
			newDist = maxDist1;
		}
		if (dist < 0 && maxDist2 !== undefined && newDist > maxDist2) {
			speed = speed * maxDist2 / newDist;
			newDist = maxDist2;
		}
		
		newDist = newDist * (dist < 0 ? -1 : 1);
		
		var newTime = -speed / -deceleration;
		if (newTime < 1) {	// We can't go back in time
			newTime = 1;
		}

		return { dist: Math.round(newDist), time: Math.round(newTime) };
	}
};

