(function(window){

function ScrollContents(){
	this.initialize.apply(this,arguments);
}
var p = ScrollContents.prototype;
	p.element = null;
	p.containerElement = null;
	p.controlElement = null;

	p._top = 0;
	p._left = 0;

	p.startElementPosition = null;
	p.startMousePosition = null;
	p.moveMousePosition = null;
	p.mouseHistory = null;
	p.eventStack = null;

	p.isDragging = false;
	p.moveTimerId = null;
	p.callBackStack = null;

	p.isActive = false;

	p.loopHeight = 0;

	p.initialize = function(contentsElement,containerElement,controlElement,loopHeight){
		this.element = contentsElement;
		this.containerElement = containerElement;
		this.controlElement = controlElement;
		this.loopHeight = loopHeight;
		this.callBackStack = {};
		this.eventStack = [];
	}
	p.active = function(bool){
		if(bool){
			this.isActive = true;
			this.eventStack["MouseDown"] = addListener(this.controlElement,"mousedown",this.onTouchStart,this,null,true,true);
			this.eventStack["TouchStart"] = addListener(this.controlElement,"touchstart",this.onTouchStart,this,null,false,true);
			this.eventStack["MouseWheel"] = addListener(window,"mousewheel",this.onWheel,this,null,false,true);
			this.eventStack["MouseWheel2"] = addListener(document,"mousewheel",this.onWheel,this,null,false,true);
		}
		else{
			removeListener(this.eventStack["MouseDown"]);
			removeListener(this.eventStack["TouchStart"]);
			removeListener(this.eventStack["MouseWheel"]);
			removeListener(this.eventStack["MouseWheel2"]);
		}
	}
	p.onWheel = function(e){
		clearTimeout(this.moveTimerId);
		var delta;
		if(e && e.detail) delta =  e.detail;
		else if(event.wheelDelta) delta = -event.wheelDelta;
		if(delta < 0) delta = 20;
		else delta = -20;
		this.inertia(delta);
	}
	p.onTouchStart = function(e){
		this.isDragging = true;
		var mouseX = getPointer(e).x;
		var mouseY = getPointer(e).y;
		this.startMousePosition = {x:mouseX,y:mouseY};
		this.moveMousePosition = {x:mouseX,y:mouseY};
		this.startElementPosition = {left:this.left(),top:this.top()};
		this.mouseHistory = [{x:mouseX,y:mouseY},{x:mouseX,y:mouseY},{x:mouseX,y:mouseY}];
		this.stop();
		this.eventStack["MouseMove"] = addListener(document,"mousemove",this.onTouchMove,this,null,true,true);
		this.eventStack["TouchMoveEvent"] = addListener(this.controlElement,"touchmove",this.onTouchMove,this,null,true,true);
		this.eventStack["MouseUpEvent"] = addListener(document,"mouseup",this.onTouchEnd,this,null,true,true);
		this.eventStack["TouchEndEvent"] = addListener(this.controlElement,"touchend",this.onTouchEnd,this,null,true,true);

		var self = this;
		this.enterFrameId = setInterval(function(){self.onEnterFrame.call(self);},10);
	}
	p.onEnterFrame = function(){
		this.mouseHistory.pop();
		this.mouseHistory.unshift({x:this.moveMousePosition.x,y:this.moveMousePosition.y});
	}
	p.onTouchMove = function(e){
		if(!this.isDragging) return;
		var y = getPointer(e).y - this.startMousePosition.y + this.startElementPosition.top;
		var height = this.element.offsetHeight - this.containerElement.offsetHeight;
		/*if(y > 0) y = 0;
		else if(y < -height) y = -height;*/
		this.top(y);
		this.moveMousePosition = {x:getPointer(e).x,y:getPointer(e).y};
	}
	p.onTouchEnd = function(e){
		clearInterval(this.enterFrameId);
		removeListener(this.eventStack["MouseMove"]);
		removeListener(this.eventStack["TouchMoveEvent"]);
		removeListener(this.eventStack["MouseUpEvent"]);
		removeListener(this.eventStack["TouchEndEvent"]);
		this.inertia(this.getAccel().y);
		this.isDragging = false;
	}
	p.getAccel = function(){
		var accel = {};
		var i, l = this.mouseHistory.length - 1;
		for(i = 0; i < l;i++){
			if(i == 0) {
				accel.x = this.mouseHistory[i].x - this.mouseHistory[i+1].x;
				accel.y = this.mouseHistory[i].y - this.mouseHistory[i+1].y;
			}
			else {
				accel.x = (accel.x + this.mouseHistory[i].x - this.mouseHistory[i+1].x)/2;
				accel.y = (accel.y + this.mouseHistory[i].y - this.mouseHistory[i+1].y)/2;
			}
		}
		return accel;
	}
	p.inertia = function(value){
		value *= 0.96;
		this.top(this.top() + value);
		var self = this;
		var height = this.element.offsetHeight - this.containerElement.offsetHeight;
		if(this.top() > 0) this.top(0);
		else if(this.top() < -height) this.top(-height);
		else if(Math.abs(value) > 1) this.moveTimerId = setTimeout(function(){self.inertia.call(self,value)},10);
	}
	p.stop = function(){
		clearInterval(this.moveTimerId);
	}
	p.left = function(value){
		if(typeof value !== "undefined"){
			this._left = value;
			this.element.style.left = value + "px";
		}
		return this._left;
	}
	p.top = function(value){
		if(typeof value !== "undefined"){
			if(value < -this.loopHeight) value += this.loopHeight;
			if(value > 0) value  -= this.loopHeight;
			var beforTop = this._top;
			this._top = value;
			this.element.style.top = value + "px";
			var scrollEvent = {};
			scrollEvent.scrollTop = -value;
			scrollEvent.scrollTopDelta = -value + beforTop;
			this.runCallBack('SCROLL',scrollEvent);
		}
		return this._top;
	}
	p.addCallBack = function(eventName,func,scope,arg){
		if(typeof this.callBackStack[eventName] === 'undefined') this.callBackStack[eventName] = [];
		this.callBackStack[eventName].push(function(e){ func.call(scope,e,arg); });
	}
	p.runCallBack = function(eventName,e){
		if(typeof this.callBackStack[eventName] !== 'undefined'){
			var stack = this.callBackStack[eventName];
			var i,l = stack.length;
			for(i=0;i<l;i++) this.callBackStack[eventName][i](e);
		}
	}
	p.move = function(value){
		if(!this.isActive) return;
		clearTimeout(this.moveTimerId);
		this.update(this.top(),-value,new Date().getTime(),1.5);
	}
	p.update = function(from,to,startTime,time)
	{
		var currentTime = (new Date().getTime() - startTime)/1000;
		this.top(this.easing(currentTime,from,to-from,time));
		var self = this;
		if(currentTime < time ) this.moveTimerId = setTimeout(function(){self.update.call(self,from,to,startTime,time)},10);
		else this.top(to);
	}
	p.easing = function(t, b, c, d ) {
		var s = 0.7;
		if ((t /= d / 2) < 1) {
			return c / 2 * (t * t * (((s * 1.525) + 1) * t - s * 1.525)) + b;
		}
		return c / 2 * ((t -= 2) * t * (((s * 1.525) + 1) * t + s * 1.525) + 2) + b;
	}

function getPointer(e){
		var pointer = {x:0,y:0};
		if(e && e.touches && e.touches[0]){
			pointer.x = e.touches[0].pageX;
			pointer.y = e.touches[0].pageY;
		}
		else if(e && e.pageX ){
			pointer.x = e.pageX;
			pointer.y = e.pageY;
		}
		else if(typeof event != 'undefined' && event.clientX){
			pointer.x = event.clientX;
			pointer.y = event.clientY;
		}
		return pointer;
	}

function addListener(target,eventName,func,scope,arg,preventDefault,stopPropagation){
	var preventDefault = (preventDefault) ? true : false;
	var stopPropagation = (stopPropagation) ? true : false;
	var scope = (scope) ? scope : window;
	var arg = (arg) ? arg : {};
	var f = function(e){
		if(preventDefault){
			if(e.preventDefault) e.preventDefault();
			else if(window.event) window.event.returnValue = false;
		}
		if(stopPropagation){
			if(e.stopPropagation) e.stopPropagation();
			else if(window.event) window.event.cancelBubble = true;
		}
		func.call(scope,e,arg);
	};
	if(target.addEventListener){

		target.addEventListener(eventName,f,false);
		if(eventName == "mousewheel") { window.addEventListener('DOMMouseScroll', f, false); }// Firefox
	}
	else if(target.attachEvent){
		target.attachEvent("on" + eventName,f);
	}
	return {target:target,eventName:eventName,func:f};
}
function removeListener(obj){
	if(document.addEventListener) {
		obj.target.removeEventListener(obj.eventName,obj.func,false);
		if(obj.eventName == "mousewheel") obj.target.removeEventListener('DOMMouseScroll',obj.func,false);
	}
	else if(document.detachEvent) obj.target.detachEvent("on" + obj.eventName,obj.func);
}

window.ScrollContents = ScrollContents;

}(window))
