/* *
 * Roll Model Version 2
 *
 *	Roll on Vertical or Horizontal direction
 *	Create the Gradient layer elements
 *	Create the previous and next button
 *		roll back
 *		roll front
 *		** Head follow Tail
 * Deo 2010.06.02
 
 * ------------------------------------------
 * Modify 2010.11.19
 *	1.Delete the gradient effect
 *	2.Upadte roll mechanism
 *	3.Update loop bug
 * */

var roll = (function() {
	
	// Roll status
	var STATUS = {
		PAUSE: 'pause',
		FINISHED: 'finished'
	};
	
	// Styles
	var styles = {
		box		: 'sm_box',
		mover	: 'sm_mover',
		buttons	: 'sm_control_box',
		btn_prev	: 'sm_button-prev_',
		btn_next	: 'sm_button-next_',
		content_hor	: 'sm_content-horizontal'
	};
	
	var que = {};
	
	function initialization( id ) {
		
		var obj = que[id];
		
		// Go next
		obj._next = true;
		
		// Get Model
		getModel( obj );
		
		// Don't roll
		if( obj._view > obj._real ) return;
		
		// Get step
		obj._stepArr = getStep( obj._view );
		
		// Default roll
		loopStart( obj );
		
		// Stop roll
		jpack.bind( obj, 'mouseover', function() {
			// Display the control bar
			if( !que[obj.id].config.displayControl )
				obj._control.style.display = 'block';
		
			// Stop when this turn finished
			if ( obj.timer.roll != null || 
					obj.index != obj._stepArr.length ) {
				obj.ending_trun = true;
			}
			
			loop( obj, true );
			
			return;
		});
		
		// Start roll
		jpack.bind( obj, 'mouseout', function() {
			// Hide the control bar
			if( !que[obj.id].config.displayControl )
				obj._control.style.display = 'none';
			
			obj._next = true;
			
			obj.ending_trun = false;
			
			loopStart( obj );
			
			return;
		});
		
	}
	
	// Put the object html into new object
	// Create the wrap, mover, control
	// ** Add style to object first child element when roll in horizontal
	function getModel( obj ) {
		var is_ver = que[obj.id].config.direction == 'vertical'? true: false;
		
		// Get current element view size
		if( is_ver ) {
			obj._view = getStyle( obj, 'height' );
		} else {
			obj._view = getStyle( obj, 'width' );
			
			// Reset the element and copy element to one line
			if( obj.getElementsByTagName('*')[0] != undefined ) {
				jpack.classEvent( obj.getElementsByTagName('*')[0] ).add( styles.content_hor );
			} else {
				obj.innerHTML = jpack.trim( obj.innerHTML );
			}	
		}
		
		// Html temp
		var temp = obj.innerHTML;
		
		obj.innerHTML = '';
		
		// Get the wrap
		// Store all
		var wrap = document.createElement('div');

		obj.appendChild( wrap );
		
		// Get the scroll box
		// Put into wrap
		var box = document.createElement('div');
		
		if( is_ver ) {
			jpack.css( box, { 'height': obj._view +'px' });
		} else {
			jpack.css( box, { 'width': obj._view +'px', 'height': getStyle( obj, 'height' ) +'px' });
		}
		
		jpack.classEvent( box ).add( styles.box );

		wrap.appendChild( box );
		
		// Get the scroll mover box
		// Put into box
		var mover = document.createElement('div');
		mover.innerHTML = temp;
		jpack.classEvent( mover ).add( styles.mover );
		
		box.appendChild( mover );
		
		obj._mover = mover;
		
		obj._real = is_ver? obj._mover.offsetHeight: obj._mover.offsetWidth;
		
		// Horizontal
		if( !is_ver ) {
			// This real width is one element
			jpack.css( obj._mover, { 'width': obj._real * 2 +'px' });
		}
		
		if( obj._real > obj._view ) {
			// Real size * 2
			// Add temp html ti mover
			obj._real *= 2;
			mover.innerHTML += temp;
		
			// Add control
			obj._control = getButtons( obj );
			
			wrap.appendChild( obj._control  );
			
			var wrap_hei = is_ver? obj._view: getStyle( obj, 'height' );

			jpack.css( wrap, { 
				'height': ( wrap_hei + obj._control.offsetHeight ) +'px',
				'position': 'relative'
			});
			
			if( !que[obj.id].config.displayControl )
				obj._control.style.display = 'none';
		}
	}
	
	// Create Control
	// Create prev button
	// Create next button
	// Bind the button click event
	function getButtons( obj ) {
		// Prev button
		var prev = document.createElement('a');
			prev.title = 'Previous';
		jpack.classEvent( prev ).add( styles.btn_prev + que[obj.id].config.direction );
		
		// Next button
		var next = document.createElement('a');
			next.title = 'Next';
		jpack.classEvent( next ).add( styles.btn_next + que[obj.id].config.direction );
		
		// Buttons box
		var buttons = document.createElement('div');
		buttons.appendChild( prev );
		buttons.appendChild( next );
		
		jpack.classEvent( buttons ).add( styles.buttons );
		
		jpack.bind( prev, 'click', function() {	
			clickEvent( obj, false );
			return false;
		});
		
		jpack.bind( next, 'click', function() {			
			clickEvent( obj, true );
			return false;
		});
		
		return buttons;
	}
	
	// View page roll
	function loopStart( obj ) {
		clearTimeout( que[obj.id].timer.loop );
		
		que[obj.id].timer.loop = setTimeout(function() {
											   
			// Start roll
			loop( obj, false );
			
		}, que[obj.id].config.wait * 1000 );
	}
	
	// View page roll
	function loop( obj, over_stop, stop_trun/* Just for mouseover event */ ) {
		var start = 0;
		
		clearTimeout( que[obj.id].timer.loop );
		
		var is_ver = que[obj.id].config.direction == 'vertical'? true: false;
	
		// Get current mover top
		var cur = is_ver? obj._mover.offsetTop: obj._mover.offsetLeft;

		// Break the new roll
		if( obj.ending_trun === true ) return;
		
		roll( obj, start, cur, over_stop, function( status, index ) {
			
			// Roll pause
			if( status == STATUS.PAUSE ) return;
			
			// Not loop the roll when playing
			if( obj.ending_trun ) return;
			
			// Roll finished
			if( status == STATUS.FINISHED ) loopStart( obj );
		});
	}
	
	// Click event
	// Roll prev or next
	function clickEvent( obj, go_next ) {
		
		var start = 0;
			
		obj._next = go_next;
		
		var is_ver = que[obj.id].config.direction == 'vertical'? true: false;
		
		// Get current mover top
		var cur = is_ver? obj._mover.offsetTop: obj._mover.offsetLeft;
		
		if( obj.timer.roll != null &&
		   		obj.index != obj._stepArr.length ) {
			cur = cur - ( obj._stepArr[ obj._stepArr.length - 1 ] - obj._stepArr[ obj.index ] );
		}
		
		roll( obj, start, cur, false, function( status, index ) {
			
			// Roll pause
			if( status == STATUS.PAUSE ) return;
			
			// Roll finished
			if( status == STATUS.FINISHED ) loopStart( obj );
			
		});
		
	}
	
	// Roll main function
	function roll( obj, start, cur, over_stop, func ) {
		clearTimeout( que[obj.id].timer.loop );
		clearTimeout( que[obj.id].timer.roll );
		
		var stepArr = obj._stepArr, mt = 0;
		
		// Stop roll and not click any button
		if( over_stop ) {
			if( func && typeof func == 'function' ) 
				func( STATUS.PAUSE, start );
				
			return;
		}
		
		obj.index = start;
		
		if( start < stepArr.length ) {
			// Go next
			if( obj._next ) {
				mt = cur + ( stepArr[start] * -1 );

				// Reset current top when move top over max
				if( Math.abs( mt ) >= Math.abs( obj._view - obj._real ) ) {
					cur = mt + obj._real / 2 + stepArr[ start ];
				}
			} 
			
			// Go previous
			else {
				mt = cur + stepArr[start];
				
				if( mt > 0 ) 
					mt = mt - obj._real / 2;
			}
			
			// Vertical or Horizontal
			if( que[obj.id].config.direction == 'vertical' ) {
				jpack.css( obj._mover, { 'top': mt +'px' } );
			} else {
				jpack.css( obj._mover, { 'left': mt +'px' } );
			}
			
			que[obj.id].timer.roll = setTimeout( function() { 
													
				// Roll loop
				roll( obj, ++ start, cur, over_stop, func );
				
			}, que[obj.id].config.speed * 10 );
		
		} 
		
		// Finished
		else {
			if( func && typeof func == 'function' ) 
				func( STATUS.FINISHED, start );
		}
	}
	
	// Get run step array
	function getStep( end ) {
		var i = 0, start = 0, steps = 50, step = 0, map = {}, arr = [];
		
		while( i < steps ) {
			i ++;
			
			step = Math.ceil( tween( i, start, end, steps ) );
			
			if( !map[i] ) {
				map[i] = i;
				
				arr[arr.length] = step;
			}
		}

		return arr;
	}
	
	// Get current style
	function getStyle( obj, type ) {
		return parseInt( jpack.getCurrentStyle( 
			obj, type 
		).replace( /px|pt|em/ig, function( $1 ) { return ''; } ) );
	}

	function tween( t, b, c, d ) {
		return c * ( ( t = t / d - 1) * t * t * t * t + 1) + b;
	}
	
	return {
		init: function( id, settings ) {
			// Join the queue
			que[id] = jpack.$( id );
			que[id].id = id;
			que[id].index = 0;
			
			// Go on play when this turn ending
			que[id].ending_trun = false;
			
			que[id].timer = {
				loop: null,
				roll: null
			};
			
			// This object private config
			que[id].config = {
				
				// Default control bar is hide
				displayControl: false,
				
				// Direction
				// 1. vertical
				// 2. horizontal
				direction	: 'vertical',
				
				// Unit: second
				// Roll view screen after wait time
				wait	: 2, 
				
				// Roll finished time
				speed	: 5
			};
			
			jpack.extend( que[id].config, settings || {} );
			
			if( que[id].config.direction != 'vertical' && que[id].config.direction != 'horizontal' )
				return;
			
			initialization( id );
		}
	};
})();
