/*
max by ProgramMax is licensed under a Creative Commons Attribution 3.0 Unported License:
http://creativecommons.org/licenses/by/3.0/

To learn more visit http://www.programmax.net/projects/max
*/

if( typeof max == "undefined" ) {
	var max = { };
}

if( typeof max.exceptions == "undefined" ) {
	max.exceptions = { };
}

max.exceptions.CouldNotAttachEvent = function( ) {
};

if( typeof max.animation == "undefined" ) {
	max.animation = function( ) {

		var returning = { };

		returning.Duration = function( parameters ) {
			max.common.checkParameters({
				"parameters.durationInMilliseconds" : {
					value: parameters.durationInMilliseconds,
					type: Number
				},
				"parameters.callback": {
					value: parameters.callback,
					type: Function
				}
			});

			if( window.mozRequestAnimationFrame ) {
				var BeginningTime = window.mozAnimationStartTime;

				var AnimationStep = new max.events.EventHandler({ object: window, event: "MozBeforePaint", callback: function( event ) {
					max.events.cancelEvent( event );

					var ElapsedTime = event.timeStamp - BeginningTime;
					var PercentComplete = ElapsedTime / parameters.durationInMilliseconds * 100;

					if( PercentComplete >= 100 ) {
						PercentComplete = 100;
						max.events.removeEventHandler({ eventHandler: AnimationStep });
					}

					parameters.callback( PercentComplete );
					window.mozRequestAnimationFrame();
				} });
				max.events.addEventHandler({ eventHandler: AnimationStep });

				window.mozRequestAnimationFrame();
			} else if( window.webkitRequestAnimationFrame ) {
				var BeginningTime = Date.now();

				var AnimationStep = function( TimeStamp ) {
					var ElapsedTime = TimeStamp - BeginningTime;
					var PercentComplete = ElapsedTime / parameters.durationInMilliseconds * 100;

					if( PercentComplete >= 100 ) {
						PercentComplete = 100;
					} else {
						window.webkitRequestAnimationFrame( AnimationStep );
					}
					parameters.callback( PercentComplete );
				};

				window.webkitRequestAnimationFrame( AnimationStep );
			} else {
				var BeginningTime = ( new Date( ) ).getTime( );
				var IntervalID = setInterval( function( ) {
					var ElapsedTime = ( new Date( ) ).getTime( ) - BeginningTime;
					var PercentComplete = ElapsedTime / parameters.durationInMilliseconds * 100;

					if( PercentComplete >= 100 ) {
						PercentComplete = 100;
						clearInterval( IntervalID );
					}

					parameters.callback( PercentComplete );
				}, 16 ); // 60 frames per second = 16.66... so this is as good a guess as any for smooth animation
			}
		};

		returning.Continuous = function( parameters ) {
			max.common.checkParameters({
				"parameters.callback": {
					value: parameters.callback,
					type: Function
				}
			});

			if( window.mozRequestAnimationFrame )
			{
				var BeginningTime = window.mozAnimationStartTime;

				var AnimationStep = new max.events.EventHandler({ object: window, event: "MozBeforePaint", callback: function( event ) {
					max.events.cancelEvent( event );

					var CurrentTime = event.timeStamp;
					var ElapsedTime = CurrentTime - BeginningTime;
					BeginningTime = CurrentTime;
					parameters.callback( ElapsedTime );
					window.mozRequestAnimationFrame();
				} });
				max.events.addEventHandler({ eventHandler: AnimationStep });

				window.mozRequestAnimationFrame();
			} else if( window.webkitRequestAnimationFrame ) {
				var BeginningTime = Date.now();

				var AnimationStep = function( TimeStamp ) {
					var ElapsedTime = TimeStamp - BeginningTime;
					BeginningTime = TimeStamp;
					parameters.callback( ElapsedTime );
					window.webkitRequestAnimationFrame( AnimationStep );
				}

				window.webkitRequestAnimationFrame( AnimationStep );
			} else {
				var BeginningTime = ( new Date( ) ).getTime( );
				setInterval( function( ) {
					var CurrentTime = ( new Date( ) ).getTime( );
					var ElapsedTime = CurrentTime - BeginningTime;
					BeginningTime = CurrentTime;
					parameters.callback( ElapsedTime );
				}, 16 ); // 60 frames per second = 16.66... so this is as good a guess as any for smooth animation
			}
		};

		returning.SineInterpolation = function( parameters ) {
			max.common.checkParameters({
				"parameters.percentComplete" : {
					value: parameters.percentComplete,
					type: Number
					}
			});

			var Radians = parameters.percentComplete / 100 * Math.PI; // 2pi radians in a full circle, but we only want half the curve
			Radians -= Math.PI / 2; // start at the bottom of the curve

			// var Acceleration = Math.sin( Radians );
			// var Speed = Math.cos( Radians ); // the derivative of sin is cos
			var Position = Math.sin( Radians ); // the derivative of cos is sin

			// sin returns [-1,1] and we want [0,1]
			var ScaledPosition = (Position + 1) / 2;

			return ScaledPosition;
		};








		returning.ScrollVertically = function( parameters ) {
			max.common.checkParameters({
				"parameters.durationInMilliseconds" : {
					value: parameters.durationInMilliseconds,
					type: Number
					},
				"parameters.element" : {
					value: parameters.element,
					type: Object
					}
			});

			max.animation.Duration({ durationInMilliseconds: parameters.durationInMilliseconds, callback: function( PercentComplete ) {
				var PixelsToMove = max.animation.SineInterpolation({ percentComplete: PercentComplete }) * ViewportHeight;

				RenderPosition( PixelsToMove - ViewportHeight );

				// temporarily change the last page's position to be before 0
				if( CurrentPage === 0 ) {
					Pages[ PagesLength - 1 ].style.top = -(PagesLength * ViewportHeight) + PixelsToMove + 'px';
				}

				if( PercentComplete === 100 ) {
					CurrentlyAnimating = false;
					if( CurrentPage === 0 ) {
						// We temporarily moved the last page. Now lets put it back.
						Pages[ PagesLength - 1 ].style.top = ((PagesLength - 1) * ViewportHeight);

						// then put our current page back in range
						CurrentPage = PagesLength;

						// and finally update page tops to reset our view
						RenderPosition( 0 );
					}
				}
			} });
		};

		returning.ScrollHorizontally = function( parameters ) {
			max.common.checkParameters({
				"parameters.durationInMilliseconds" : {
					value: parameters.durationInMilliseconds,
					type: Number
					},
				"parameters.element" : {
					value: parameters.element,
					type: Object
					}
			});

			max.animation.Duration({ durationInMilliseconds: parameters.durationInMilliseconds, callback: function( PercentComplete ) {
				var PixelsToMove = max.animation.SineInterpolation({ percentComplete: PercentComplete }) * ViewportHeight;

				RenderPosition( PixelsToMove - ViewportHeight );

				if( PercentComplete === 100 ) {
					CurrentlyAnimating = false;
					if( CurrentPage === 0 ) {
						// We temporarily moved the last page. Now lets put it back.
						Pages[ PagesLength - 1 ].style.top = ((PagesLength - 1) * ViewportHeight);

						// then put our current page back in range
						CurrentPage = PagesLength;

						// and finally update page tops to reset our view
						RenderPosition( 0 );
					}
				}
			} });
		};

		return returning;
	}();
}
