//
//  ASWAnimation.h
//  ASWAnimationTest
//
//  Created by Rudy Richter on 12/11/06.
//  Copyright 2006-2007 Ambrosia Software, Inc. All rights reserved.
//

#if !defined(ASW_NOT_IPHONE)
#define ASW_NOT_IPHONE !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
#endif

#import <Foundation/Foundation.h>

#if defined(__IPHONE_3_0) &&  __IPHONE_3_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED
#import <UIKit/UIKit.h>
#elif defined(ASW_NOT_IPHONE) && ASW_NOT_IPHONE
#import <AppKit/AppKit.h>
#endif

#define ASWBlockingRunLoopMode @"com.Ambrosia.Animation.blocking"

/*! \file ASWAnimation.h */

/*! valid values for progress are 0.0f to 1.0f */
typedef CGFloat ASWAnimationProgress;

/*! valid values for value are 0.0f to 1.0f */
typedef CGFloat ASWAnimationValue;

/*! Animation curve types */
typedef enum {
	ASWAnimationEaseInOut,
	ASWAnimationEaseIn,
	ASWAnimationEaseOut,
	ASWAnimationLinear
} ASWAnimationCurve;

/*! Animation blocking types */
typedef enum { 
	ASWAnimationBlocking,
	ASWAnimationNonblocking,
	ASWAnimationNonblockingThreaded
} ASWAnimationBlockingMode;

/*! \brief a simple animation class */
@interface ASWAnimation : NSObject 
{
	NSTimer						*mAnimationTimer;

	NSTimeInterval				mStartTime;
	NSTimeInterval				mDuration;
	
	CGFloat						mFrameRate;
	ASWAnimationCurve			mCurve;
	
	id							mUserInfo;
	
	NSObject					*mDelegate;
	ASWAnimationProgress		mProgress;
	ASWAnimationValue			mValue;
	ASWAnimationBlockingMode	mBlockingMode;
	CFRunLoopSourceRef			source;
	
	BOOL						mRepeats;
	
	BOOL						mRespondsToShouldStart;
	BOOL						mRespondsToDidStop;
	BOOL						mRespondsToDidEnd;
	BOOL						mRespondsToValueForProgress;
	BOOL						mRespondsToDidReachProgressMark;
	BOOL						mRespondsToTimerFiredAtTime;
	
	NSMutableArray				*mProgressMarks;
}

/*! \brief creates an ASWAnimation instance with specific duration and animation curve
	\param duration the length of time the animation should take
	\param curve the type of animation curve to use with the value methods */
- (id)initWithDuration:(NSTimeInterval)duration withCurve:(ASWAnimationCurve)curve;

/*! \brief deallocate any ivar objects we've got around */
- (void)dealloc;

/*! \brief is the animation currently running
	\return YES/TRUE if the animation is running and NO/FALSE if it isn't */
- (BOOL)isAnimating;

/*! \brief starts the animation */
- (void)startAnimation;

/*! \brief stops the animation potentially before completion */
- (void)stopAnimation;

/*! \brief destroys the animation timer, thusly halting the animation in its tracks */
- (void)cancel;

/*! \brief performs the animation in a manner that blocks the thread while the animation is run */
- (void)blockingAnimation;

/*! \brief runs the animation on its own thread
	\param sender the calling animation */
- (void)threadedAnimation:(id)sender;

/*! \brief used to get a particular value at a particular point in time

	this method is called in animate to update the current value, but it can
	also be called externally in the case where you don't want the timer, but you do want the values.
	override this method if you want to supply your own custom animation curves
	
	\param time the point in time */
- (CGFloat)valueForTime:(NSTimeInterval)time;

/*! \brief called at each animation step
	\param sender the object that animate should be dealing with */
- (void)animate:(id)sender;

/*! \brief responds with the blocking mode that is used for animation
	\return the blocking mode set on this animation object */
- (ASWAnimationBlockingMode)animationBlockingMode;

/*! \brief sets the current animation blocking mode */
- (void)setAnimationBlockingMode:(ASWAnimationBlockingMode)inMode;

/*! \brief returns the current progress of the animation
	\return a float value representing the current progress, on a scale of 0.0 to 1.0 */
- (CGFloat)currentProgress;

/*! \brief sets the current progress of the animation
	\param progress the value that should be set as the progress */
- (void)setCurrentProgress:(CGFloat)progress;

/*! \brief returns the currently set animation curve
	\return the currently set animation curve */
- (ASWAnimationCurve)animationCurve;

/*! \brief sets the current animation curve
	\param curve the curve that should be used for the animation */
- (void)setAnimationCurve:(ASWAnimationCurve)curve;

/*! \brief the current value based on the chosen animation curve
	\return a float value representing the current value, on a scale of 0.0 to 1.0 */
- (CGFloat)currentValue;

/*! \brief sets the current value, which may or may not be on the selected animation curve
	\param current the value that we want to change the animation's value to */
- (void)setCurrentValue:(CGFloat)current;

/*! \brief set the start time of the animation to now
	
	this method is used to tell the animation when the start time is without actually starting the timer.
	this is used in the case where the managing timer is external to the class and currentValue is being called */
- (void)setStartTimeToNow;

/*! \brief the time that has passed since the animation started
	\return a NSTimeInterval that represents the elapsed animation time */
- (NSTimeInterval)elapsedTime;

/*! \brief should the animation run again after it has finished running
	\return YES if the animation should repeat, NO if it shouldn't */
- (BOOL)repeats;

/*! \brief allows the animation to repeat
	\param repeats YES if the animation should repeat, NO if not. */
- (void)setRepeats:(BOOL)repeats;

/*! \brief provides the currently set userInfo back to the caller
	\return the currently set userInfo */
- (id)userInfo;

/*! \brief allows the caller to set an associated userInfo
	
	the passed inUserInfo is copied by ASWAnimation
	
	\param inUserInfo the object to set as the userInfo */
- (void)setUserInfo:(id)inUserInfo;

/*! \brief the current duration the animation is working towards
	\return a NSTimeInterval indicating how long the animation is set to run for */
- (NSTimeInterval)duration;

/*! \brief allows changing of the duration after the animation has been created
	\param duration the new duration the animation should work towards */
- (void)setDuration:(NSTimeInterval)duration;

/*! \brief the frameRate that is set on the animation
	\return a float value representing frames per second */
- (CGFloat)frameRate;

/*! \brief change the frame rate of the animation
	
	changing the framerate invalidates the timers and starts a new animation timer with the framesPerSecond that is being supplied
	
	\param framesPerSecond a float value indicating how many frames per second the animation should work towards */
- (void)setFrameRate:(CGFloat)framesPerSecond;

/*! \brief returns the currently set delegate
	\return a reference to the delegate */
- (id)delegate;

/*! \brief change the assigned delegate
	\param delegate the new delegate that we want to use */
- (void)setDelegate:(id)delegate;


/*! \brief float values that represent the progress points we want to know about
	
	the progress marks that the animation is using to report back to the delegate */
- (NSArray*)progressMarks;

/*! \brief set a new set of progress marks
	\param progressMarks a NSArray of float values to use as progress marks */
- (void)setProgressMarks:(NSArray*)progressMarks;

/*! \brief add another progressMark to the set of marks
	\param progressMark the new mark to add to the set */
- (void)addProgressMark:(ASWAnimationProgress)progressMark;

/*! \brief remove a single progress mark from the set of marks
	\param progressMark the mark to remove from the set */
- (void)removeProgressMark:(ASWAnimationProgress)progressMark;

/*! \brief removes all the progress marks from the animation */
- (void)removeAllProgressMarks;

@end

/*! \brief ASWAnimation delegate interface */
@interface NSObject (ASWAnimationDelegate)

/*! \brief a method to be implemented by the delegate
	
	this method is entirely optional, no other indication that the animation is about to start will happen
	
	\param animation the animation that is asking if it should start
	\return YES if you want the animation to start, NO if not
*/
- (BOOL)animationShouldStart:(ASWAnimation*)animation;

/*! \brief method to be implemented by the delegate to be notified when an animation prematurely stopped
	
	entirely optional method, it notifies the delegate when the animation stopped before completion
	
	\param animation the animation that is stopping
*/
- (void)animationDidStop:(ASWAnimation*)animation;

/*! \brief method to be implemented by the delegate to be notified when the animation has completed
	
	entirely optional method, notifies the delegate when the animation has completed
	
	\param animation the animation that has finished running */
- (void)animationDidEnd:(ASWAnimation*)animation;

/*! \brief method that allows the delegate to supply a new value for a particular progress point
	
	entirely optional method, asks the delegate what the value should be at a given progress point
	
	\param animation the animation that is running
	\param progress a float value from 0.0 to 1.0 that indicates the progress of the animation
	\return the delegate returns a new value for a progress point
*/
- (float)animation:(ASWAnimation*)animation valueForProgress:(ASWAnimationProgress)progress;

/*! \brief method that notifies the delegate when the animation has hit the desired progress marks
	
	entirely optional method, the delegate is notified by the animation when a progress mark has been reached
	
	\param animation the animation that is running
	\param progress the progress mark that was hit
*/
- (void)animation:(ASWAnimation*)animation didReachProgressMark:(ASWAnimationProgress)progress;

/*! \brief method that notifies the delegate every time the animation timer fires
	
	entirely optional method, the delegate is notified every time the timer fires
	
	\param animation the animation that is running
	\param time the time that the timer fired
*/
- (void)animation:(ASWAnimation*)animation timerFiredAtTime:(NSTimeInterval)time;
@end

