/**
 * 
 * Find more about the MTD Touch Library function at
 * http://api.mutado.com/mobile
 *
 * Copyright (c) 2010 Mutado Mobile, http://mutado.com/mobile
 * Released under MIT license
 * http://api.mutado.com/mobile/shared/license
 * 
 * Version 1.0.0 - Last updated: 2011.09.14
 * 
 */
 
 
/**
 * UniversalTouchHScroll Component
 * -----------------------------------------------------------
 */


(function($){var addMethods=function(source){var ancestor=this.superclass&&this.superclass.prototype;var properties=$.keys(source);if(!$.keys({toString:true}).length)properties.push("toString","valueOf");for(var i=0,length=properties.length;i<length;i++){var property=properties[i],value=source[property];if(ancestor&&$.isFunction(value)&&$.argumentNames(value)[0]=="$super"){var method=value,value=$.extend($.wrap((function(m){return function(){return ancestor[m].apply(this,arguments)};})(property),method),{valueOf:function(){return method},toString:function(){return method.toString()}});}
this.prototype[property]=value;}
return this;}
$.extend({keys:function(obj){var keys=[];for(var key in obj)keys.push(key);return keys;},argumentNames:function(func){var names=func.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(/, ?/);return names.length==1&&!names[0]?[]:names;},bind:function(func,scope){return function(){return func.apply(scope,$.makeArray(arguments));}},wrap:function(func,wrapper){var __method=func;return function(){return wrapper.apply(this,[$.bind(__method,this)].concat($.makeArray(arguments)));}},klass:function(){var parent=null,properties=$.makeArray(arguments);if($.isFunction(properties[0]))parent=properties.shift();var klass=function(){this.initialize.apply(this,arguments);};klass.superclass=parent;klass.subclasses=[];klass.addMethods=addMethods;if(parent){var subclass=function(){};subclass.prototype=parent.prototype;klass.prototype=new subclass;parent.subclasses.push(klass);}
for(var i=0;i<properties.length;i++)
klass.addMethods(properties[i]);if(!klass.prototype.initialize)
klass.prototype.initialize=function(){};klass.prototype.constructor=klass;return klass;},delegate:function(rules){return function(e){var target=$(e.target),parent=null;for(var selector in rules){if(target.is(selector)||((parent=target.parents(selector))&&parent.length>0)){return rules[selector].apply(this,[parent||target].concat($.makeArray(arguments)));}
parent=null;}}}});var bindEvents=function(instance){for(var member in instance){if(member.match(/^on(.+)/)&&typeof instance[member]=='function'){instance.element.bind(RegExp.$1,$.bind(instance[member],instance));}}}
var behaviorWrapper=function(behavior){return $.klass(behavior,{initialize:function($super,element,args){this.element=$(element);if($super)$super.apply(this,args);}});}
var attachBehavior=function(el,behavior,args){var wrapper=behaviorWrapper(behavior);instance=new wrapper(el,args);bindEvents(instance);if(!behavior.instances)behavior.instances=[];behavior.instances.push(instance);return instance;};$.fn.extend({attach:function(){var args=$.makeArray(arguments),behavior=args.shift();if($.livequery&&this.selector){return this.livequery(function(){attachBehavior(this,behavior,args);});}else{return this.each(function(){attachBehavior(this,behavior,args);});}},attachAndReturn:function(){var args=$.makeArray(arguments),behavior=args.shift();return $.map(this,function(el){return attachBehavior(el,behavior,args);});},delegate:function(type,rules){return this.bind(type,$.delegate(rules));},attached:function(behavior){var instances=[];if(!behavior.instances)return instances;this.each(function(i,element){$.each(behavior.instances,function(i,instance){if(instance.element.get(0)==element)instances.push(instance);});});return instances;},firstAttached:function(behavior){return this.attached(behavior)[0];}});Remote=$.klass({initialize:function(options){if(this.element.attr('nodeName')=='FORM')this.element.attach(Remote.Form,options);else this.element.attach(Remote.Link,options);}});Remote.Base=$.klass({initialize:function(options){this.options=options;},_makeRequest:function(options){$.ajax(options);return false;}});Remote.Link=$.klass(Remote.Base,{onclick:function(){var options=$.extend({url:this.element.attr('href'),type:'GET'},this.options);return this._makeRequest(options);}});Remote.Form=$.klass(Remote.Base,{onclick:function(e){var target=e.target;if($.inArray(target.nodeName.toLowerCase(),['input','button'])>=0&&target.type.match(/submit|image/))
this._submitButton=target;},onsubmit:function(){var data=this.element.serializeArray();if(this._submitButton)data.push({name:this._submitButton.name,value:this._submitButton.value});var options=$.extend({url:this.element.attr('action'),type:this.element.attr('method')||'GET',data:data},this.options);this._makeRequest(options);return false;}});$.ajaxSetup({beforeSend:function(xhr){if(!this.dataType)
xhr.setRequestHeader("Accept","text/javascript, text/html, application/xml, text/xml, */*");}});})(jQuery);function $MTD(query){return $(query).component();}
$MTD.log=function(o){}
$MTD.delegate=function(){var arr=[];for(var i=0;i<arguments.length;i++){arr.push(arguments[i]);}
var obj=arr.shift();var func=arr.shift();var args=arr;var f=function(){var target=arguments.callee.target;var func=arguments.callee.func;var args=arguments.callee.args;if(args.length>0){return func.apply(target,args.concat(arguments));}else{return func.apply(target,arguments);}};f.target=obj;f.func=func;f.args=args;return f;}
$MTD.UIComponentManager={registry:{},append:function(id,klass){this.registry[id]=klass;},resolve:function(id){return this.registry[id];},remove:function(id){this.registry[id]=null;delete this.registry[id];}}
$MTD.UIComponent=$.klass({holding:false,dragging:false,firstTouch:null,dragThresold:3,dragHorizontal:false,dragVertical:false,initialize:function(params){$MTD.UIComponentManager.append(this.id(),this);/* $MTD.log('UIComponent initialize... [#'+this.id()+']'); */this.__forwarder={};this.build(params);this.bindTouches();this.afterInitialize();},touchableElement:function(){return this.element;},bindTouches:function(){var el=this.touchableElement();if(this.isTouch()){el.bind('touchstart',$MTD.delegate(this,this._touchesBegan));el.bind('touchmove',$MTD.delegate(this,this._touchesMoved));el.bind('touchend',$MTD.delegate(this,this._touchesEnded));}},id:function(){return this.element.attr('id');},owner:function(){return $(this.ownerString());},isTouch:function(){return('ontouchstart'in window);},ownerString:function(){return'#'+this.id();},bind:function(type,fun,scope){if(!scope){scope=this;}
this.__forwarder[type]=$MTD.delegate(scope,fun);},notify:function(){var arr=[];for(var i=0;i<arguments.length;i++){arr.push(arguments[i]);}
var type=arr.shift();if(this.__forwarder[type]){return this.__forwarder[type].apply(this,arr);}},hasEvent:function(type){return this.__forwarder[type]!=null;},parseTouchesEvent:function(e,touchIndex){if(touchIndex==null){touchIndex=0;}
if(this.isTouch()){return{x:e.originalEvent.touches[touchIndex].pageX,y:e.originalEvent.touches[touchIndex].pageY};}
return{x:e.originalEvent.pageX,y:e.originalEvent.pageY};},_touchesBegan:function(e){this.holding=true;this.dragHorizontal=false;this.dragVertical=false;this.firstTouch=this.parseTouchesEvent(e);if(!this.isTouch()){e.preventDefault();}
this.touchesBegan(e);},_touchesMoved:function(e){if(!this.holding){return;}
if(!this.dragging){var p=this.parseTouchesEvent(e);var ox=Math.abs(p.x-this.firstTouch.x);var oy=Math.abs(p.y-this.firstTouch.y);this.dragHorizontal=ox>oy&&(p.x<=this.firstTouch.x-this.dragThresold||p.x>=this.firstTouch.x+this.dragThresold);this.dragVertical=oy>ox&&(p.y<=this.firstTouch.y-this.dragThresold||p.y>=this.firstTouch.y+this.dragThresold);if(this.dragHorizontal||this.dragVertical){this.dragging=true;}}
this.touchesMoved(e);},_touchesEnded:function(e){if(this.dragging){e.preventDefault();}
this.touchesEnded(e);this.holding=false;this.dragging=false;this.firstTouch=null;},touchesBegan:function(e){},touchesMoved:function(e){},touchesEnded:function(e){},afterInitialize:function(){},build:function(params){/* $MTD.log(this.ownerString()+' > .build() not implemented'); */},merge:function(obj1,obj2){var obj3={};for(var attrname in obj1){obj3[attrname]=obj1[attrname];}
for(var attrname in obj2){obj3[attrname]=obj2[attrname];}
return obj3;}});jQuery.fn.extend({component:function(){return $MTD.UIComponentManager.resolve(this.attr('id'));}});

$MTD.UniversalTouchHScroll = $.klass( $MTD.UIComponent, {
	
	WRAPPER_CLASS: 'mtdtouch-scroll-wrapper',
	PAGER_WRAPPER_CLASS: 'mtdtouch-scroll-pager-wrapper',
	PAGER_CLASS: 'mtdtouch-scroll-pager',
	
	/**
	* Animation Constants
	*/
	kAnimationUseNone: 		0,
	kAnimationUseWebkit: 	1,
	kAnimationUseMoz: 		2,	
	kAnimationUseOpera: 	3,
	
	timeout: null,
	
	staticOptions: {
		animationEngine:		0,
		items: 0,
		limit: 0.1,
		position: 0,
		width: 0,
		height: 0,
		pointer: 0,
		movePointer: 0,
		point: { x: 0, y: 0 },
		timer: 0,
		currentItem: 1
	},
	
	defaults: {
		horizontal: true,
		paging: true,
		friction: 0.33,
		duration: 200,
		offset: 0,
		infinite: false,
		auto: false,
		pause: 1000,
		hoverPause: false,
		hoverableObject: false,
		stylizePager: true
	},
	
	_ul : null,
	
	options : {},
	
	afterInitialize: function(){
		
		this.checkProperties();
	},
	//var options = $.extend(defaults, options); 
	checkProperties: function(){
		this.options.animationEngine = this.kAnimationUseNone;
		if( this.checkProperty( 'webkitTransform' ) ) 
			this.options.animationEngine = this.kAnimationUseWebkit;
		else if( this.checkProperty( 'MozTransform' ) ) 
			this.options.animationEngine = this.kAnimationUseMoz;
		else if( this.checkProperty( 'OTransform' ) ) 
			this.options.animationEngine = this.kAnimationUseOpera;
	},
	
	checkProperty: function( prop ){
		var div = document.createElement( 'div' );
		return prop in div.style;
	},
	
	
	build: function( params ) {
		this._ul = this.ul();
		this.options = this.merge( $.extend(this.defaults, params), this.staticOptions );
		
		
		
		
		$( this.element ).css( 'overflow', 'hidden' ).append( '<div class="' + this.WRAPPER_CLASS + '"></div>' );
		
		var original = this.ownerString() + ' > ul';
		var div = this.wrapper();
		var li = this.li();
		var w = $( this.element ).outerWidth();
		var h = $( this.element ).outerHeight();
		var offset = this.options.offset;
		
		//$( div ).css( 'float', 'left' );
		$( div ).width( w + 'px' );
		$( div ).height( h + 'px' );
		
		
		this.owner().css( 'position', 'relative' );
		if( this.options.horizontal ){
			this.owner().addClass( 'horizontal' );
		} else{
			this.owner().addClass( 'vertical' );
		}
		
		$( div ).append( $( original ) );
		
		var pos = this.options.position;
		var c = this.options.items;		
		var hor = this.options.horizontal;
		$( li ).each( function( index ) {
			
			$( this ).css( 'float', 'left' );
			$( this ).css( 'width', w + 'px' );
			$( this ).css( 'height', h + 'px' );			
			$( this ).css( 'text-align', 'center' );
			$( this ).css( 'padding', '0' );
			$( this ).css( 'margin', '0' );
			$( this ).css( 'margin-right', offset + 'px' );			
			$( this ).css( 'margin-bottom', offset + 'px' );
			pos += ( hor ? w : h ) + offset;
			c++;
		});
				
		this.options.items = c;
		this.options.width = w;
		this.options.height = h;
		this.options.position = pos;
		
		$( this._ul ).css( 'list-style', 'none' );
		$( this._ul ).css( 'position', 'relative' );
		$( this._ul ).css( 'padding', '0' );
		$( this._ul ).css( 'margin', '0' );
		
		if ( this.options.horizontal ) {
			$( this._ul ).css( 'width', this.options.position + 'px' );
			$( this._ul ).css( 'height', h + 'px' );
		} else {
			$( this._ul ).css( 'width', w + 'px' );
			$( this._ul ).css( 'height', this.options.position + 'px' );
		}
		
		$( div ).css( 'overflow', 'hidden' );
		
		if ( this.options.paging ) {
			this.createPager();
		}
		
		window.setTimeout( $MTD.delegate( this, this.scrollTo, 0 ), 100 );
		
		if( this.options.auto ){
			this.startTimer();
			if( this.options.hoverPause ){
				var ref = this;
				var hoverObject = ref.options.hoverableObject ? ref.options.hoverableObject : ref.owner();
				$( hoverObject ).hover(function(){

					ref.stopTimer();
				}, function(){

					ref.startTimer();
				});
			}
		}
		
	},
	
	startTimer: function(){

		this.stopTimer();
		this.timeout = setInterval( $MTD.delegate( this, this.next ), this.options.pause );
	},
	
	stopTimer: function(){

		clearInterval( this.timeout );
	},
	
	wrapper: function() {
		return this.ownerString() + ' > .' + this.WRAPPER_CLASS;
	},
	
	ul: function() {
		return this.wrapper() + ' > ul';
	},
	
	li: function() {
		return this.ul() + ' > li';
	},
		
	hasPaging: function() {
		return this.options.paging;
	},
	
	directionHorizontal: function() {
		return this.options.horizontal;
	},
	
	createPager: function() {
		$( this.element ).append( '<div class="' + this.PAGER_WRAPPER_CLASS + '"><div class="' + this.PAGER_CLASS +'"></div></div>' );
		var pagerWrapper = this.ownerString() + ' > .' + this.PAGER_WRAPPER_CLASS;
		var pager = pagerWrapper + ' .' + this.PAGER_CLASS;
		// wrapper
		
		
		
		
		$( pager ).append( '<ul></ul>' );
		
		
		var ul = $( pager + ' > ul' );
		$( ul ).css( 'list-style', 'none' );
		$( ul ).css( 'float', 'left' );
		
		for ( var i = 0; i < this.options.items; i++ ) {
			$( ul ).append( '<li></li>' );	
		}
		
		var li = $( pager + ' > ul > li' );
		$( pager + ' > ul > li:first-child' ).addClass( 'first' );
		$( pager + ' > ul > li:last-child' ).addClass( 'last' );
		var ref = this;
		$( li ).each( function( index ) {
			if ( ref.options.horizontal ) {
				$( this ).css( 'float', 'left' );
			}
			$( this ).click( $MTD.delegate( ref, ref.scrollTo, index ) );
		});
		
		
		if( this.options.stylizePager === true ){

			$( pagerWrapper ).css( {
				'position' : 'absolute',
				'width': this.options.width
			});
			$( pager ).css({
				'position' : 'absolute',
				'text-align' : 'center'
			});
			
			if ( this.options.horizontal ) {
				$( pagerWrapper ).css( 'top', '100%' );
				$( pager ).css( 'bottom', '0' );
				$( pager ).css( 'width', this.options.width );
				$( ul ).css( 'margin-left', ( this.options.width * 0.5 - $( ul ).innerWidth() * 0.5 ) + 'px' );
			} else {
				$( pagerWrapper ).css( 'top', '0' );
				$( pager ).css( 'left', '0' );
				$( pager ).css( 'height', this.options.height );
				$( ul ).css( 'margin-top', ( this.options.height * 0.5 - $( ul ).innerHeight() * 0.5 ) + 'px' );
			}
		}

	},	
	
	updatePager: function() {
		var pager = this.ownerString() + ' > .' + this.PAGER_WRAPPER_CLASS + ' > .' + this.PAGER_CLASS;
		var li = $( pager + ' > ul > li' );
		$( li ).each( function( index ) {
			$( this ).removeClass( 'selected' );
		});
		$( li ).eq( this.options.pointer ).addClass( 'selected' );
	},
	
	scrollTo: function( index ) {
		
		this.setAnimDuration( this.options.duration );
		switch( this.options.animationEngine ){
			case this.kAnimationUseWebkit:
				this.webkitScrollTo( index );
			break;
			case this.kAnimationUseMoz:
				this.mozScrollTo( index );
			break;
			case this.kAnimationUseOpera:
				this.operaScrollTo( index );
			break;
			case this.kAnimationUseNone:
				this.jQueryScrollTo( index );
			break;
		}
		
		
		window.setTimeout( $MTD.delegate( this, this.scrollToCompleted, ( this.options.pointer != index ) ), this.options.duration );
		this.options.pointer = this.options.movePointer = index;
		
		if ( this.options.paging ) {
			this.updatePager();
		}

		this.checkIndexBounds( index );
		if( this.options.auto ){
			this.startTimer();
		}
		
	},
	
	webkitScrollTo: function( index ){
		if ( this.options.horizontal ) {
			$( this._ul ).css( '-webkit-transform', 'translate3d(-' + ( this.options.width + this.options.offset ) * index + 'px, 0px, 0px)' );
		} else {
			$( this._ul ).css( '-webkit-transform', 'translate3d(0px, -' + ( this.options.height + this.options.offset ) * index + 'px, 0px)' );
		}
	},
	
	mozScrollTo: function( index ){
		
		if ( this.options.horizontal ) {
			$( this._ul ).css( '-moz-transform', 'translate(-' + ( this.options.width + this.options.offset ) * index + 'px, 0px)' );
		} else {
			$( this._ul ).css( '-moz-transform', 'translate(0px, -' + ( this.options.height + this.options.offset ) * index + 'px)' );
		}
	},
	
	operaScrollTo: function( index ){
		
		if ( this.options.horizontal ) {
			$( this._ul ).css( '-o-transform', 'translate(-' + ( this.options.width + this.options.offset ) * index + 'px, 0px)' );
		} else {
			$( this._ul ).css( '-o-transform', 'translate(0px, -' + ( this.options.height + this.options.offset ) * index + 'px)' );
		}
	},
	
	jQueryScrollTo: function( index ){

		if( this.options.horizontal ){
			var newLeft =  '-' + ( ( this.options.width + this.options.offset ) * index ) + 'px';
			$( this._ul ).animate( { left: newLeft }, this.options.duration );
		} else {
			var newTop =  '-' + ( ( this.options.height + this.options.offset ) * index ) + 'px';
			$( this._ul ).animate( { top: newTop }, this.options.duration );
		}
		
	},
	
	setAnimDuration: function( value ){
	
		switch( this.options.animationEngine ){
			case this.kAnimationUseWebkit:
				$( this._ul ).css( '-webkit-transition-duration', value + 'ms' );
			break;
			case this.kAnimationUseMoz:
				$( this._ul ).css( '-moz-transition-duration', value + 'ms' );
			break;
			case this.kAnimationUseOpera:
				$( this._ul ).css( '-opera-transition-duration', value + 'ms' );
			break;
			case this.kAnimationUseNone:
			break;
		}
	},
	
	checkIndexBounds: function( index ){
		if( index == 0 ){
			this.notify( 'firstIndex', true );
		}
		else if( index == this.options.items - 1 ){
			this.notify( 'lastIndex', true );
		}
	},
	
	scrollToCompleted: function( changed ) {
		this.setAnimDuration( 0 );
		
		if ( changed ) {
			this.notify( 'changed', this.options.pointer );
		}
	},
	
	touchesBegan: function( e ) {
		this.options.point = this.parseTouchesEvent( e );
		var d = new Date();
		this.options.timer = d.getTime();
		if( this.options.auto ){
			this.stopTimer();
		}
	},
	
	touchesMoved: function( e ) {
		var p = this.parseTouchesEvent( e );
		if ( this.dragVertical && this.options.horizontal ) {
			return;
		}
		if ( this.dragHorizontal && !this.options.horizontal ) {
			return;
		}
		if ( this.dragHorizontal && this.options.horizontal ) {
			e.preventDefault();
		}
		if ( this.dragVertical && !this.options.horizontal ) {
			e.preventDefault();
		}
		
		var dx = this.options.point.x - p.x;
		var dy = this.options.point.y - p.y;
		
		var tpx = - ( ( this.options.width + this.options.offset ) * this.options.pointer ) - dx;
		var tpy = - ( ( this.options.height + this.options.offset ) * this.options.pointer ) - dy;
		
		if ( tpx > 0 || tpx < - ( ( this.options.width + this.options.offset ) * ( this.options.items - 1 ) ) ) {
			dx *= this.options.friction;
		}
		if ( tpy > 0 || tpy < - ( ( this.options.height + this.options.offset ) * ( this.options.items - 1 ) ) ) {
			dy *= this.options.friction;
		}
		
		var nx = - ( ( this.options.width + this.options.offset ) * this.options.pointer ) - dx;
		var ny = - ( ( this.options.height + this.options.offset ) * this.options.pointer ) - dy;
		
		var i;
		var can = false;
		
		if ( this.options.horizontal ) {
			can = Math.abs( dx ) / this.options.width > this.options.limit;
			i = this.options.pointer + ( can ? ( dx > 0 ? 1 : -1 ) : 0 );
		} else {
			can = Math.abs( dy ) / this.options.height > this.options.limit;
			i = this.options.pointer + ( can ? ( dy > 0 ? 1 : -1 ) : 0 );
		}
		 
		this.options.movePointer = Math.min( Math.max( 0, i ), this.options.items - 1 );
		
		if ( this.options.horizontal ) {
			$( this._ul ).css( '-webkit-transform', 'translate3d(' + nx + 'px, 0px, 0px)' );
		} else {
			$( this._ul ).css( '-webkit-transform', 'translate3d(0px, ' + ny + 'px, 0px)' );
		}
		
	},
	
	touchesEnded: function( e ) {
		var d = new Date();
		var speed = d.getTime() - this.options.timer;
		this.scrollTo( this.options.movePointer );
	},
	
	next: function() {
		
		var newIndex;
		if( this.options.infinite ){
			newIndex = ( this.options.pointer + 1 > this.options.items - 1 ) ? 0 : this.options.pointer + 1;
		} else{
			newIndex = Math.min( this.options.pointer + 1, this.options.items - 1 );
		}
		this.options.currentItem = newIndex; 
		this.scrollTo( newIndex );

	},
	
	prev: function() {
		
		var newIndex;
		if( this.options.infinite ){
			newIndex = ( this.options.pointer - 1 < 0 ) ? this.options.items - 1 : this.options.pointer - 1;
		} else{
			newIndex = Math.max( this.options.pointer - 1, 0 );
		} 

		this.options.currentItem = newIndex;
		this.scrollTo( newIndex );
	},
	
	first: function() {

		this.scrollTo( 0 );
	},
	
	last: function() {

		this.scrollTo( this.options.items - 1 );
	},
	
	count: function() {
		return this.options.items;
	},
	
	currentItem: function(){
			return ( this.options.currentItem + 1 );
	}
		
});

jQuery.fn.extend( {

	UniversalMTDTouchHScroll: function( params ) {
		$( this ).attach( $MTD.UniversalTouchHScroll, params );
	}
		
});

