// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

#pragma once

#include "afxanimationhelper.h"
#include "afxtempl.h"

#ifdef _AFX_MINREBUILD
#pragma component(minrebuild, off)
#endif 

#ifdef _AFX_PACKING
#pragma pack(push, _AFX_PACKING)
#endif

class CBaseKeyFrame;
class CAnimationVariable;

/// <summary>
/// Represents a basic transition.
/// </summary>
/// <remarks>
/// This class encapsulates IUIAnimationTransition interface and serves as a base class for all transitions.
/// </remarks>
class CBaseTransition : public CObject
{
	DECLARE_DYNAMIC(CBaseTransition);
public:
	/// <summary>
	/// Defines the transition types currently supported by the MFC implementation of Windows Animation API.
	/// </summary>
	/// <remarks>
	/// A transition type is set in the constructor of specific transition.
	/// For example, CSinusoidalTransitionFromRange sets its type to SINUSOIDAL_FROM_RANGE.
	/// </remarks>
	enum TRANSITION_TYPE
	{
		UNKNOWN,
		ACCELERATE_DECELERATE,
		CONSTANT,
		CUBIC,
		DISCRETE,
		INSTANTENEOUS,
		LINEAR,
		LINEAR_FROM_SPEED,
		SMOOTH_STOP,
		PARABOLIC_FROM_ACCELERATION,
		REVERSAL,
		SINUSOIDAL_FROM_RANGE,
		SINUSOIDAL_FROM_VELOCITY,
		CUSTOM
	};
public:
	/// <summary>
	/// Constructs a base transtion object.
	/// </summary>
	CBaseTransition() : m_type(CBaseTransition::UNKNOWN), m_pStartKeyframe(NULL), m_pEndKeyframe(NULL), 
		m_bAdded(FALSE), m_pRelatedVariable(NULL)
	{
	}

	/// <summary>
	/// The destructor. Called when a transition object is being destroyed.
	/// </summary>
	virtual ~CBaseTransition()
	{
	}

	/// <summary>
	/// Releases encapsulated IUIAnimationTransition COM object.
	/// </summary>
	/// <remarks>
	/// This method should be called from a derived class's Create method in order to prevent 
	/// IUITransition interface leak.
	/// </remarks>
	void Clear()
	{
		if (m_transition != NULL)
		{
			m_transition.Detach()->Release();
		}
	}

	/// <summary>
	/// Returns transition type.
	/// </summary>
	/// <returns> 
	/// One of TRANSITION_TYPE enumerated values.
	/// </returns> 
	/// <remarks>
	/// This method can be used to identify a transition object by its type. 
	/// The type is set in a constructor in a derived class.
	/// </remarks>
	TRANSITION_TYPE GetType() const {return m_type;}

	/// <summary>
	/// Creates a COM transition.
	/// </summary>
	/// <returns> 
	/// TRUE if a transition COM object was created successfully; otherwise FALSE.
	/// </returns> 
	/// <remarks>
	/// This is a pure virtual function that must be overridden in a derived class. 
	/// It's called by the framework to instantiate the underlying COM transition object.
	/// </remarks>
	/// <param name="pLibrary">A pointer to transition library, which creates standard transitions. It can be NULL for custom transitions.</param>
	/// <param name="pFactory">A pointer to transition factory, which creates custom transitions. It can be NULL for standard transitions.</param>
	virtual BOOL Create(IUIAnimationTransitionLibrary* pLibrary, IUIAnimationTransitionFactory* pFactory) = 0;

	/// <summary>
	/// Returns a pointer to underlying COM transition object.
	/// </summary>
	/// <returns> 
	/// A valid pointer to IUIAnimationTransition or NULL if underlying transition can't be created.
	/// </returns> 
	/// <remarks>
	/// This method returns a pointer to underlying COM transition object and creates it if necessary.
	/// </remarks>
	/// <param name="pLibrary">A pointer to transition library, which creates standard transitions. It can be NULL for custom transitions.</param>
	/// <param name="pFactory">A pointer to transition factory, which creates custom transitions. It can be NULL for standard transitions.</param>
	IUIAnimationTransition* GetTransition(IUIAnimationTransitionLibrary* pLibrary, IUIAnimationTransitionFactory* pFactory);

	/// <summary>
	/// Returns a pointer to underlying COM transition object.
	/// </summary>
	/// <returns> 
	/// A valid pointer to IUIAnimationTransition or NULL if underlying transition can't be created.
	/// </returns> 
	/// <remarks>
	/// It's an accessor method to underlying COM transition object. It doesn't instantiates the underlying IUIAnimationTransition COM 
	/// object if it wasn't created.
	/// </remarks>
	IUIAnimationTransition* GetTransition()
	{
		return m_transition;
	}

	/// <summary>
	/// Sets keyframes for a transition.
	/// </summary>
	/// <remarks>
	/// This method tells the transition to start after specified keyframe and, optionally, if pEnd is not NULL, end 
	/// before the specified keyframe. 
	/// If the transition was created with a duration parameter specified, that duration is overwritten with the duration of time between the start and end keyframes.
	/// </remarks>
	/// <param name="pStart">A keyframe that specifies the beginning of the transition. </param>
	/// <param name="pEnd">A keyframe that specifies the end of the transition.</param>
	void SetKeyframes(CBaseKeyFrame* pStart = NULL, CBaseKeyFrame* pEnd = NULL)
	{
		m_pStartKeyframe = pStart;
		m_pEndKeyframe = pEnd;
	}

	/// <summary>
	/// Tells whether a transition has been added to a storyboard.
	/// </summary>
	/// <returns> 
	/// Returns TRUE if a transition has been added to a storyboard, otherwise FALSE.
	/// </returns> 
	/// <remarks>
	/// This flag is set internally when the top level code adds transitions to storyboard.
	/// </remarks>
	BOOL IsAdded(){return m_bAdded;}

	/// <summary>
	/// Returns start keyframe.
	/// </summary>
	/// <returns> 
	/// A valid pointer to a keyframe, or NULL if a transition should not start after a keyframe.
	/// </returns> 
	/// <remarks>
	/// This method can be used to access a keyframe object that was previously set by SetKeyframes.
	/// It's called by top level code when transitions are being added to storyboard.
	/// </remarks>
	CBaseKeyFrame* GetStartKeyframe() {return m_pStartKeyframe;}

	/// <summary>
	/// Returns start keyframe.
	/// </summary>
	/// <returns> 
	/// A valid pointer to a keyframe, or NULL if a transition should not be inserted between keyframes.
	/// </returns> 
	/// <remarks>
	/// This method can be used to access a keyframe object that was previously set by SetKeyframes.
	/// It's called by top level code when transitions are being added to storyboard.
	/// </remarks>
	CBaseKeyFrame* GetEndKeyframe() {return m_pEndKeyframe;}

	/// <summary>
	/// Establishes a relationship between animation variable and transition.
	/// </summary>
	/// <remarks>
	/// Establishes a relationship between animation variable and transition. A transition can be applied only to one variable.
	/// </remarks>
	/// <param name="pVariable">A pointer to related animation variable.</param>
	void SetRelatedVariable(CAnimationVariable* pVariable)
	{
		m_pRelatedVariable = pVariable;
	}

	/// <summary>
	/// Returns a pointer to related variable.
	/// </summary>
	/// <returns> 
	/// A valid pointer to animation variable, or NULL if an animation variable has not been set by SetRelatedVariable.
	/// </returns> 
	/// <remarks>
	/// This is an accessor to related animation variable.
	/// </remarks>
	CAnimationVariable* GetRelatedVariable() {return m_pRelatedVariable;}

	/// <summary>
	/// Adds a transition to a storyboard.
	/// </summary>
	/// <returns> 
	/// TRUE, if transition was successfully added to a storyboard.
	/// </returns> 
	/// <remarks>
	/// Applies the transition to the related variable in the storyboard.  If this is the first transition 
	/// applied to this variable in this storyboard, the transition begins at the start of the storyboard. 
	/// Otherwise, the transition is appended to the transition added most recently to the variable. 
	/// </remarks>
	/// <param name="pStoryboard">A pointer to storyboard, which will animate the related variable.</param>
	BOOL AddToStoryboard(IUIAnimationStoryboard* pStoryboard);

	/// <summary>
	/// Adds a transition to a storyboard.
	/// </summary>
	/// <returns> 
	/// TRUE, if transition was successfully added to a storyboard.
	/// </returns> 
	/// <remarks>
	/// Applies the transition to the related variable in the storyboard. If the start keyframe was specified, the transition 
	/// begins at that keyframe. If the end keyframe was specified, the transition begins at the start keyframe and
	/// and stops at the end keyframe. If the transition was created with a duration parameter specified, that duration is 
	/// overwritten with the duration of time between the start and end keyframes.
	/// If no keyframe was specified, the transition is appended to the transition added most recently to the variable.
	/// </remarks>
	/// <param name="pStoryboard">A pointer to storyboard, which will animate the related variable.</param>
	BOOL AddToStoryboardAtKeyframes(IUIAnimationStoryboard* pStoryboard);

protected:
	/// <summary>
	/// Stores the transition type.  
	/// </summary>
	TRANSITION_TYPE 				m_type;

	/// <summary>
	/// Stores a pointer to IUIAnimationTransition. NULL if a COM transition object has not been created.
	/// </summary>
	ATL::CComPtr<IUIAnimationTransition> m_transition;

	/// <summary>
	/// Stores a pointer to the keyframe that specifies the beginning of the transition.
	/// </summary>
	CBaseKeyFrame* 					m_pStartKeyframe;

	/// <summary>
	/// Stores a pointer to the keyframe that specifies the end of the transition.
	/// </summary>
	CBaseKeyFrame* 					m_pEndKeyframe;

	/// <summary>
	/// A pointer to an animation variable, which is animated with the transition stored in m_transition.
	/// </summary>
	CAnimationVariable*		 		m_pRelatedVariable;

	/// <summary>
	/// Specifies whether a transition has been added to a storyboard.
	/// </summary>
	BOOL							m_bAdded;
};

/// <summary>
/// Implements basic functionality of keyframe.
/// </summary>
/// <remarks>
/// Encapsulates UI_ANIMATION_KEYFRAME variable. Serves as a base class for any keyframe implementation. 
/// A keyframe represents a moment in time within a storyboard and can be used to specify the start and end times of transitions.
/// There are two types of keyframes - keyframes added to storyboard at the specified offset (in time), or keyframes added
/// after specified transition. Because durations of some transitions can't be known before animation starts, the actual values
/// of some keyframes are determined at runtime only.
/// Because keyframes may depend on transitions, which in their turn depend on keyframes, it's important to prevent
/// infinite recursions when building keyframe chains.
/// </remarks>
class CBaseKeyFrame : public CObject
{
	DECLARE_DYNAMIC(CBaseKeyFrame);
	friend class CAnimationGroup;
protected:
	/// <summary>
	/// Represents a Windows Animation API keyframe. When a keyframe is not initialized
	/// it is set to the predefined value UI_ANIMATION_KEYFRAME_STORYBOARD_START.
	/// </summary>
	UI_ANIMATION_KEYFRAME	m_keyframe;

	/// <summary>
	/// Specifies whether this keyframe has been added to a storyboard.
	/// </summary>
	BOOL					m_bAdded;

	/// <summary>
	/// Specifies whether this keyframe should be added to storyboard at an offset from
	/// another existing keyframe, or at the end of some transition.
	/// </summary>
	BOOL					m_bIsKeyframeAtOffset;
public:
	/// <summary>
	/// Constructs a keyframe object.
	/// </summary>
	CBaseKeyFrame() : m_keyframe(UI_ANIMATION_KEYFRAME_STORYBOARD_START), m_bAdded(TRUE)
	{
		m_keyframe = UI_ANIMATION_KEYFRAME_STORYBOARD_START;
		m_bIsKeyframeAtOffset = TRUE;
	}

	/// <summary>
	/// Returns the underlying keyframe value.
	/// </summary>
	/// <returns> 
	/// A current keyframe. The default value is UI_ANIMATION_KEYFRAME_STORYBOARD_START.
	/// </returns> 
	/// <remarks>
	/// This is an accessor to the underlying keyframe value.
	/// </remarks>
	UI_ANIMATION_KEYFRAME GetAnimationKeyframe() const {return m_keyframe;}

	/// <summary>
	/// Tells whether a keyframe has been added to storyboard.
	/// </summary>
	/// <returns> 
	/// TRUE if a keyframe is added to a storyboard; otehrwise FALSE.
	/// </returns> 
	/// <remarks>
	/// In the base class IsAdded always returns TRUE, but it's overridden in derived classes.
	/// </remarks>
	BOOL IsAdded() const {return m_bAdded;}

	/// <summary>
	/// Specifies whether the keyframe should be added to storyboard at offset, or after transition.
	/// </summary>
	/// <returns> 
	/// TRUE if the keyframe should be added to storyboard at some specified offset.
	/// FALSE if the keyframe should be added to storyboard after some transition.
	/// </returns> 
	/// <remarks>
	/// Specifies whether the keyframe should be added to storyboard at offset. 
	/// The offset or transition must be specified in a derived class.
	/// </remarks>
	BOOL IsKeyframeAtOffset() const {return m_bIsKeyframeAtOffset;}

	/// <summary>
	/// Adds a keyframe to storyboard.
	/// </summary>
	/// <returns> 
	/// TRUE if keyframe was added to storyboard successfully; otherwise FALSE. 
	/// </returns> 
	/// <remarks>
	/// This method is called to add a keyframe to storyboard.
	/// </remarks>
	/// <param name="pStoryboard">A pointer to a storyboard.</param>
	/// <param name="bDeepAdd">If this parameter is TRUE and the keyframe being added depends on some other keyframe or transition, this method tries
	/// to add this keyframe or transition to storyboard first.</param>
	virtual BOOL AddToStoryboard(IUIAnimationStoryboard* pStoryboard, BOOL bDeepAdd);
};

/// <summary>
/// Represents an animation keyframe.
/// </summary>
/// <remarks>
/// This class implements an animation keyframe. A keyframe represents a moment in time within a 
/// storyboard and can be used to specify the start and end times of transitions. 
/// A keyframe may be based on other keyframe and have an offset (in seconds) from it, or may be based on a transition and
/// represent a moment in time when this transition ends.
/// </remarks>
class CKeyFrame : public CBaseKeyFrame
{
	DECLARE_DYNAMIC(CKeyFrame);
protected:

	/// <summary>
	/// Stores a pointer to transtion that begins at this keyframe.
	/// </summary>
	CBaseTransition*		m_pTransition;

	/// <summary>
	/// Specifies offset of this keyframe from a keyframe stored in m_pExistingKeyFrame.
	/// </summary>
	UI_ANIMATION_SECONDS 	m_offset;

	/// <summary>
	/// Stores a pointer to an existing keframe. This keyframe is added to storyboard with m_offset to the existing keyframe. 
	/// </summary>
	CBaseKeyFrame* 			m_pExistingKeyFrame;

public:
	/// <summary>
	/// Constructs a keyframe that depends on a transition.
	/// </summary>
	/// <remarks>
	/// The constructed keyframe will represent a moment in time within a storyboard when the specified transition ends.
	/// </remarks>
	/// <param name="pTransition">A pointer to a transition.</param>
	CKeyFrame(CBaseTransition* pTransition);

	/// <summary>
	/// Constructs a keyframe that depends on other keyframe.
	/// </summary>
	/// <remarks>
	/// The constructed keyframe will represent a moment in time within a storyboard, which has a specified offset from pKeyframe.
	/// </remarks>
	/// <param name="pKeyframe">A pointer to keyframe.</param>
	/// <param name="offset">Offset, in seconds, from keyframe specified by pKeyframe.</param>
	CKeyFrame(CBaseKeyFrame* pKeyframe, UI_ANIMATION_SECONDS offset = 0.0);
	
	/// <summary>
	/// Returns a pointer to a transition this keyframe depends on.
	/// </summary>
	/// <returns> 
	/// A valid pointer to transition, or NULL if this keyframe does not depend on transition.
	/// </returns> 
	/// <remarks>
	/// This is an accessor to a transition this keyframe depends on.
	/// </remarks>
	CBaseTransition* GetTransition() {return m_pTransition;}

	/// <summary>
	/// Returns a pointer to a keyframe this keyframe depends on.
	/// </summary>
	/// <returns> 
	/// A valid pointer to keyframe, or NULL if this keyframe does not depend on other keyframe.
	/// </returns> 
	/// <remarks>
	/// This is an accessor to a keyframe this keyframe depends on.
	/// </remarks>
	CBaseKeyFrame* GetExistingKeyframe() {return m_pExistingKeyFrame;}

	/// <summary>
	/// Returns an offset from other keyframe.
	/// </summary>
	/// <returns> 
	/// An offset in seconds from other keyframe.
	/// </returns> 
	/// <remarks>
	/// This method should be called to determine an offset in seconds from other keyframe.
	/// </remarks>
	UI_ANIMATION_SECONDS GetOffset() {return m_offset;}

	/// <summary>
	/// Adds a keyframe to a storyboard.
	/// </summary>
	/// <returns> 
	/// TRUE, if keyframe was added successfully.
	/// </returns> 
	/// <remarks>
	/// This method adds a keyframe to storyboard. If it depends on other keyframe or transition and bDeepAdd is TRUE,
	/// this method tries to add them recursively.
	/// </remarks>
	/// <param name="pStoryboard">A pointer to a storyboard.</param>
	/// <param name="bDeepAdd">Specifies whether to add keyframe or transition recursively.</param>
	virtual BOOL AddToStoryboard(IUIAnimationStoryboard* pStoryboard, BOOL bDeepAdd);

	/// <summary>
	/// Adds a keyframe to storyboard after transition.
	/// </summary>
	/// <returns> 
	/// TRUE, if keyframe was added successfully.
	/// </returns> 
	/// <remarks>
	/// This function is called by the framework to add a keyframe to storyboard after transition.
	/// </remarks>
	/// <param name="pStoryboard">A pointer to a storyboard.</param>
	/// <param name="bDeepAdd">Specifies whether to add a transition recursively.</param>
	BOOL AddToStoryboardAfterTransition(IUIAnimationStoryboard* pStoryboard, BOOL bDeepAdd);

	/// <summary>
	/// Adds a keyframe to storyboard at offset.
	/// </summary>
	/// <returns> 
	/// TRUE, if keyframe was added successfully.
	/// </returns> 
	/// <remarks>
	/// This function is called by the framework to add a keyframe to storyboard at offset.
	/// </remarks>
	/// <param name="pStoryboard">A pointer to a storyboard.</param>
	/// <param name="bDeepAdd">Specifies whether to add a keyframe this keyframe depend on recursively.</param>
	virtual BOOL AddToStoryboardAtOffset(IUIAnimationStoryboard* pStoryboard, BOOL bDeepAdd);
 };

class CAnimationController;
class CAnimationBaseObject;

/// <summary>
/// Represents an animation variable.
/// </summary>
/// <remarks>
/// The CAnimationVariable class encapsulates IUIAnimationVariable COM object. It also holds a list of transitions
/// to be applied to the animation variable in a storyboard. CAnimationVariable objects are embedded to 
/// animation objects, which can represent in an application an animated value, point, size, color and rectangle.
/// </remarks>
class CAnimationVariable 
{
	friend class CAnimationBaseObject;
protected:
	/// <summary>
	/// Stores a pointer to IUIAnimationVariable COM object. NULL if the COM object has not been created yet, or if creation failed.
	/// </summary>
	ATL::CComPtr<IUIAnimationVariable> 	m_variable;

	/// <summary>
	/// Specifies the default value, which is propagated to IUIAnimationVariable.
	/// </summary>
	DOUBLE 							m_dblDefaultValue;

	/// <summary>
	/// Contains a list of transitions that animate this animation variable.
	/// </summary>
	CObList 						m_lstTransitions;

	/// <summary>
	/// A pointer to an animation object that encapsulates this animation variable.
	/// </summary>
	CAnimationBaseObject*			m_pParentObject;

protected:
	/// <summary>
	/// Sets the relationship between an animation variable and an animation object.
	/// </summary>
	/// <remarks>
	/// This method is called internally to establish one-to-one relationship between an animation variable and an animation object that encapsulates it.
	/// </remarks>
	/// <param name="pParentObject">A pointer to an animation object that contains this variable.</param>
	void SetParentAnimationObject(CAnimationBaseObject* pParentObject) {m_pParentObject = pParentObject;}

public:
	/// <summary>
	/// Constructs an animation variable object.
	/// </summary>
	/// <remarks>
	/// Constructs an animation variable object and sets its default value. A default value is used when
	/// a variable is not animated, or can't be animated.
	/// </remarks>
	/// <param name="dblDefaultValue">Specifies the default value.</param>
	CAnimationVariable(DOUBLE dblDefaultValue = 0.0);

	/// <summary>
	/// The destructor. Called when a CAnimationVariable object is being destroyed. 
	/// </summary>
	virtual ~CAnimationVariable();

	/// <summary>
	/// Returns the parent animation object.
	/// </summary>
	/// <returns> 
	/// A pointer to parent animation object, if relationship was established, otherwise NULL.
	/// </returns> 
	/// <remarks>
	/// This method can be called to retrieve a pointer to a parent animation object (a container).
	/// </remarks>
	CAnimationBaseObject* GetParentAnimationObject() {return m_pParentObject;}

	/// <summary>
	/// Returns a pointer to IUIAnimationVariable COM object.
	/// </summary>
	/// <returns> 
	/// A valid pointer to IUIAnimationVariable COM object, or NULL if animation variable was not created, or can't be created.
	/// </returns> 
	/// <remarks>
	/// Use this function to access the underlying IUIAnimationVariable COM object and call its methods directly if needed.
	/// </remarks>
	IUIAnimationVariable* GetVariable() {return m_variable;}

	/// <summary>
	/// Sets default value and releases IUIAnimationVariable COM object.
	/// </summary>
	/// <remarks>
	/// Use this method to reset the default value. This method releases the internal IUIAnimationVariable COM object,
	/// therefore when animation variable is recreated, the underlying COM object gets the new default value.
	/// The default value is returned by GetValue if the COM object representing the animation variable is not created, 
	/// or if the variable has not been animated.
	/// </remarks>
	/// <param name="dblDefaultValue">Specifies the new default value.</param>
	void SetDefaultValue(DOUBLE dblDefaultValue);

	/// <summary>
	/// Creates the underlying animation variable COM object.
	/// </summary>
	/// <returns> 
	/// TRUE if the animation variable was successfully created; otherwise FALSE.
	/// </returns> 
	/// <remarks>
	/// This method creates the underlying animation variable COM object and sets its default value.
	/// </remarks>
	/// <param name="pManager">A pointer to animation manager.</param>
	virtual BOOL Create(IUIAnimationManager* pManager);

	/// <summary>
	/// Creates all transitions to be applied to this animation variable.
	/// </summary>
	/// <returns> 
	/// TRUE if transitions were created successfully; otherwise FALSE.
	/// </returns> 
	/// <remarks>
	/// This method is called by the framework when it needs to create transitions that have been added
	/// to the variable's internal list of transitions.
	/// </remarks>
	/// <param name="pLibrary">A pointer to transition library.</param>
	/// <param name="pFactory">A pointer to transition factory.</param>
	BOOL CreateTransitions(IUIAnimationTransitionLibrary* pLibrary, IUIAnimationTransitionFactory* pFactory);

	/// <summary>
	/// Returns the current value of animation variable.
	/// </summary>
	/// <returns> 
	/// S_OK if the value was obtained successfully, or underlying animation variable has not been created. Otherwise
	/// HRESULT error code. 
	/// </returns> 
	/// <remarks>
	/// This method can be called to retrieve the current value of animation variable. If the underlying COM object
	/// has not been created, dblValue will contain a default value, when the function returns.
	/// </remarks>
	/// <param name="dblValue">The current value of the animation variable.</param>
	HRESULT GetValue(DOUBLE& dblValue);

	/// <summary>
	/// Returns the current value of animation variable.
	/// </summary>
	/// <returns> 
	/// S_OK if the value was obtained successfully, or underlying animation variable has not been created. Otherwise
	/// HRESULT error code. 
	/// </returns> 
	/// <remarks>
	/// This method can be called to retrieve the current value of animation variable. If the underlying COM object
	/// has not been created, dblValue will contain a default value, when the function returns.
	/// </remarks>
	/// <param name="nValue">The current value of the animation variable.</param>
	HRESULT GetValue(INT32& nValue);

	/// <summary>
	/// Adds a transition.
	/// </summary>
	/// <remarks>
	/// This method is called to add a transition to the internal list of transitions to be applied to the animation variable. 
	/// This list should be cleared when an animation has been scheduled.
	/// </remarks>
	/// <param name="pTransition">A pointer to a transition to add.</param>
	void AddTransition(CBaseTransition* pTransition);

	/// <summary>
	/// Clears transitions.
	/// </summary>
	/// <remarks>
	/// This method removes all transitions from the internal list of transitions. If bAutodestroy is TRUE, or 
	/// m_bAutodestroyTransitions is TRUE, then transitions are deleted. Otherwise the caller should deallocate
	/// the transition objects.
	/// </remarks>
	/// <param name="bAutodestroy">Specifies whether this method should delete transition objects.</param>
	void ClearTransitions(BOOL bAutodestroy);

	/// <summary>
	/// Adds transitions from the internal list to storyboard.
	/// </summary>
	/// <remarks>
	/// This method adds transitions from the internal list to storyboard. It's called from the 
	/// top level code several times to add transitions that do not depend on keyframes and add 
	/// transitions that depend on keyframes. If the underlying animation variable 
	/// COM object has not been created, this method creates it at this stage.
	/// </remarks>
	/// <param name="pController">A pointer to parent animation controller.</param>
	/// <param name="pStoryboard">A pointer to storyboard.</param>
	/// <param name="bDependOnKeyframes">TRUE, if this method should add transitions that depend on keyframes.</param>
	void ApplyTransitions(CAnimationController* pController, IUIAnimationStoryboard* pStoryboard, BOOL bDependOnKeyframes);

	/// <summary>
	/// Enables or disables the ValueChanged event.
	/// </summary>
	/// <remarks>
	/// When ValueChanged event is enabled, the framework calls virtual method CAnimationController::OnAnimationValueChanged.
	/// You need to override it in a class derived from CAnimationController in order to process this event. This method is called every time 
	/// the value of animation variable is changed.
	/// </remarks>
	/// <param name="pController">A pointer to parent controller.</param>
	/// <param name="bEnable">TRUE - enable event, FALSE - disable event.</param>
	void EnableValueChangedEvent (CAnimationController* pController, BOOL bEnable);

	/// <summary>
	/// Enables or disables the IntegerValueChanged event.
	/// </summary>
	/// <remarks>
	/// When ValueChanged event is enabled, the framework calls virtual method CAnimationController::OnAnimationIntegerValueChanged.
	/// You need to override it in a class derived from CAnimationController in order to process this event. This method is called every time 
	/// the integer value of animation variable is changed.
	/// </remarks>
	/// <param name="pController">A pointer to parent controller.</param>
	/// <param name="bEnable">TRUE - enable event, FALSE - disable event.</param>
	void EnableIntegerValueChangedEvent (CAnimationController* pController, BOOL bEnable);

	/// <summary>
	/// Returns default value.
	/// </summary>
	/// <returns> 
	/// The default value.
	/// </returns> 
	/// <remarks>
	/// Use this function to obtain default value of animation variable. The default value can be set in constructor or by 
	/// SetDefaultValue method.
	/// </remarks>
	DOUBLE GetDefaultValue() const {return m_dblDefaultValue;}

public:
	/// <summary>
	/// Specifies whether related transition objects should be deleted.
	/// </summary>
	/// <remarks>
	/// Set this value to TRUE to force deletion of transition objects when they are being removed from the internal list
	/// of transitions. If this value is FALSE the transitions should be deleted by calling application.
	/// The list of transitions is always cleared after an animation has been scheduled. The default value is FALSE.
	/// </remarks>
	BOOL	m_bAutodestroyTransitions;
};

/// <summary>
/// The base class for all animation objects.
/// </summary>
/// <remarks>
/// This class implements basic methods for all animation objects. An animation object can represent a value, point,
/// size, rectangle or color in an application, as well as any custom entity. Animation objects are stored in animation groups 
/// (see CAnimationGroup). Each group can be animated separately and can be treated as an analogue of storyboard.
/// An animation object encapsulates one or more animation variables (see CAnimationVariable), depending on its logical
/// representation. For example, CAnimationRect contains four animation variables - one variable for each side of rectangle.
/// Each animation object class exposes overloaded AddTransition method, which should be used to apply transitions to 
/// encapsulated animation variables.
/// An animation object can be identified by Object ID (optionally) and by Group ID. A Group ID is necessary in order
/// to place an animation object to correct group, but if a Group ID is not specified, an object is placed in the default group with ID 0.
/// If you call SetID with different GroupID, an animation object will be moved to another group (a new group is created if necessary).
/// </remarks>
class CAnimationBaseObject : public CObject
{
	DECLARE_DYNAMIC(CAnimationBaseObject)
	friend class CAnimationController;

protected:
	/// <summary>
	/// Specifies the Group ID of the animation object.
	/// </summary>
	UINT32 	m_nGroupID;

	/// <summary>
	/// Specifes the Object ID of the animation object.
	/// </summary>
	UINT32 	m_nObjectID;

	/// <summary>
	/// Stores user-defined data.
	/// </summary>
	DWORD 	m_dwUserData;

	/// <summary>
	/// Specifies whether related transitions should be automatically destroyed.
	/// </summary>
	BOOL 	m_bAutodestroyTransitions;
	
	/// <summary>
	/// A pointer to the parent animation controller.
	/// </summary>
	CAnimationController* m_pParentController;

public:
	/// <summary>
	/// Constructs an animation object.
	/// </summary>
	/// <remarks>
	/// Constructs an animation objects and assigns default Object ID (0) and Group ID (0).
	/// </remarks>
	CAnimationBaseObject();

	/// <summary>
	/// Constructs an animation object.
	/// </summary>
	/// <remarks>
	/// Constructs an animation object with specified Object ID and Group ID.
	/// </remarks>
	/// <param name="nGroupID">Specifies Group ID.</param>
	/// <param name="nObjectID">Specifies Object ID.</param>
	/// <param name="dwUserData">User-defined data, which can be associated with animation object and retrieved later at runtime.</param>
	CAnimationBaseObject(UINT32 nGroupID, UINT32 nObjectID = (UINT32)-1, DWORD dwUserData = 0);

	/// <summary>
	/// The destructor. Called when an animation object is being destroyed.
	/// </summary>
	virtual ~CAnimationBaseObject();

	/// <summary>
	/// Creates transitions associated with an animation object.
	/// </summary>
	/// <returns> 
	/// TRUE if transitions were created successfully; otherwise FALSE.
	/// </returns> 
	/// <remarks>
	/// Loops over list of animation variables encapsulated in a derived animation object and creates transitions 
	/// associated with each animation variable.
	/// </remarks>
	BOOL CreateTransitions();

	/// <summary>
	/// Sets new IDs.
	/// </summary>
	/// <remarks>
	/// Allows to change Object ID and Group ID. If the new Group ID differs from the current ID, an animation object 
	/// is moved to another group (a new group will be created, if necessary).
	/// </remarks>
	/// <param name="nObjectID">Specifies new Object ID.</param>
	/// <param name="nGroupID">Specifies new Group ID.</param>
	void SetID(UINT32 nObjectID, UINT32 nGroupID = 0);

	/// <summary>
	/// Sets user-defined data.
	/// </summary>
	/// <remarks>
	/// Use this method to associate a custom data with an animation object. This data may be retrieved later at runtime by GetUserData.
	/// </remarks>
	/// <param name="dwUserData">Specifies the custom data.</param>
	void SetUserData (DWORD dwUserData)
	{
		m_dwUserData = dwUserData;
	}

	/// <summary>
	/// Detaches an animation object from parent animation controller.
	/// </summary>
	/// <remarks>
	/// This method is used internally.
	/// </remarks>
	void DetachFromController()
	{
		m_pParentController = NULL;
	}

	/// <summary>
	/// Returns current Object ID.
	/// </summary>
	/// <returns> 
	/// Current Object ID.
	/// </returns> 
	/// <remarks>
	/// Use this method to retrieve Object ID. It's 0 if Object ID has not been set explicitly in constructor or with SetID.
	/// </remarks>
	UINT32 GetObjectID() const {return m_nObjectID;}

	/// <summary>
	/// Returns current Group ID.
	/// </summary>
	/// <returns> 
	/// Current Group ID.
	/// </returns> 
	/// <remarks>
	/// Use this method to retrieve Group ID. It's 0 if Group ID has not been set explicitly in constructor or with SetID.
	/// </remarks>
	UINT32 GetGroupID() const {return m_nGroupID;}

	/// <summary>
	/// Returns user defined data.
	/// </summary>
	/// <returns> 
	/// A value of custom data.
	/// </returns> 
	/// <remarks>
	/// Call this method to retrieve the custom data at runtime. The returned value will be 0 if it was not explicitly initialized in constructor or with SetUserData.
	/// </remarks>
	DWORD GetUserData() const {return m_dwUserData;}

	/// <summary>
	/// Sets a flag that orders to automatically destroy transitions.
	/// </summary>
	/// <remarks>
	/// Set this flag only if you allocated transition objects using operator new. If for some reason transition
	/// objects are allocated on the stack, the auto destroy flag should be FALSE. By default this flag is TRUE. 
	/// </remarks>
	/// <param name="bValue">Specifies the auto destroy flag.</param>
	void SetAutodestroyTransitions(BOOL bValue)
	{
		m_bAutodestroyTransitions = bValue;
	}

	/// <summary>
	/// Tells whether related transition are destroyed automatically.
	/// </summary>
	/// <returns> 
	/// If TRUE, related transitions are destroyed automatically; if FALSE, transition objects should be deallocated by calling application.
	/// </returns> 
	/// <remarks>
	/// By default this flag is TRUE. Set this flag only if you allocated transition on the stack and/or transitions should be deallocated by 
	/// the calling application.
	/// </remarks>
	BOOL GetAutodestroyTransitions() const
	{
		return m_bAutodestroyTransitions;
	}

	/// <summary>
	/// Adds transitions to storyboard with encapsulated animation variable.
	/// </summary>
	/// <returns> 
	/// TRUE if transitions were added successfully.
	/// </returns> 
	/// <remarks>
	/// Adds related transitions, that have been added with AddTransition (overloaded methods in derived classes), to storyboard.
	/// </remarks>
	/// <param name="pStoryboard">A pointer to a storyboard.</param>
	/// <param name="bDependOnKeyframes">With FALSE this method adds only those transitions that do not depend on keyframes.</param>
	virtual BOOL ApplyTransitions(IUIAnimationStoryboard* pStoryboard, BOOL bDependOnKeyframes);

	/// <summary>
	/// Removes all related transitions.
	/// </summary>
	/// <remarks>
	/// Removes all related transitions and destroys them if bAutodestroy or m_bAutodestroyTransitions flag is TRUE.
	/// Transitions should be destroyed automatically only if they are not allocated on the stack.
	/// If the above flags are FALSE, transitions are just removed from the internal list of related transitions.
	/// </remarks>
	/// <param name="bAutodestroy">Specifies whether to destroy transition objects automatically, or just remove them from the related list.</param>
	virtual void ClearTransitions(BOOL bAutodestroy);

	/// <summary>
	/// Sets up Value Changed event handler.
	/// </summary>
	/// <remarks>
	/// If the Value Changed event handler is enabled, you can handle this event in CAnimationController::OnAnimationValueChanged method,
	/// which should be overridden in a CAnimationController-derived class. This method is called every time the animation value has changed.
	/// </remarks>
	/// <param name="pController">A pointer to a parent controller.</param>
	/// <param name="bEnable">Specifies whether to enable, or disable Value Changed event.</param>
	virtual void EnableValueChangedEvent(CAnimationController* pController, BOOL bEnable);

	/// <summary>
	/// Sets up Integer Value Changed event handler.
	/// </summary>
	/// <remarks>
	/// If the Integer Value Changed event handler is enabled, you can handle this event in CAnimationController::OnAnimationIntegerValueChanged method,
	/// which should be overridden in a CAnimationController-derived class. This method is called every time the animation integer value has changed.
	/// </remarks>
	/// <param name="pController">A pointer to a parent controller.</param>
	/// <param name="bEnable">Specifies whether to enable, or disable Integer Value Changed event.</param>
	virtual void EnableIntegerValueChangedEvent(CAnimationController* pController, BOOL bEnable);

	/// <summary>
	/// Determines whether an animation object contains a particular animation variable.
	/// </summary>
	/// <returns> 
	/// TRUE if the animation variable is contained in the animation object; otherwise FALSE.
	/// </returns> 
	/// <remarks>
	/// This method can be used to determine whether an animation variable specified by pVariable is contained
	/// within an animation object. An animation object, depending on its type, may contain several animation variables.
	/// For example, CAnimationColor contains three variables, one for each color component (red, green and blue). When a
	/// value of animation variable has changed, Windows Animation API sends ValueChanged or IntegerValueChanged events (if enabled),
	/// and the parameter of this event is a pointer to interface IUIAnimationVariable of animation variable. 
	/// This method helps to obtain a pointer to animation from a pointer to contained COM object.
	/// </remarks>
	/// <param name="pVariable">A pointer to animation variable.</param>
	virtual BOOL ContainsVariable(IUIAnimationVariable* pVariable);

protected:
	/// <summary>
	/// Collects pointers to contained animation variables.
	/// </summary>
	/// <remarks>
	/// This is a pure virtual method that must be overridden in a derived class. 
	/// An animation object, depending on its type, contains one or more animation variables. For example, CAnimationPoint
	/// contains two variables, for X and Y coordinates respectively. The base class CAnimationBaseObject implements 
	/// some generic methods, which act on a list of animation variables: ApplyTransitions, ClearTransitions, 
	/// EnableValueChangedEvent, EnableIntegerValueChangedEvent. These methods call GetAnimationVariableList, which is filled
	/// in a derived class with actual animation variables contained in a particular animation object, then loop over the
	/// list and perform necessary actions.
	/// If you create a custom animation object, you must add to lst all animation variables contained in that object.
	/// </remarks>
	/// <param name="lst">A list that must be filled with animation variables contained in an animation object.</param>
	virtual void GetAnimationVariableList(CList<CAnimationVariable*, CAnimationVariable*>& lst) = 0;

	/// <summary>
	/// Establishes relationship between animation variables, contained in an animation object, and their container. 
	/// </summary>
	/// <remarks>
	/// This is a helper that can be used to establish relationship between animation variables, contained in an animation object, 
	/// and their container. It loops over animation variables and sets a back pointer to a parent animation object
	/// to each animation variable. 
	/// In the current implementation the actual relationship is established in CAnimationBaseObject::ApplyTransitions, therefore
	/// back pointers are not set until you call CAnimationGroup::Animate.
	/// Knowing the relationship may be helpful when you processing events and need to get a parent animation object
	/// from CAnimationVariable (use CAnimationVariable::GetParentAnimationObject).
	/// </remarks>
	virtual void SetParentAnimationObjects();
};

/// <summary>
/// Implements the functionality of animation object with one value.
/// </summary>
/// <remarks>
/// The CAnimationValue class encapsulates a single CAnimationVariable object and can represent in applications
/// a single animated value. For example, you can use this class for animated transparency (fade effect), angle (to rotate objects), 
/// or for any other case when you need to create an animation depending on a single animated value.
/// To use this class in application, just instantiate an object of this class, add it to animation controller using
/// CAnimationController::AddAnimationObject and call AddTransition for each transition to be applied to the value. 
/// </remarks>
class CAnimationValue : public CAnimationBaseObject
{
	DECLARE_DYNAMIC(CAnimationValue)
protected:
	/// <summary>
	/// The encapsulated animation variable that represents animation value.
	/// </summary>
	CAnimationVariable 	m_value;
	
public:
	/// <summary>
	/// Constructs a CAnimationValue object.
	/// </summary>
	/// <remarks>
	/// Constructs CAnimationValue object with default properties: default value, Group ID and Object ID are set to 0.
	/// </remarks>
	CAnimationValue();

	/// <summary>
	/// Constructs a CAnimationValue object.
	/// </summary>
	/// <remarks>
	/// Constructs CAnimationValue object with specified properties.
	/// </remarks>
	/// <param name="dblDefaultValue">Specifies default value.</param>
	/// <param name="nGroupID">Specifies Group ID.</param>
	/// <param name="nObjectID">Specifies Object ID.</param>
	/// <param name="dwUserData">specifies user-defined data.</param>
	CAnimationValue(DOUBLE dblDefaultValue, UINT32 nGroupID, UINT32 nObjectID = (UINT32)-1, DWORD dwUserData = 0);

	/// <summary>
	/// Sets default value.
	/// </summary>
	/// <remarks>
	/// Use this method to set a default value. A default value is returned to application when animation has not been started
	/// and/or underlying COM object has not been created. If the underlying COM object encapsulated in CAnimationVarible
	/// was already created, this method recreates it, therefore you might need to call EnableValueChanged/EnableIntegerValueChanged
	/// methods again.
	/// </remarks>
	/// <param name="dblDefaultValue">Specifies the default value.</param>
	void SetDefaultValue(DOUBLE dblDefaultValue)
	{
		m_value.SetDefaultValue(dblDefaultValue);
	}

	/// <summary>
	/// Retrieves the current value.
	/// </summary>
	/// <returns> 
	/// TRUE if the current value was retrieved successfully; otherwise FALSE.
	/// </returns> 
	/// <remarks>
	/// Call this function to retrieve the current value. This implementation calls the encapsulated COM object, and if
	/// the call fails, this method returns the default value that was previously set in constructor or with SetDefaultValue.
	/// </remarks>
	/// <param name="dblValue">Output. When the function returns it contains a current value of animation variable.</param>
	BOOL GetValue(DOUBLE& dblValue);

	/// <summary>
	/// Retrieves the current value.
	/// </summary>
	/// <returns> 
	/// TRUE if the current value was retrieved successfully; otherwise FALSE.
	/// </returns> 
	/// <remarks>
	/// Call this function to retrieve the current value. This implementation calls the encapsulated COM object, and if
	/// the call fails, this method returns the default value that was previously set in constructor or with SetDefaultValue.
	/// </remarks>
	/// <param name="nValue">Output. When the function returns it contains a current value of animation variable.</param>
	BOOL GetValue(INT32& nValue);

	/// <summary>
	/// Provides conversion between CAnimationValue and DOUBLE.
	/// </summary>
	/// <returns>
	/// Current value of Animation Value.
	/// </returns>
	/// <remarks>
	/// Provides conversion between CAnimationValue and DOUBLE. This method internally calls GetValue and doesn't check for 
	/// errors. If GetValue fails, the returned value will contain a default value previously set in constructor or with SetDefaultValue.
	/// </remarks>
	operator DOUBLE()
	{
		DOUBLE dblVal = 0.;
		GetValue(dblVal);
		return dblVal;
	}

	/// <summary>
	/// Provides conversion between CAnimationValue and INT32.
	/// </summary>
	/// <returns>
	/// Current value of Animation Value as integer.
	/// </returns>
	/// <remarks>
	/// Provides conversion between CAnimationValue and INT32. This method internally calls GetValue and doesn't check for 
	/// errors. If GetValue fails, the returned value will contain a default value previously set in constructor or with SetDefaultValue.
	/// </remarks>
	operator INT32()
	{
		INT32 nVal = 0;
		GetValue(nVal);
		return nVal;
	}

	/// <summary>
	/// Assigns a DOUBLE value to CAnimationValue.
	/// </summary>
	/// <remarks>
	/// Assigns a DOUBLE value to CAnimationValue. This value is set as a default value for encapsulated animation variable.
	/// If you subscribed this animation object to events (ValueChanged or IntegerValueChanged), you need to re-enable these events.
	/// </remarks>
	/// <param name="dblVal">Specifies the value to be assigned to Animation Value.</param>
	void operator=(DOUBLE dblVal)
	{
		SetDefaultValue(dblVal);
	}

	/// <summary>
	/// Assigns an INT32 value to CAnimationValue.
	/// </summary>
	/// <remarks>
	/// Assigns an INT32 value to CAnimationValue. This value is set as a default value for encapsulated animation variable.
	/// If you subscribed this animation object to events (ValueChanged or IntegerValueChanged), you need to re-enable these events.
	/// </remarks>
	/// <param name="nVal">Specifies the value to be assigned to Animation Value.</param>
	void operator=(INT32 nVal)
	{
		SetDefaultValue((DOUBLE)nVal);
	}

	/// <summary>
	/// Provides access to encapsulated animation variable.
	/// </summary>
	/// <returns> 
	/// A reference to encapsulated animation variable.
	/// </returns> 
	/// <remarks>
	/// Use this method to access the encapsulated animation variable. From CAnimationVariable you get access 
	/// to underlying IUIAnimationVariable object, whose pointer can be NULL if animation variable has not been created.
	/// </remarks>
	CAnimationVariable& GetVariable() {return m_value;}

	/// <summary>
	/// Adds a transition to be applied to a value.
	/// </summary>
	/// <remarks>
	/// Call this function to add a transition to internal list of transitions to be applied to an animation variable.
	/// When you add transitions, they are not applied immediately and stored in an internal list. Transitions are applied 
	/// (added to a storyboard for a particular value) when you call CAnimationController::AnimateGroup.
	/// </remarks>
	/// <param name="pTransition">A pointer to transition object.</param>
	void AddTransition(CBaseTransition* pTransition);

protected:
	/// <summary>
	/// Puts the encapsulated animation variable into a list.
	/// </summary>
	/// <param name="lst">When the function returns, it contains a pointer to CAnimationVariable representing the animated value.</param>
	virtual void GetAnimationVariableList(CList<CAnimationVariable*, CAnimationVariable*>& lst);
};

/// <summary>
/// Implements the functionality of a point whose coordinates can be animated.
/// </summary>
/// <remarks>
/// The CAnimationPoint class encapsulates two CAnimationVariable objects and can represent in applications
/// a point. For example, you can use this class to animate a position of any object on the screen (like text string, circle, point etc).
/// To use this class in application, just instantiate an object of this class, add it to animation controller using
/// CAnimationController::AddAnimationObject and call AddTransition for each transition to be applied to X and/or Y coordinates. 
/// </remarks>
class CAnimationPoint : public CAnimationBaseObject
{
	DECLARE_DYNAMIC(CAnimationPoint)
protected:
	/// <summary>
	/// The encapsulated animation variable that represents X coordinate of animation point.
	/// </summary>
	CAnimationVariable 	m_xValue;

	/// <summary>
	/// The encapsulated animation variable that represents Y coordinate of animation point.
	/// </summary>
	CAnimationVariable 	m_yValue;

public:
	/// <summary>
	/// Constructs CAnimationPoint object.
	/// </summary>
	/// <remarks>
	/// Constructs CAnimationPoint object with default properties: default point coordinates, Group ID and Object ID are set to 0.
	/// </remarks>
	CAnimationPoint();

	/// <summary>
	/// Constructs CAnimationPoint object.
	/// </summary>
	/// <remarks>
	/// Constructs CAnimationPoint object with specified properties.
	/// </remarks>
	/// <param name="ptDefault">Specifies default point coordinates.</param>
	/// <param name="nGroupID">Specifies Group ID.</param>
	/// <param name="nObjectID">Specifies Object ID.</param>
	/// <param name="dwUserData">Specifies user-defined data.</param>
	CAnimationPoint(const CPoint& ptDefault, UINT32 nGroupID, UINT32 nObjectID = (UINT32)-1, DWORD dwUserData = 0);

	/// <summary>
	/// Sets default value.
	/// </summary>
	/// <remarks>
	/// Use this function to set a default value to animation object. This methods assigns default values to X and Y 
	/// coordinates of animation point. It also recreates underlying COM objects if they have been created. If you 
	/// subscribed this animation object to events (ValueChanged or IntegerValueChanged), you need to re-enable these events.
	/// </remarks>
	/// <param name="ptDefault">Specifies the default point value.</param>
	void SetDefaultValue(const POINT& ptDefault);

	/// <summary>
	/// Returns the default values for X and Y coordinates.
	/// </summary>
	/// <returns> 
	/// A point containing default value.
	/// </returns> 
	/// <remarks>
	/// Call this function to retrieve default value, which was previously set by constructor or SetDefaultValue.
	/// </remarks>
	CPoint GetDefaultValue();

	/// <summary>
	/// Returns current value.
	/// </summary>
	/// <returns> 
	/// TRUE, if the current value was successfully retrieved; otherwise FALSE.
	/// </returns> 
	/// <remarks>
	/// Call this function to retrieve the current value of animation point. If this method fails or underlying COM objects for 
	/// X and Y coordinates have not been initialized, ptValue contains default
	/// value, which was previously set in constructor or by SetDefaultValue. 
	/// </remarks>
	/// <param name="ptValue">Output. Contains the current value when this method returns.</param>
	BOOL GetValue(CPoint& ptValue);

	/// <summary>
	/// Assigns ptSrc to CAnimationPoint.
	/// </summary>
	/// <remarks>
	/// Assigns ptSrc to CAnimationPoint. It's recommended to do that before animation start, because this operator calls
	/// SetDefaultValue, which recreates the underlying COM objects for X and Y coordinates if they have been created. If you 
	/// subscribed this animation object to events (ValueChanged or IntegerValueChanged), you need to re-enable these events.
	/// </remarks>
	/// <param name="ptSrc">Refers to CPoint or POINT.</param>
	void operator=(const CPoint& ptSrc) 
	{
		SetDefaultValue(ptSrc);
	}

	/// <summary>
	/// Converts a CAnimationPoint to a CPoint.
	/// </summary>
	/// <returns>
	/// Current value of CAnimationPoint as CPoint.
	/// </returns>
	/// <remarks>
	/// This function internally calls GetValue. If GetValue for some reason fails, the returned point will contain default values for X and Y coordinates.
	/// </remarks>
	operator CPoint()
	{
		CPoint pt;
		GetValue(pt); 
		return pt;
	}

	/// <summary>
	/// Provides access to CAnimationVariable for X coordinate.
	/// </summary>
	/// <returns> 
	/// A reference to encapsulated CAnimationVariable representing X coordinate.
	/// </returns> 
	/// <remarks>
	/// You can call this method to get direct access to underlying CAnimationVariable representing X coordinate.
	/// </remarks>
	CAnimationVariable& GetX() {return m_xValue;}

	/// <summary>
	/// Provides access to CAnimationVariable for Y coordinate.
	/// </summary>
	/// <returns> 
	/// A reference to encapsulated CAnimationVariable representing Y coordinate.
	/// </returns> 
	/// <remarks>
	/// You can call this method to get direct access to underlying CAnimationVariable representing Y coordinate.
	/// </remarks>
	CAnimationVariable& GetY() {return m_yValue;}

	/// <summary>
	/// Adds transitions for X and Y coordinates. 
	/// </summary>
	/// <remarks>
	/// Call this function to add the specified transitions to the internal list of transitions to be applied to animation variables for X and Y coordinates.
	/// When you add transitions, they are not applied immediately and stored in an internal list. Transitions are applied 
	/// (added to a storyboard for a particular value) when you call CAnimationController::AnimateGroup.
	/// If you don't need to apply a transition to one of coordinates, you can pass NULL.
	/// </remarks>
	/// <param name="pXTransition">A pointer to transition for X coordinates.</param>
	/// <param name="pYTransition">A pointer to transition for Y coordinate.</param>
	void AddTransition(CBaseTransition* pXTransition, CBaseTransition* pYTransition);

protected:
	/// <summary>
	/// Puts the encapsulated animation variables into a list.
	/// </summary>
	/// <param name="lst">When the function returns, it contains pointers to two CAnimationVariable objects 
	/// representing the X and Y coordinates.</param>
	virtual void GetAnimationVariableList(CList<CAnimationVariable*, CAnimationVariable*>& lst);
};

/// <summary>
/// Implements the functionality of a size object whose dimensions can be animated.
/// </summary>
/// <remarks>
/// The CAnimationSize class encapsulates two CAnimationVariable objects and can represent in applications
/// a size. For example, you can use this class to animate a size of any two dimensional object on the screen (like rectangle, control etc).
/// To use this class in application, just instantiate an object of this class, add it to animation controller using
/// CAnimationController::AddAnimationObject and call AddTransition for each transition to be applied to Width and/or Height. 
/// </remarks>
class CAnimationSize  : public CAnimationBaseObject
{
	DECLARE_DYNAMIC(CAnimationSize)
protected:
	/// <summary>
	/// The encapsulated animation variable that represents width of animation size.
	/// </summary>
	CAnimationVariable 	m_cxValue;

	/// <summary>
	/// The encapsulated animation variable that represents height of animation size.
	/// </summary>
	CAnimationVariable 	m_cyValue;

public:
	/// <summary>
	/// Constructs an animation size object.
	/// </summary>
	/// <remarks>
	/// The object is constructed with default values for width, height, Object ID and Group ID, which will be set to 0. They can be changed
	/// later at runtime using SetDefaultValue and SetID.
	/// </remarks>
	CAnimationSize();

	/// <summary>
	/// Constructs an animation size object.
	/// </summary>
	/// <remarks>
	/// The object is constructed with specified values for width, height, Object ID and Group ID. They can be changed
	/// later at runtime using SetDefaultValue and SetID.
	/// </remarks>
	/// <param name="szDefault">Specifies default size.</param>
	/// <param name="nGroupID">Specifies Group ID.</param>
	/// <param name="nObjectID">Specifies Object ID.</param>
	/// <param name="dwUserData">Specifies user-defined data.</param>
	CAnimationSize(const CSize& szDefault, UINT32 nGroupID, UINT32 nObjectID = (UINT32)-1, DWORD dwUserData = 0);

	/// <summary>
	/// Sets default value.
	/// </summary>
	/// <remarks>
	/// Use this function to set a default value to animation object. This methods assigns default values to Width and Height 
	/// of animation size. It also recreates underlying COM objects if they have been created. If you 
	/// subscribed this animation object to events (ValueChanged or IntegerValueChanged), you need to re-enable these events.
	/// </remarks>
	/// <param name="szDefault">Specifies new default size.</param>
	void SetDefaultValue(const CSize& szDefault);

	/// <summary>
	/// Returns the default values for Width and Height.
	/// </summary>
	/// <returns> 
	/// A CSize object containing default values.
	/// </returns> 
	/// <remarks>
	/// Call this function to retrieve default value, which was previously set by constructor or SetDefaultValue.
	/// </remarks>
	CSize GetDefaultValue();

	/// <summary>
	/// Returns current value.
	/// </summary>
	/// <returns> 
	/// TRUE, if the current value was successfully retrieved; otherwise FALSE.
	/// </returns> 
	/// <remarks>
	/// Call this function to retrieve the current value of animation size. If this method fails or underlying COM objects for 
	/// Width and Size have not been initialized, szValue contains default value, which was previously set in constructor or by SetDefaultValue. 
	/// </remarks>
	/// <param name="szValue">Output. Contains the current value when this method returns.</param>
	BOOL GetValue(CSize& szValue);

	/// <summary>
	/// Provides access to CAnimationVariable representing Width.
	/// </summary>
	/// <returns> 
	/// A reference to encapsulated CAnimationVariable representing Width.
	/// </returns> 
	/// <remarks>
	/// You can call this method to get direct access to underlying CAnimationVariable representing Width.
	/// </remarks>
	CAnimationVariable& GetCX() {return m_cxValue;}

	/// <summary>
	/// Provides access to CAnimationVariable representing Height.
	/// </summary>
	/// <returns> 
	/// A reference to encapsulated CAnimationVariable representing Height.
	/// </returns> 
	/// <remarks>
	/// You can call this method to get direct access to underlying CAnimationVariable representing Height.
	/// </remarks>
	CAnimationVariable& GetCY() {return m_cyValue;}

	/// <summary>
	/// Assigns szSrc to CAnimationSize.
	/// </summary>
	/// <remarks>
	/// Assigns szSrc to CAnimationSize. It's recommended to do that before animation start, because this operator calls
	/// SetDefaultValue, which recreates the underlying COM objects for Width and Height if they have been created. If you 
	/// subscribed this animation object to events (ValueChanged or IntegerValueChanged), you need to re-enable these events.
	/// </remarks>
	/// <param name="szSrc">Refers to CSize or SIZE.</param>
	void operator=(const CSize& szSrc)
	{
		SetDefaultValue(szSrc);
	}

	/// <summary>
	/// Converts a CAnimationSize to a CSize.
	/// </summary>
	/// <returns>
	/// Current value of animation size as CSize.
	/// </returns>
	/// <remarks>
	/// This function internally calls GetValue. If GetValue for some reason fails, the returned size will contain default values for Width and Height.
	/// </remarks>
	operator CSize()
	{
		CSize sz;
		GetValue(sz); 
		return sz;
	}

	
	/// <summary>
	/// Adds transitions for Width and Height. 
	/// </summary>
	/// <remarks>
	/// Call this function to add the specified transitions to the internal list of transitions to be applied to animation variables for Width and Height.
	/// When you add transitions, they are not applied immediately and stored in an internal list. Transitions are applied 
	/// (added to a storyboard for a particular value) when you call CAnimationController::AnimateGroup.
	/// If you don't need to apply a transition to one of dimensions, you can pass NULL.
	/// </remarks>
	/// <param name="pCXTransition">A pointer to transition for Width.</param>
	/// <param name="pCYTransition">A pointer to transition for Height.</param>

	void AddTransition(CBaseTransition* pCXTransition, CBaseTransition* pCYTransition);

protected:
	/// <summary>
	/// Puts the encapsulated animation variables into a list.
	/// </summary>
	/// <param name="lst">When the function returns, it contains pointers to two CAnimationVariable objects 
	/// representing the width and height.</param>
	virtual void GetAnimationVariableList(CList<CAnimationVariable*, CAnimationVariable*>& lst);
};

/// <summary>
/// Implements the functionality of a color whose red, green and blue components can be animated.
/// </summary>
/// <remarks>
/// The CAnimationColor class encapsulates three CAnimationVariable objects and can represent in applications
/// a color. For example, you can use this class to animate colors of any object on the screen (like text color, background color etc).
/// To use this class in application, just instantiate an object of this class, add it to animation controller using
/// CAnimationController::AddAnimationObject and call AddTransition for each transition to be applied to Red, Green and Blue components. 
/// </remarks>
class CAnimationColor : public CAnimationBaseObject
{
	DECLARE_DYNAMIC(CAnimationColor)
protected:
	/// <summary>
	/// The encapsulated animation variable that represents Red component of animation color.
	/// </summary>
	CAnimationVariable 	m_rValue;

	/// <summary>
	/// The encapsulated animation variable that represents Green component of animation color.
	/// </summary>
	CAnimationVariable 	m_gValue;

	/// <summary>
	/// The encapsulated animation variable that represents Blue component of animation color.
	/// </summary>
	CAnimationVariable 	m_bValue;

public:
	/// <summary>
	/// Constructs a CAnimationColor object.
	/// </summary>
	/// <remarks>
	/// The object is constructed with default values for red, green, blue, Object ID and Group ID, which will be set to 0. They can be changed
	/// later at runtime using SetDefaultValue and SetID.
	/// </remarks>
	CAnimationColor();

	/// <summary>
	/// Constructs an animation color object.
	/// </summary>
	/// <remarks>
	/// The object is constructed with specified values for RGB components, Object ID and Group ID. They can be changed
	/// later at runtime using SetDefaultValue and SetID.
	/// </remarks>
	/// <param name="color">Specifies default color.</param>
	/// <param name="nGroupID">Specifies Group ID.</param>
	/// <param name="nObjectID">Specifies Object ID.</param>
	/// <param name="dwUserData">Specifies user-defined data.</param>
	CAnimationColor(COLORREF color, UINT32 nGroupID, UINT32 nObjectID = (UINT32)-1, DWORD dwUserData = 0);

	/// <summary>
	/// Sets default value.
	/// </summary>
	/// <remarks>
	/// Use this function to set a default value to animation object. This methods assigns default values to color components 
	/// of animation color. It also recreates underlying COM objects if they have been created. If you 
	/// subscribed this animation object to events (ValueChanged or IntegerValueChanged), you need to re-enable these events.
	/// </remarks>
	/// <param name="color">Specifies new default values for red, green and blue components.</param>
	void SetDefaultValue(COLORREF color);

	/// <summary>
	/// Returns the default values for color components.
	/// </summary>
	/// <returns> 
	/// A COLORREF value containing defaults for RGB components.
	/// </returns> 
	/// <remarks>
	/// Call this function to retrieve default value, which was previously set by constructor or SetDefaultValue.
	/// </remarks>
	COLORREF GetDefaultValue();

	/// <summary>
	/// Returns current value.
	/// </summary>
	/// <returns> 
	/// TRUE, if the current value was successfully retrieved; otherwise FALSE.
	/// </returns> 
	/// <remarks>
	/// Call this function to retrieve the current value of animation color. If this method fails or underlying COM objects for 
	/// color components have not been initialized, color contains default value, which was previously set in constructor or by SetDefaultValue. 
	/// </remarks>
	/// <param name="color">Output. Contains the current value when this method returns.</param>
	BOOL GetValue(COLORREF& color);

	/// <summary>
	/// Provides access to CAnimationVariable representing Red component.
	/// </summary>
	/// <returns> 
	/// A reference to encapsulated CAnimationVariable representing Red component.
	/// </returns> 
	/// <remarks>
	/// You can call this method to get direct access to underlying CAnimationVariable representing Red component.
	/// </remarks>
	CAnimationVariable& GetR() {return m_rValue;}

	/// <summary>
	/// Provides access to CAnimationVariable representing Green component.
	/// </summary>
	/// <returns> 
	/// A reference to encapsulated CAnimationVariable representing Green component.
	/// </returns> 
	/// <remarks>
	/// You can call this method to get direct access to underlying CAnimationVariable representing Green component.
	/// </remarks>
	CAnimationVariable& GetG() {return m_gValue;}

	/// <summary>
	/// Provides access to CAnimationVariable representing Blue component.
	/// </summary>
	/// <returns> 
	/// A reference to encapsulated CAnimationVariable representing Blue component.
	/// </returns> 
	/// <remarks>
	/// You can call this method to get direct access to underlying CAnimationVariable representing Blue component.
	/// </remarks>
	CAnimationVariable& GetB() {return m_bValue;}

	/// <summary>
	/// Assigns color to CAnimationColor.
	/// </summary>
	/// <remarks>
	/// It's recommended to do that before animation start, because this operator calls
	/// SetDefaultValue, which recreates the underlying COM objects for color components if they have been created. If you 
	/// subscribed this animation object to events (ValueChanged or IntegerValueChanged), you need to re-enable these events.
	/// </remarks>
	/// <param name="color">Specifies new value Animation Color.</param>
	void operator=(COLORREF color)
	{
		SetDefaultValue(color);
	}

	/// <summary>
	/// Converts a CAnimationColor to COLORREF.
	/// </summary>
	/// <returns>
	/// Current value of animation color object as COLORREF.
	/// <returns>
	/// <remarks>
	/// This function internally calls GetValue. If GetValue for some reason fails, the returned COLORREF will contain default values for all color components.
	/// </remarks>
	operator COLORREF()
	{
		COLORREF color;
		GetValue(color);
		return color;
	}

	/// <summary>
	/// Adds transitions for Red, Green and Blue components. 
	/// </summary>
	/// <remarks>
	/// Call this function to add the specified transitions to the internal list of transitions to be applied to animation variables representing color components.
	/// When you add transitions, they are not applied immediately and stored in an internal list. Transitions are applied 
	/// (added to a storyboard for a particular value) when you call CAnimationController::AnimateGroup.
	/// If you don't need to apply a transition to one of the color components, you can pass NULL.
	/// </remarks>
	/// <param name="pRTransition">Transition for Red component.</param>
	/// <param name="pGTransition">Transition for Green component.</param>
	/// <param name="pBTransition">Transition for Blue component.</param>
	void AddTransition(CBaseTransition* pRTransition, CBaseTransition* pGTransition, CBaseTransition* pBTransition);

protected:
	/// <summary>
	/// Puts the encapsulated animation variables into a list.
	/// </summary>
	/// <param name="lst">When the function returns, it contains pointers to three CAnimationVariable objects 
	/// representing red, green and blue components.</param>
	virtual void GetAnimationVariableList(CList<CAnimationVariable*, CAnimationVariable*>& lst);
};

/// <summary>
/// Implements the functionality of a rectangle whose top, left, right and bottom sides can be animated.
/// </summary>
/// <remarks>
/// The CAnimationRect class encapsulates four CAnimationVariable objects and can represent in applications
/// a rectangle.
/// To use this class in application, just instantiate an object of this class, add it to animation controller using
/// CAnimationController::AddAnimationObject and call AddTransition for each transition to be applied to left, right top and bottom coordinates. 
/// </remarks>
class CAnimationRect : public CAnimationBaseObject
{
	DECLARE_DYNAMIC(CAnimationRect)
protected:
	/// <summary>
	/// The encapsulated animation variable that represents Left bound of animation rectangle.
	/// </summary>
	CAnimationVariable m_leftValue;

	/// <summary>
	/// The encapsulated animation variable that represents Top bound of animation rectangle.
	/// </summary>
	CAnimationVariable m_topValue;

	/// <summary>
	/// The encapsulated animation variable that represents Right bound of animation rectangle.
	/// </summary>
	CAnimationVariable m_rightValue;

	/// <summary>
	/// The encapsulated animation variable that represents Bottom bound of animation rectangle.
	/// </summary>
	CAnimationVariable m_bottomValue;

	/// <summary>
	/// Specifies initial size of animation rectangle.
	/// </summary>
	CSize 	m_szInitial;

public:
	/// <summary>
	/// Constructs a CAnimationRect object.
	/// </summary>
	/// <remarks>
	/// The object is constructed with default values for left, top, right and bottom, Object ID and Group ID, which will be set to 0. They can be changed
	/// later at runtime using SetDefaultValue and SetID.
	/// </remarks>
	CAnimationRect();

	/// <summary>
	/// Constructs an animation rect object.
	/// </summary>
	/// <remarks>
	/// The object is constructed with specified rect coordinates, Object ID and Group ID. They can be changed
	/// later at runtime using SetDefaultValue and SetID.
	/// </remarks>
	/// <param name="rect">Specifies default rectangle.</param>
	/// <param name="nGroupID">Specifies Group ID.</param>
	/// <param name="nObjectID">Specifies Object ID.</param>
	/// <param name="dwUserData">Specifies user-defined data.</param>
	CAnimationRect(const CRect& rect, UINT32 nGroupID, UINT32 nObjectID = (UINT32)-1, DWORD dwUserData = 0);

	/// <summary>
	/// Constructs an animation rect object.
	/// </summary>
	/// <remarks>
	/// The object is constructed with specified top-left corner coordinates and size of rectangle, Object ID and Group ID. They can be changed
	/// later at runtime using SetDefaultValue and SetID.
	/// </remarks>
	/// <param name="pt">Coordinate of top-left corner.</param>
	/// <param name="sz">Size of rectangle.</param>
	/// <param name="nGroupID">Specifies Group ID.</param>
	/// <param name="nObjectID">Specifies Object ID.</param>
	/// <param name="dwUserData">Specifies user-defined data.</param>
	CAnimationRect(const CPoint& pt, const CSize& sz, UINT32 nGroupID, UINT32 nObjectID = (UINT32)-1, DWORD dwUserData = 0);

	/// <summary>
	/// Constructs an animation rect object.
	/// </summary>
	/// <remarks>
	/// The object is constructed with specified coordinates of each side, Object ID and Group ID. They can be changed
	/// later at runtime using SetDefaultValue and SetID.
	/// </remarks>
	/// <param name="nLeft">Specifies coordinate of left bound.</param>
	/// <param name="nTop">Specifies coordinate of top bound.</param>
	/// <param name="nRight">Specifies coordinate of right bound.</param>
	/// <param name="nBottom">Specifies coordinate of bottom bound.</param>
	/// <param name="nGroupID">Specifies Group ID.</param>
	/// <param name="nObjectID">Specifies Object ID.</param>
	/// <param name="dwUserData">Specifies user-defined data.</param>
	CAnimationRect(int nLeft, int nTop, int nRight, int nBottom, UINT32 nGroupID, UINT32 nObjectID = (UINT32)-1, DWORD dwUserData = 0);

	/// <summary>
	/// Sets default value.
	/// </summary>
	/// <remarks>
	/// Use this function to set a default value to animation object. This methods assigns default values to rectangle's bounds. 
	/// It also recreates underlying COM objects if they have been created. If you 
	/// subscribed this animation object to events (ValueChanged or IntegerValueChanged), you need to re-enable these events.
	/// </remarks>
	/// <param name="rect">Specifies new default values for left, top, right and bottom.</param>
	void SetDefaultValue(const CRect& rect);

	/// <summary>
	/// Returns the default values for rectangle's bounds.
	/// </summary>
	/// <returns> 
	/// A CRect value containing defaults for left, right, top and bottom.
	/// </returns> 
	/// <remarks>
	/// Call this function to retrieve default value, which was previously set by constructor or SetDefaultValue.
	/// </remarks>
	CRect GetDefaultValue();

	/// <summary>
	/// Returns current value.
	/// </summary>
	/// <returns> 
	/// TRUE, if the current value was successfully retrieved; otherwise FALSE.
	/// </returns> 
	/// <remarks>
	/// Call this function to retrieve the current value of animation rectangle. If this method fails or underlying COM objects for 
	/// left, top, right and bottom have not been initialized, rect contains default value, which was previously set in constructor or by SetDefaultValue. 
	/// </remarks>
	/// <param name="rect">Output. Contains the current value when this method returns.</param>
	BOOL GetValue(CRect& rect);

	/// <summary>
	/// Provides access to CAnimationVariable representing left coordinate.
	/// </summary>
	/// <returns> 
	/// A reference to encapsulated CAnimationVariable representing left coordinate.
	/// </returns> 
	/// <remarks>
	/// You can call this method to get direct access to underlying CAnimationVariable representing the left coordinate.
	/// </remarks>
	CAnimationVariable& GetLeft() 	{return m_leftValue;}

	/// <summary>
	/// Provides access to CAnimationVariable representing top coordinate.
	/// </summary>
	/// <returns> 
	/// A reference to encapsulated CAnimationVariable representing top coordinate.
	/// </returns> 
	/// <remarks>
	/// You can call this method to get direct access to underlying CAnimationVariable representing the top coordinate.
	/// </remarks>
	CAnimationVariable& GetTop() 	{return m_topValue;}

	/// <summary>
	/// Provides access to CAnimationVariable representing right coordinate.
	/// </summary>
	/// <returns> 
	/// A reference to encapsulated CAnimationVariable representing right coordinate.
	/// </returns> 
	/// <remarks>
	/// You can call this method to get direct access to underlying CAnimationVariable representing the right coordinate.
	/// </remarks>
	CAnimationVariable& GetRight() 	{return m_rightValue;}

	/// <summary>
	/// Provides access to CAnimationVariable representing bottom coordinate.
	/// </summary>
	/// <returns> 
	/// A reference to encapsulated CAnimationVariable representing bottom coordinate.
	/// </returns> 
	/// <remarks>
	/// You can call this method to get direct access to underlying CAnimationVariable representing the bottom coordinate.
	/// </remarks>
	CAnimationVariable& GetBottom() {return m_bottomValue;}

	/// <summary>
	/// Assigns rect to CAnimationRect.
	/// </summary>
	/// <remarks>
	/// It's recommended to do that before animation start, because this operator calls
	/// SetDefaultValue, which recreates the underlying COM objects for color components if they have been created. If you 
	/// subscribed this animation object to events (ValueChanged or IntegerValueChanged), you need to re-enable these events.
	/// </remarks>
	/// <param name="rect">The new value of animation rectangle.</param>
	void operator=(const RECT& rect)
	{
		SetDefaultValue(rect);
	}

	/// <summary>
	/// Converts a CAnimationRect to RECT.
	/// </summary>
	/// <returns>
	/// Current value of animation rectangle as RECT.
	/// </returns>
	/// <remarks>
	/// This function internally calls GetValue. If GetValue for some reason fails, the returned RECT will contain default values for all rectangle coordinates.
	/// </remarks>
	operator RECT()
	{
		CRect rect;
		GetValue(rect);
		return rect;
	}

	/// <summary>
	/// Adds transitions for left, top, right and bottom coordinates. 
	/// </summary>
	/// <remarks>
	/// Call this function to add the specified transitions to the internal list of transitions to be applied to animation variables for each rectangle sides.
	/// When you add transitions, they are not applied immediately and stored in an internal list. Transitions are applied 
	/// (added to a storyboard for a particular value) when you call CAnimationController::AnimateGroup.
	/// If you don't need to apply a transition to one of the rectangle sides, you can pass NULL.
	/// </remarks>
	/// <param name="pLeftTransition">Specifies transition for the left side.</param>
	/// <param name="pTopTransition">Specifies transition for the top side.</param>
	/// <param name="pRightTransition">Specifies transition for the right side.</param>
	/// <param name="pBottomTransition">Specifies transition for the bottom side.</param>
	void AddTransition(CBaseTransition* pLeftTransition, CBaseTransition* pTopTransition, 
		CBaseTransition* pRightTransition, CBaseTransition* pBottomTransition);

public:
	/// <summary>
	/// Specifies whether the rectangle has fixed size.
	/// </summary>
	/// <remarks>
	/// If this member is true, then the size of rectangle is fixed and right and bottom values
	/// are recalculated each time the top-left corner is  moved according to the fixed size.
	/// Set this value to TRUE to easily move the rectangle around the screen. In this case transitions applied to
	/// right and bottom coordinates are ignored. The size is stored internally when you construct the object and/or
	/// call SetDefaultValue. By default this member is set to FALSE.
	/// </remarks>
	BOOL 	m_bFixedSize;

protected:
	/// <summary>
	/// Puts the encapsulated animation variables into a list.
	/// </summary>
	/// <param name="lst">When the function returns, it contains pointers to four CAnimationVariable objects 
	/// representing coordinates of rectangle.</param>
	virtual void GetAnimationVariableList(CList<CAnimationVariable*, CAnimationVariable*>& lst);
};

/// <summary>
/// Implements an animation group, which combines an animation storyboard, animation objects and transitions
/// to define an animation.
/// </summary>
/// <remarks>
/// Animation groups are created automatically by animation controller (CAnimationController) when you add animation
/// objects using CAnimationController::AddAnimationObject. 
/// An animation group is identified by GroupID, which is usually taken as a parameter to manipulate animation groups.
/// The GroupID is taken from the first animation object being added to a new animation group.
/// An encapsulated animation storyboard is created after you call CAnimationController::AnimateGroup and can be 
/// accessed via public member m_pStoryboard.
/// </remarks>
class CAnimationGroup
{
protected:
	/// <summary>
	/// A unique identifier of animation group. 
	/// </summary>
	UINT32 	m_nGroupID;

	/// <summary>
	/// A pointer to animation controller this group belongs to.
	/// </summary>
	CAnimationController* m_pParentController;
protected:
	/// <summary>
	/// A helper that adds keyframes to a storyboard.
	/// </summary>
	/// <param name="pStoryboard">A pointer to a storyboard COM object.</param>
	/// <param name="bAddDeep">Specifies whether this method should add to the storyboard keyframes that depend on other keyframes.</param>
	void AddKeyframes(IUIAnimationStoryboard* pStoryboard, BOOL bAddDeep);

	/// <summary>
	/// A helper that adds transitions to a storyboard.
	/// </summary>
	/// <param name="pStoryboard">A pointer to a storyboard COM object.</param>
	/// <param name="bAddDeep">Specifies whether this method should add to the storyboard transitions that depend on other keyframes.</param>
	void AddTransitions(IUIAnimationStoryboard* pStoryboard, BOOL bDependOnKeyframes);

	/// <summary>
	/// A helper that creates COM transition objects.
	/// </summary>
	/// <returns>
	/// TRUE is the method succeeds, otherwise FALSE.
	/// </returns>
	BOOL CreateTransitions();

public:
	/// <summary>
	/// Constructs an animation group.
	/// </summary>
	/// <param name="pParentController">A pointer to animation controller that creates a group.</param>
	/// <param name="nGroupID">Specifies GroupID.</param>
	CAnimationGroup(CAnimationController* pParentController, UINT32 nGroupID);

	/// <summary>
	/// The destructor. Called when an animation group is being destroyed.
	/// </summary>
	~CAnimationGroup();

	/// <summary>
	/// Returns GroupID.
	/// </summary>
	/// <returns>
	/// A group identifier.
	/// </returns>
	UINT32 GetGroupID() const {return m_nGroupID;}

	/// <summary>
	/// Applies transitions to animation objects.
	/// </summary>
	/// <remarks>
	/// This method ASSERTS in debug mode if storyboard has not been created. 
	/// It creates all transitions first, then adds "static" keyframes (keyframes that depend on offsets),
	/// adds transitions that do not depend on keyframes, adds keyframes depending on transitions and other keyframes,
	/// and at last adds transitions that depend on keyframes.
	/// </remarks>
	void ApplyTransitions();

	/// <summary>
	/// Removes transitions from animation objects that belong to an animation group.
	/// </summary>
	/// <remarks>
	/// If m_bAutoclearTransitions flag is set to TRUE, this method loops over all animation objects that belong to the group
	/// and calls CAnimationObject::ClearTransitions(FALSE).
	/// </remarks>
	void RemoveTransitions();

	/// <summary>
	/// Removes and optionally destroys all keyframes that belong to an animation group.
	/// </summary>
	/// <remarks>
	/// If m_bAutodestroyKeyframes member is TRUE then keyframes are removed and destroyed, otherwise keyframes are 
	/// just removed from the internal list of keyframes.
	/// </remarks>
	void RemoveKeyframes();

	/// <summary>
	/// Finds an animation object that contains the specified animation variable.
	/// </summary>
	/// <returns> 
	/// A pointer to animation object, or NULL if animation object is not found.
	/// </returns> 
	/// <param name="pVariable">A pointer to animation variable.</param>
	CAnimationBaseObject* FindAnimationObject(IUIAnimationVariable* pVariable);

	/// <summary>
	/// Animates a group.
	/// </summary>
	/// <returns> 
	/// TRUE if the method succeeds; otherwise FALSE.
	/// </returns> 
	/// <remarks>
	/// This method creates an internal storyboard, creates and applies transitions and schedules an animation
	/// if bScheduleNow is TRUE. If bScheduleNow is FALSE, you need to call Schedule to start animation at the 
	/// specified time.
	/// </remarks>
	/// <param name="pManager"></param>
	/// <param name="pTimer"></param>
	/// <param name="bScheduleNow"></param>
	BOOL Animate(IUIAnimationManager* pManager, IUIAnimationTimer* pTimer, BOOL bScheduleNow);

	/// <summary>
	/// Schedules an animation at the specified time.
	/// </summary>
	/// <returns> 
	/// TRUE if the method succeeds; FALSE if the method fails or if Animate has not been called with bScheduleNow set to FALSE.
	/// </returns> 
	/// <remarks>
	/// Call this function to schedule an animation at the specified time. You must call Animate with bScheduleNow set to FALSE first.
	/// </remarks>
	/// <param name="pTimer">A pointer to animation timer.</param>
	/// <param name="time">Specifies time to schedule the animation.</param>
	BOOL Schedule(IUIAnimationTimer* pTimer, UI_ANIMATION_SECONDS time);

	/// <summary>
	/// Directs all animation objects that belong to group automatically destroy transitions. 
	/// </summary>
	/// <remarks>
	/// Set this value to FALSE only if you allocate transitions on the stack. The default value is TRUE, therefore
	/// it's highly recommended to allocate transition objects using operator new.
	/// </remarks>
	/// <param name="bAutoDestroy">Specifies how to destroy transitions.</param>
	void SetAutodestroyTransitions(BOOL bAutoDestroy = TRUE);

public:
	/// <summary>
	/// Contains a list of animation objects.
	/// </summary>
	CObList m_lstAnimationObjects;

	/// <summary>
	/// Contains a list of keyframes.
	/// </summary>
	CObList m_lstKeyFrames;

	/// <summary>
	/// Points to animation storyboard. This pointer is valid only after call on Animate.
	/// </summary>
	ATL::CComPtr<IUIAnimationStoryboard> m_pStoryboard;

	/// <summary>
	/// Specifies how to destroy keyframes. If this value is TRUE, all keyframes are removed and destroyed;
	/// otherwise they are removed from the list only. The default value is TRUE.
	/// </summary>
	BOOL	m_bAutodestroyKeyframes;

	/// <summary>
	/// Specifies how to clear transitions from animation objects that belong to group. If this member is TRUE,
	/// transitions are removed automatically when an animation has been scheduled. Otherwise you need to remove 
	/// transitions manually.
	/// </summary>
	BOOL 	m_bAutoclearTransitions;

	/// <summary>
	/// Specifies how to destroy animation objects. If this parameter is TRUE, animation objects will be destroyed automatically
	/// when the group is destroyed. Otherwise animation objects must be destroyed manually. The default value is FALSE.
	/// Set this value to TRUE only if all animation objects that belong to group are allocated dynamically with operator new.
	/// </summary>
	BOOL 	m_bAutodestroyAnimationObjects;
};

// PHT - priority handler type
#define UI_ANIMATION_PHT_NONE				0x0000
#define UI_ANIMATION_PHT_CANCEL 			0x0001
#define UI_ANIMATION_PHT_CONCLUDE 			0x0002
#define UI_ANIMATION_PHT_COMPRESS			0x0004
#define UI_ANIMATION_PHT_TRIM 				0x0008
#define UI_ANIMATION_PHT_ALL 				0x00FF
#define UI_ANIMATION_PHT_CANCEL_REMOVE 		0x0010
#define UI_ANIMATION_PHT_CONCLUDE_REMOVE	0x0020
#define UI_ANIMATION_PHT_COMPRESS_REMOVE	0x0040
#define UI_ANIMATION_PHT_TRIM_REMOVE		0x0080

/// <summary>
/// Implements the animation controller, which provides a central interface for creating and managing UI animations.
/// </summary>
/// <remarks>
/// The CAnimationController class is the key class that manages animations.
/// You may create one or more instances of animation controller in an application and, optionally, connect an instance of 
/// animation controller to a CWnd object using CAnimationController::SetRelatedWnd. This connection is required to send WM_PAINT messages 
/// to the related window automatically when animation manager status has changed or animation timer has been updated. 
/// If you do not enable this relation, you must redraw a window that displays an animation manually. For this purpose you can derive a class 
/// from CAnimationController and override OnAnimationManagerStatusChanged and/or OnAnimationTimerPostUpdate and invalidate one or 
/// more windows when necessary.
/// </remarks>
class CAnimationController : public CObject
{
	DECLARE_DYNCREATE(CAnimationController)
protected:
	/// <summary>
	/// Specifies whether an animation controller is valid or not. 
	/// This member is set to FALSE if current OS does not support Windows Animation API.
	/// </summary>
	BOOL m_bIsValid;

	/// <summary>
	/// Stores a pointer to Animation Manager COM object.
	/// </summary>
	ATL::CComPtr<IUIAnimationManager> m_pAnimationManager;

	/// <summary>
	/// Stores a pointer to Transition Library COM object.
	/// </summary>
	ATL::CComPtr<IUIAnimationTransitionLibrary> m_pTransitionLibrary;

	/// <summary>
	/// Stores a pointer to Animation Timer COM object.
	/// </summary>
	ATL::CComPtr<IUIAnimationTimer> m_pAnimationTimer;

	/// <summary>
	/// Stores a pointer to Transition Factory COM object.
	/// </summary>
	ATL::CComPtr<IUIAnimationTransitionFactory> m_pTransitionFactory;

	/// <summary>
	/// A pointer to a related CWnd object, which can be automatically redrawn when 
	/// the status of animation manager has changed, or post update event has occurred. Can be NULL.
	/// </summary>
	CWnd* m_pRelatedWnd;

	/// <summary>
	/// A list of animation groups that belong to this animation controller.
	/// </summary>
	CList<CAnimationGroup*, CAnimationGroup*> m_lstAnimationGroups;

	/// <summary>
	/// A keyframe that represents start of storyboard.
	/// </summary>
	static CBaseKeyFrame g_KeyframeStoryboardStart;
public:

	/// <summary>
	/// Constructs an animation controller.
	/// </summary>
	CAnimationController(void);

	/// <summary>
	/// The destructor. Called when animation controller object is being destroyed.
	/// </summary>
	virtual ~CAnimationController(void);

	/// <summary>
	/// Provides access to encapsulated IUIAnimationManager object.
	/// </summary>
	/// <returns> 
	/// A pointer to IUIAnimationManager interface or NULL, if creation of animation manager failed.
	/// </returns> 
	/// <remarks>
	/// If current OS does not support Windows Animation API, this method returns NULL and after that all subsequent calls
	/// on CAnimationController::IsValid return FALSE.
	/// You may need to access IUIAnimationManager in order to call its interface methods, which are not wrapped by
	/// animation controller.
	/// </remarks>
	IUIAnimationManager* GetUIAnimationManager();

	/// <summary>
	/// Provides access to encapsulated IUIAnimationTransitionLibrary object.
	/// </summary>
	/// <returns>
	/// A pointer to IUIAnimationTransitionLibrary interface or NULL, if creation of transition library failed.
	/// </returns> 
	/// <remarks>
	/// If current OS does not support Windows Animation API, this method returns NULL and after that all subsequent calls
	/// on CAnimationController::IsValid return FALSE.
	/// </remarks>
	IUIAnimationTransitionLibrary* GetUITransitionLibrary();

	/// <summary>
	/// Provides access to encapsulated IUIAnimationTimer object.
	/// </summary>
	/// <returns> 
	/// A pointer to IUIAnimationTimer interface or NULL, if creation of animation timer failed.
	/// </returns> 
	/// <remarks>
	/// If current OS does not support Windows Animation API, this method returns NULL and after that all subsequent calls
	/// on CAnimationController::IsValid return FALSE.
	/// </remarks>
	IUIAnimationTimer* GetUIAnimationTimer();

	/// <summary>
	/// A pointer to IUIAnimationTransitionFactory interface or NULL, if creation of transition library failed.
	/// </summary>
	/// <returns> 
	/// A pointer to IUIAnimationTransitionFactory or NULL, if creation of transition factory failed.
	/// </returns> 
	/// <remarks>
	/// If current OS does not support Windows Animation API, this method returns NULL and after that all subsequent calls
	/// on CAnimationController::IsValid return FALSE.
	/// </remarks>
	IUIAnimationTransitionFactory* GetUITransitionFactory();

	/// <summary>
	/// Tells whether animation controller is valid.
	/// </summary>
	/// <returns> 
	/// TRUE if animation controller is valid; otherwise FALSE.
	/// </returns> 
	/// <remarks>
	/// This method returns FALSE only if Windows Animation API is not supported on the current OS and creation of 
	/// animation manager failed because it's not registered. You need to call GetUIAnimationManager at least once after initialization of
	/// COM libraries to cause setting of this flag.
	/// </remarks>
	BOOL IsValid() const {return m_bIsValid;}

	/// <summary>
	/// Returns a keyframe that identifies start of storyboard.
	/// </summary>
	/// <returns> 
	/// A pointer to base keyframe, which identifies start of storyboard.
	/// </returns> 
	/// <remarks>
	/// Obtain this keyframe to base any other keyframes or transitions on the moment in time when a storyboard starts.
	/// </remarks>
	static CBaseKeyFrame* GetKeyframeStoryboardStart();

	/// <summary>
	/// Sets or releases a handler to call when animation manager's status changes.
	/// </summary>
	/// <returns> 
	/// TRUE if the handler was successfully set or released.
	/// </returns> 
	/// <remarks>
	/// When a handler is set (enabled) Windows Animation calls OnAnimationManagerStatusChanged when animation manager's status changes.
	/// </remarks>
	/// <param name="bEnable">Specifies whether to set or release a handler.</param>
	virtual BOOL EnableAnimationManagerEvent(BOOL bEnable = TRUE);

	/// <summary>
	/// Sets or releases the priority comparison handler to call to determine whether a scheduled storyboard can be cancelled,
	/// concluded, trimmed or compressed.
	/// </summary>
	/// <returns> 
	/// TRUE if the handler was successfully set or released.
	/// </returns> 
	/// <remarks>
	/// When a handler is set (enabled) Windows Animation calls the following virtual methods depending on dwHandlerType:
	/// OnHasPriorityCancel, OnHasPriorityConclude, OnHasPriorityTrim, OnHasPriorityCompress.
	/// dwHandler can be a combination of the following flags:
	/// UI_ANIMATION_PHT_NONE - release all handlers 
	/// UI_ANIMATION_PHT_CANCEL - set Cancel comparison handler
	/// UI_ANIMATION_PHT_CONCLUDE - set Conclude comparison handler
	/// UI_ANIMATION_PHT_COMPRESS - set Compress comparison handler
	/// UI_ANIMATION_PHT_TRIM - set Trim comparison handler
	/// UI_ANIMATION_PHT_CANCEL_REMOVE - remove Cancel comparison handler
	/// UI_ANIMATION_PHT_CONCLUDE_REMOVE - remove Conclude comparison handler
	/// UI_ANIMATION_PHT_COMPRESS_REMOVE - remove Compress comparison handler
	/// UI_ANIMATION_PHT_TRIM_REMOVE - remove Trim comparison handler
	/// </remarks>
	/// <param name="dwHandlerType">A combination of UI_ANIMATION_PHT_ flags (see remarks), which specifies what handlers to set or release.</param>
	virtual BOOL EnablePriorityComparisonHandler(DWORD dwHandlerType);

	/// <summary>
	/// Sets or releases a handler for storyboard status and update events.
	/// </summary>
	/// <returns> 
	/// TRUE if the handler was successfully set or released; FALSE if the specified animation group is now found or
	/// animation for the specified group has not been initiated and its internal storyboard is NULL.
	/// </returns> 
	/// <remarks>
	/// When a handler is set (enabled) Windows Animation API calls OnStoryboardStatusChanges and OnStoryboardUpdated virtual methods.
	/// A handler must be set after CAnimationController::Animate has been called for the specified animation group, because
	/// it creates encapsulated IUIAnimationStoryboard object.
	/// </remarks>
	/// <param name="nGroupID">Specifies Group ID.</param>
	/// <param name="bEnable">Specifies whether to set or release a handler.</param>
	virtual BOOL EnableStoryboardEventHandler(UINT32 nGroupID, BOOL bEnable = TRUE);

	/// <summary>
	/// Sets or releases a handler for timing events and handler for timing updates.
	/// </summary>
	/// <returns> 
	/// TRUE if handlers were successfully set or released; FALSE if this method is called for a second time without
	/// releasing the handlers first, or if any other error occurs.
	/// </returns> 
	/// <remarks>
	/// When the handlers are set (enabled) Windows Animation API calls OnAnimationTimerPreUpdate, OnAnimationTimerPostUpdate,
	/// OnRenderingTooSlow methods.
	/// You need to enable animation timers to allow Windows Animation API update storyboards. Otherwise you'll need to
	/// call CAnimationController::UpdateAnimationManager in order to direct the animation manager to update the values 
	/// of all animation variables.
	/// </remarks>
	/// <param name="bEnable">Specifies whether to set or release the handlers.</param>
	/// <param name="idleBehavior">Specifies idle behavior for timer update handler.</param>
	virtual BOOL EnableAnimationTimerEventHandler(BOOL bEnable = TRUE, UI_ANIMATION_IDLE_BEHAVIOR idleBehavior = UI_ANIMATION_IDLE_BEHAVIOR_DISABLE);

	/// <summary>
	/// Directs the animation manager to update the values of all animation variables.
	/// </summary>
	/// <remarks>
	/// Calling this method advances the animation manager to current time, changing statuses of storyboards as necessary 
	/// and updating any animation variables to appropriate interpolated values. Internally this method calls
	/// IUIAnimationTimer::GetTime(timeNow) and IUIAnimationManager::Update(timeNow). Override this method in a derived
	/// class to customize this behavior.
	/// </remarks>
	virtual void UpdateAnimationManager();

	/// <summary>
	/// Tells whether at least one group is playing animation.
	/// </summary>
	/// <returns> 
	/// TRUE if there is an animation in progress for this animation controller; otherwise FALSE.
	/// </returns> 
	/// <remarks>
	/// Checks status of animation manager and returns TRUE if the status is UI_ANIMATION_MANAGER_BUSY.
	/// </remarks>
	virtual BOOL IsAnimationInProgress();

	/// <summary>
	/// Establishes a relationship between animation controller and a window.
	/// </summary>
	/// <remarks>
	/// If a related CWnd object is set, the animation controller can automatically update it (send WM_PAINT message) when 
	/// the status of animation manager has changed or timer post update event has occurred.
	/// </remarks>
	/// <param name="pWnd">A pointer to window object to set.</param>
	void SetRelatedWnd(CWnd* pWnd)
	{
		m_pRelatedWnd = pWnd;
	}

	/// <summary>
	/// Adds an animation object to a group that belongs to the animation controller.
	/// </summary>
	/// <returns> 
	/// A pointer to existing or new animation group where pObject has been added if function succeeds; NULL if 
	/// pObject has already been added to a group that belongs to another animation controller.
	/// </returns> 
	/// <remarks>
	/// Call this method to add an animation object to the animation controller. An object will be added to a group
	/// according to object's GroupID (see CAnimationBaseObject::SetID). The animation controller will create a new
	/// group if it's the first object being added with the specified GroupID. An animation object can be added to
	/// one animation controller only. If you need to add an object to another controller, call RemoveAnimationObject first.
	/// If you call SetID with new GroupID for an object that has been already added to a group, the object will be removed
	/// from the old group and added to another group with specified ID.
	/// </remarks>
	/// <param name="pObject">A pointer to an animation object.</param>
	CAnimationGroup* AddAnimationObject(CAnimationBaseObject* pObject);

	/// <summary>
	/// Remove an animation object from animation controller.
	/// </summary>
	/// <remarks>
	/// Removes an animation object from animation controller and animation group. Call this function if
	/// a particular object should not be animated anymore, or if you need to move the object to another animation controller.
	/// In the last case bNoDelete must be TRUE.
	/// </remarks>
	/// <param name="pObject">A pointer to an animation object.</param>
	/// <param name="bNoDelete">If this parameter is TRUE the object will not be deleted upon remove.</param>
	void RemoveAnimationObject(CAnimationBaseObject* pObject, BOOL bNoDelete = FALSE);

	/// <summary>
	/// Removes an animation group with specified ID from animation controller.
	/// </summary>
	/// <remarks>
	/// This method removes an animation group from the internal list of groups and deletes it, therefore if you stored
	/// a pointer to that animation group, it must be invalidated. If CAnimationGroup::m_bAutodestroyAnimationObjects is TRUE,
	/// all animation objects that belong to that group will be deleted; otherwise their references to parent animation
	/// controller will be set to NULL and they can be added to another controller.
	/// </remarks>
	/// <param name="nGroupID">Specifies animation group ID.</param>
	void RemoveAnimationGroup(UINT32 nGroupID);

	/// <summary>
	/// Removes all animation groups from animation controller.
	/// </summary>
	/// <remarks>
	/// All groups will be deleted, their pointer, if stored at the application level, must be invalidated.
	/// If CAnimationGroup::m_bAutodestroyAnimationObjects for a group being deleted is TRUE,
	/// all animation objects that belong to that group will be deleted; otherwise their references to parent animation
	/// controller will be set to NULL and they can be added to another controller.
	/// </remarks>
	void RemoveAllAnimationGroups();

	/// <summary>
	/// Removes transitions from animation objects that belong to the specified group.
	/// </summary>
	/// <remarks>
	/// The group loops over its animation objects and calls ClearTransitions(FALSE) for each animation object.
	/// This method is called by the framework after animation has been scheduled.
	/// </remarks>
	/// <param name="nGroupID">Specifies Group ID.</param>
	void RemoveTransitions(UINT32 nGroupID);

	/// <summary>
	/// Creates a keyframe that depends on transition and adds it to the specified group.
	/// </summary>
	/// <returns> 
	/// A pointer to newly created keyframe if the function succeeds.
	/// </returns> 
	/// <remarks>
	/// You can store the returned pointer and base other keyframes on the newly created keyframe (see the second overload).
	/// It's possible to begin transitions at keyframes - see CBaseTransition::SetKeyframes.
	/// You don't need to delete keyframes created in this way, because they are deleted automatically by animation groups.
	/// Be careful when creating keyframes based on other keyframes and transitions and avoid circular references. 
	/// </remarks>
	/// <param name="nGroupID">Specifies Group ID for which keyframe is created.</param>
	/// <param name="pTransition">A pointer to transition. Keyframe will be inserted to storyboard after this transition.</param>
	CKeyFrame* CreateKeyframe(UINT32 nGroupID, CBaseTransition* pTransition);

	/// <summary>
	/// Creates a keyframe that depends on other keyframe with optional offset in seconds and adds it to the specified group.
	/// </summary>
	/// <returns> 
	/// A pointer to newly created keyframe if the function succeeds.
	/// </returns> 
	/// <remarks>
	/// You can store the returned pointer and base other keyframes on the newly created keyframe (see the second overload).
	/// It's possible to begin transitions at keyframes - see CBaseTransition::SetKeyframes.
	/// You don't need to delete keyframes created in this way, because they are deleted automatically by animation groups.
	/// Be careful when creating keyframes based on other keyframes and transitions and avoid circular references. 
	/// </remarks>
	/// <param name="nGroupID">Specifies Group ID for which keyframe is created.</param>
	/// <param name="pKeyframe">A  pointer to base keyframe for this keyframe.</param>
	/// <param name="offset">Offset in seconds from the base keyframe specified by pKeyframe.</param>
	CKeyFrame* CreateKeyframe(UINT32 nGroupID, CBaseKeyFrame* pKeyframe, UI_ANIMATION_SECONDS offset = 0.0);

	/// <summary>
	/// Adds a keyframe to group.
	/// </summary>
	/// <returns> 
	/// TRUE if the function succeeds; otherwise FALSE.
	/// </returns> 
	/// <remarks>
	/// Usually you don't need to call this method, use CAnimationController::CreateKeyframe instead, which creates 
	/// and adds the created keyframe to a group automatically.
	/// </remarks>
	/// <param name="nGroupID">Specifies Group ID.</param>
	/// <param name="pKeyframe">A pointer to a keyframe.</param>
	BOOL AddKeyframeToGroup(UINT32 nGroupID, CBaseKeyFrame* pKeyframe);

	/// <summary>
	/// Finds an animation group by its Group ID.
	/// </summary>
	/// <returns> 
	/// A pointer to animation group or NULL if the group with specified ID is not found.
	/// </returns> 
	/// <remarks>
	/// Use this method to find an animation group at runtime. A group is created and added to the internal list of animation groups
	/// when a first animation object with particular GroupID is being added to animation controller.
	/// </remarks>
	/// <param name="nGroupID">Specifies a GroupID.</param>
	CAnimationGroup* FindAnimationGroup(UINT32 nGroupID);

	/// <summary>
	/// Finds an animation group by its storyboard.
	/// </summary>
	/// <returns> 
	/// A pointer to animation group if succeeds, or NULL if no group plays the specified storyboard.
	/// </returns> 
	/// <remarks>
	/// This method is usually called from event handlers to find a group by pointer to storyboard that comes as a parameter to an event handler.
	/// </remarks>
	/// <param name="pStoryboard">A pointer to a storyboard.</param>
	CAnimationGroup* FindAnimationGroup(IUIAnimationStoryboard* pStoryboard);

	/// <summary>
	/// Finds animation object containing a specified animation variable.
	/// </summary>
	/// <returns> 
	/// TRUE if object was found; otherwise FALSE.
	/// </returns> 
	/// <remarks>
	/// Called from event handlers when it's required to find an animation object from incoming animation variable.
	/// </remarks>
	/// <param name="pVariable">A pointer to animation variable.</param>
	/// <param name="ppObject">Output. Contains a pointer to animation object or NULL. </param>
	/// <param name="ppGroup">Output. Contains a pointer to animation group that holds the animation object, or NULL.</param>
	BOOL FindAnimationObject(IUIAnimationVariable* pVariable, CAnimationBaseObject** ppObject, CAnimationGroup** ppGroup);

	/// <summary>
	/// Prepares a group to run animation and optionally schedules it.
	/// </summary>
	/// <returns> 
	/// TRUE if animation was successfully scheduled and run.
	/// </returns> 
	/// <remarks>
	/// This method does the actual work creating storyboard, adding animation variables, applying transitions and setting keyframes.
	/// It's possible to delay scheduling if you set bScheduleNow to FALSE. In this case the specified group 
	/// will hold a storyboard that has been set up for animation. At that point you can setup events for the storyboard and
	/// animation variables. When you actually need to run the animation call CAnimationController::ScheduleGroup.
	/// </remarks>
	/// <param name="nGroupID">Specifies GroupID.</param>
	/// <param name="bScheduleNow">Specifies whether to run animation right away.</param>
	BOOL AnimateGroup(UINT32 nGroupID, BOOL bScheduleNow = TRUE);

	/// <summary>
	/// Schedules an animation. 
	/// </summary>
	/// <returns> 
	/// TRUE if animation was scheduled successfully. FALSE if storyboard has not been created, or other error occurs.
	/// </returns> 
	/// <remarks>
	/// You must call AnimateGroup with parameter bScheduleNow set to FALSE prior ScheduleGroup. You can specify the 
	/// desired animation time obtained from IUIAnimationTimer::GetTime. If the time parameter is 0.0, the animation is scheduled for the 
	/// current time.
	/// </remarks>
	/// <param name="nGroupID">Specifies animation Group ID to schedule.</param>
	/// <param name="time">Specifies time to schedule.</param>
	BOOL ScheduleGroup(UINT32 nGroupID, UI_ANIMATION_SECONDS time = 0.0);

	/// <summary>
	/// Called by the framework to clean up the group when animation has been scheduled.
	/// </summary>
	/// <remarks>
	/// This method removes all transitions and keyframes from the specified group, because they are not relevant
	/// after an animation has been scheduled.
	/// </remarks>
	/// <param name="nGroupID">Specifies GroupID.</param>
	void CleanUpGroup(UINT32 nGroupID);

	/// <summary>
	/// Called by the framework right before the animation is scheduled.
	/// </summary>
	/// <remarks>
	/// This call is routed to related CWnd and can be overridden in a derived class to perform any
	/// additional actions before the animation starts for the specified group.
	/// </remarks>
	/// <param name="pGroup">A pointer to an animation group whose animation is about to start.</param>
	virtual void OnBeforeAnimationStart(CAnimationGroup* pGroup);

	/// <summary>
	/// Called by the framework in response to StatusChanged event from animation manager.
	/// </summary>
	/// <remarks>
	/// This method is called if you enable animation manager events with EnableAnimationManagerEvent.
	/// It can be overridden in a derived class to take application-specific actions. The default implementation 
	/// updates a related window if it has been set with SetRelatedWnd.
	/// </remarks>
	/// <param name="newStatus">New animation manager status.</param>
	/// <param name="previousStatus">Previous animation manager status.</param>
	virtual void OnAnimationManagerStatusChanged(UI_ANIMATION_MANAGER_STATUS newStatus, UI_ANIMATION_MANAGER_STATUS previousStatus);

	/// <summary>
	/// Called by the framework when value of animation variable has changed.
	/// </summary>
	/// <remarks>
	/// This method is called if you enable animation variable events with EnableValueChangedEvent called for a specific
	/// animation variable or animation object. 
	/// It can be overridden in a derived class to take application-specific actions.
	/// </remarks>
	/// <param name="pGroup">A pointer to an animation group that holds an animation object whose value has changed.</param>
	/// <param name="pObject">A pointer to an animation object that contains an animation variable whose value has changed.</param>
	/// <param name="variable">A pointer to an animation variable.</param>
	/// <param name="newValue">Specifies new value.</param>
	/// <param name="prevValue">Specifies previous value.</param>
	virtual void OnAnimationValueChanged(CAnimationGroup* pGroup, CAnimationBaseObject* pObject, IUIAnimationVariable* variable, DOUBLE newValue, DOUBLE prevValue);

	/// <summary>
	/// Called by the framework when integer value of animation variable has changed.
	/// </summary>
	/// <remarks>
	/// This method is called if you enable animation variable events with EnableIntegerValueChangedEvent called for a specific
	/// animation variable or animation object. 
	/// It can be overridden in a derived class to take application-specific actions.
	/// </remarks>
	/// <param name="pGroup">A pointer to an animation group that holds an animation object whose value has changed.</param>
	/// <param name="pObject">A pointer to an animation object that contains an animation variable whose value has changed.</param>
	/// <param name="variable">A pointer to an animation variable.</param>
	/// <param name="newValue">Specifies new value.</param>
	/// <param name="prevValue">Specifies previous value.</param>
	virtual void OnAnimationIntegerValueChanged(CAnimationGroup* pGroup, CAnimationBaseObject* pObject, IUIAnimationVariable* variable, INT32 newValue, INT32 prevValue);

	/// <summary>
	/// Called by the framework when storyboard status has changed.
	/// </summary>
	/// <remarks>
	/// This method is called if you enable storyboard events using CAnimationController::EnableStoryboardEventHandler.
	/// It can be overridden in a derived class to take application-specific actions.
	/// </remarks>
	/// <param name="pGroup">A pointer to an animation group that owns the storyboard whose status has changed.</param>
	/// <param name="newStatus">Specifies the new status.</param>
	/// <param name="previousStatus">Specifies the previous status.</param>
	virtual void OnStoryboardStatusChanged(CAnimationGroup* pGroup, UI_ANIMATION_STORYBOARD_STATUS newStatus, UI_ANIMATION_STORYBOARD_STATUS previousStatus);

	/// <summary>
	/// Called by the framework when storyboard has been updated.
	/// </summary>
	/// <remarks>
	/// This method is called if you enable storyboard events using CAnimationController::EnableStoryboardEventHandler.
	/// It can be overridden in a derived class to take application-specific actions.
	/// </remarks>
	/// <param name="pGroup">A pointer to a group that owns the storyboard.</param>
	virtual void OnStoryboardUpdated(CAnimationGroup* pGroup);

	/// <summary>
	/// Called by the framework to resolve scheduling conflicts.
	/// </summary>
	/// <returns> 
	/// Should return TRUE if storyboard owned by pGroupNew has priority. Should return FALSE if storyboard owned by
	/// pGroupScheduled has priority.
	/// </returns> 
	/// <remarks>
	/// This method is called if you enable priority comparison events using CAnimationController::EnablePriorityComparisonHandler
	/// and specify UI_ANIMATION_PHT_CANCEL.
	/// It can be overridden in a derived class to take application-specific actions.
	/// Read Windows Animation API documentation for more information about Conflict Management (http://msdn.microsoft.com/en-us/library/dd371759(VS.85).aspx).
	/// </remarks>
	/// <param name="pGroupScheduled">The group that owns the currently scheduled storyboard.</param>
	/// <param name="pGroupNew">The group that owns the new storyboard that is in scheduling conflict with the scheduled storyboard owned by pGroupScheduled.</param>
	/// <param name="priorityEffect">The potential effect on pGroupNew if pGroupScheduled has a higher priority.</param>
	virtual BOOL OnHasPriorityCancel(CAnimationGroup* pGroupScheduled, CAnimationGroup* pGroupNew, UI_ANIMATION_PRIORITY_EFFECT priorityEffect);

	/// <summary>
	/// Called by the framework to resolve scheduling conflicts.
	/// </summary>
	/// <returns> 
	/// Should return TRUE if storyboard owned by pGroupNew has priority. Should return FALSE if storyboard owned by
	/// pGroupScheduled has priority.
	/// </returns> 
	/// <remarks>
	/// This method is called if you enable priority comparison events using CAnimationController::EnablePriorityComparisonHandler
	/// and specify UI_ANIMATION_PHT_CONCLUDE.
	/// It can be overridden in a derived class to take application-specific actions.
	/// Read Windows Animation API documentation for more information about Conflict Management (http://msdn.microsoft.com/en-us/library/dd371759(VS.85).aspx).
	/// </remarks>
	/// <param name="pGroupScheduled">The group that owns the currently scheduled storyboard.</param>
	/// <param name="pGroupNew">The group that owns the new storyboard that is in scheduling conflict with the scheduled storyboard owned by pGroupScheduled.</param>
	/// <param name="priorityEffect">The potential effect on pGroupNew if pGroupScheduled has a higher priority.</param>
	virtual BOOL OnHasPriorityConclude(CAnimationGroup* pGroupScheduled, CAnimationGroup* pGroupNew, UI_ANIMATION_PRIORITY_EFFECT priorityEffect);

	/// <summary>
	/// Called by the framework to resolve scheduling conflicts.
	/// </summary>
	/// <returns> 
	/// Should return TRUE if storyboard owned by pGroupNew has priority. Should return FALSE if storyboard owned by
	/// pGroupScheduled has priority.
	/// </returns> 
	/// <remarks>
	/// This method is called if you enable priority comparison events using CAnimationController::EnablePriorityComparisonHandler
	/// and specify UI_ANIMATION_PHT_TRIM.
	/// It can be overridden in a derived class to take application-specific actions.
	/// Read Windows Animation API documentation for more information about Conflict Management (http://msdn.microsoft.com/en-us/library/dd371759(VS.85).aspx).
	/// </remarks>
	/// <param name="pGroupScheduled">The group that owns the currently scheduled storyboard.</param>
	/// <param name="pGroupNew">The group that owns the new storyboard that is in scheduling conflict with the scheduled storyboard owned by pGroupScheduled.</param>
	/// <param name="priorityEffect">The potential effect on pGroupNew if pGroupScheduled has a higher priority.</param>
	virtual BOOL OnHasPriorityTrim(CAnimationGroup* pGroupScheduled, CAnimationGroup* pGroupNew, UI_ANIMATION_PRIORITY_EFFECT priorityEffect);

	/// <summary>
	/// Called by the framework to resolve scheduling conflicts.
	/// </summary>
	/// <returns> 
	/// Should return TRUE if storyboard owned by pGroupNew has priority. Should return FALSE if storyboard owned by
	/// pGroupScheduled has priority.
	/// </returns> 
	/// <remarks>
	/// This method is called if you enable priority comparison events using CAnimationController::EnablePriorityComparisonHandler
	/// and specify UI_ANIMATION_PHT_COMPRESS.
	/// It can be overridden in a derived class to take application-specific actions.
	/// Read Windows Animation API documentation for more information about Conflict Management (http://msdn.microsoft.com/en-us/library/dd371759(VS.85).aspx).
	/// </remarks>
	/// <param name="pGroupScheduled">The group that owns the currently scheduled storyboard.</param>
	/// <param name="pGroupNew">The group that owns the new storyboard that is in scheduling conflict with the scheduled storyboard owned by pGroupScheduled.</param>
	/// <param name="priorityEffect">The potential effect on pGroupNew if pGroupScheduled has a higher priority.</param>
	virtual BOOL OnHasPriorityCompress(CAnimationGroup* pGroupScheduled, CAnimationGroup* pGroupNew, UI_ANIMATION_PRIORITY_EFFECT priorityEffect);

	/// <summary>
	/// Called by the framework before an animation update begins. 
	/// </summary>
	/// <remarks>
	/// This method is called if you enable timer event handlers using EnableAnimationTimerEventHandler.
	/// It can be overridden in a derived class to take application-specific actions.
	/// </remarks>
	virtual void OnAnimationTimerPreUpdate();

	/// <summary>
	/// Called by the framework after an animation update is finished. 
	/// </summary>
	/// <remarks>
	/// This method is called if you enable timer event handlers using EnableAnimationTimerEventHandler.
	/// It can be overridden in a derived class to take application-specific actions.
	/// </remarks>
	virtual void OnAnimationTimerPostUpdate();

	/// <summary>
	/// Called by the framework when the rendering frame rate for an animation falls below a minimum desirable frame rate.
	/// </summary>
	/// <remarks>
	/// This method is called if you enable timer event handlers using EnableAnimationTimerEventHandler.
	/// It can be overridden in a derived class to take application-specific actions.
	/// The minimum desirable frame rate is specified by calling IUIAnimationTimer::SetFrameRateThreshold. 
	/// </remarks>
	/// <param name="fps">The current frame rate in frames per second. </param>
	virtual void OnAnimationTimerRenderingTooSlow(UINT32 fps);

protected:
	
	/// <summary>
	/// Called by the framework when an animation for the specified group has just been scheduled.
	/// </summary>
	/// <remarks>
	/// The default implementation removes keyframes from the specified group and transitions from animation variables that 
	/// belong to the specified group. Can be overridden in a derived class to take any additional actions upon animation schedule.
	/// </remarks>
	/// <param name="pGroup">A pointer to an animation group, which has been scheduled.</param>
	virtual void OnAfterSchedule(CAnimationGroup* pGroup);

	/// <summary>
	/// A helper that cleans up the group.
	/// </summary>
	/// <remarks>
	/// This method removes all transitions and keyframes from the specified group.
	/// </remarks>
	/// <param name="pGroup">A pointer to animation group to clean.</param>
	void CleanUpGroup(CAnimationGroup* pGroup);
};

//----------------------------
// Event handler definitions
//----------------------------
/// <summary>
/// Implements a callback, which is called by Animation API when a status of animation manager changed.
/// </summary>
/// <remarks>
/// This event handler is created and passed to IUIAnimationManager::SetManagerEventHandler method, 
/// when you call CAnimationController::EnableAnimationManagerEvent.
/// </remarks>
class CAnimationManagerEventHandler : public CUIAnimationManagerEventHandlerBase<CAnimationManagerEventHandler>
{
	CAnimationController* m_pAnimationController;

public:
	/// <summary>
	/// Constructs a CAnimationManagerEventHandler object.
	/// </summary>
	CAnimationManagerEventHandler() : m_pAnimationController(NULL)
	{
	}

	/// <summary>
	/// Creates an instance of CAnimationManagerEventHandler object.
	/// </summary>
	/// <returns>
	/// If the method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.
	/// </returns>
	/// <param name="pAnimationController">A pointer to animation controller, which will receive events.</param>
	/// <param name="ppManagerEventHandler">Output. If the method succeeds it contains a pointer to COM object that will handle 
	/// status updates to an animation manager.</param>
	static COM_DECLSPEC_NOTHROW HRESULT CreateInstance(CAnimationController* pAnimationController, IUIAnimationManagerEventHandler **ppManagerEventHandler)
	{
		CAnimationManagerEventHandler *pManagerEventHandler = NULL;
		HRESULT hr = CUIAnimationCallbackBase::CreateInstance(ppManagerEventHandler, &pManagerEventHandler);
		if (SUCCEEDED(hr))
		{
			pManagerEventHandler->SetAnimationController (pAnimationController);
		}

		return hr;
	}

	/// <summary>
	/// Stores a pointer to animation controller to route events.
	/// </summary>
	/// <param name="pAnimationController">A pointer to animation controller, which will receive events.</param>
	void SetAnimationController(CAnimationController* pAnimationController)
	{
		m_pAnimationController = pAnimationController;
	}

	/// <summary>
	/// Called when a status of animation manager has changed.
	/// </summary>
	/// <returns>
	/// Current implementation always returns S_OK;
	/// </returns>
	/// <param name="newStatus">New status.</param>
	/// <param name="previousStatus">Previous status.</param>
	IFACEMETHOD(OnManagerStatusChanged)(UI_ANIMATION_MANAGER_STATUS newStatus,UI_ANIMATION_MANAGER_STATUS previousStatus)
	{
		if (m_pAnimationController != NULL)
		{
			m_pAnimationController->OnAnimationManagerStatusChanged(newStatus, previousStatus);
		}

		return S_OK;
	}
};

/// <summary>
/// Implements a call back, which is called by Animation API when the value of an animation variable changes.
/// </summary>
/// <remarks>
/// This event handler is created and passed to IUIAnimationVariable::SetVariableChangeHandler method, 
/// when you call CAnimationVariable::EnableValueChangedEvent or CAnimationBaseObject::EnableValueChangedEvent
/// (which enables this event for all animation variables encapsulated in an animation object).
/// </remarks>

class CAnimationVariableChangeHandler : public CUIAnimationVariableChangeHandlerBase<CAnimationVariableChangeHandler>
{
	CAnimationController* m_pAnimationController;

public:
	/// <summary>
	/// Constructs a CAnimationVariableChangeHandler object.
	/// </summary>
	CAnimationVariableChangeHandler() : m_pAnimationController(NULL)
	{
	}

	/// <summary>
	/// Creates an instance of CAnimationVariableChangeHandler object.
	/// </summary>
	/// <returns>
	/// If the method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.
	/// </returns>
	/// <param name="pAnimationController">A pointer to animation controller, which will receive events.</param>
	/// <param name="ppManagerEventHandler">Output. If the method succeeds it contains a pointer to COM object that will handle 
	/// variable change events.</param>
	static COM_DECLSPEC_NOTHROW HRESULT CreateInstance(CAnimationController* pAnimationController, IUIAnimationVariableChangeHandler **ppHandler)
	{
		CAnimationVariableChangeHandler *pHandler = NULL;
		HRESULT hr = CUIAnimationCallbackBase::CreateInstance(ppHandler, &pHandler);
		if (SUCCEEDED(hr))
		{
			pHandler->SetAnimationController (pAnimationController);
		}

		return hr;
	}

	/// <summary>
	/// Stores a pointer to animation controller to route events.
	/// </summary>
	/// <param name="pAnimationController">A pointer to animation controller, which will receive events.</param>
	void SetAnimationController(CAnimationController* pAnimationController)
	{
		m_pAnimationController = pAnimationController;
	}

	/// <summary>
	/// Called when a value of an animation variable has changed.
	/// </summary>
	/// <returns>
	/// If the method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.
	/// </returns>
	/// <param name="storyboard">The storyboard that is animating the variable.</param>
	/// <param name="variable">The animation variable that was updated.</param>
	/// <param name="newValue">The new value.</param>
	/// <param name="previousValue">The previous value.</param>
	IFACEMETHOD(OnValueChanged)
    (
        __in IUIAnimationStoryboard *storyboard,
        __in IUIAnimationVariable *variable,
        __in DOUBLE newValue,
        __in DOUBLE previousValue
    ) 
	{
		if (m_pAnimationController == NULL)
		{
			TRACE("An instance of OnValueChanged event handler has not been initialized.\n");
			return E_FAIL;
		}

		if (storyboard == NULL && variable != NULL)
		{
			(void)variable->GetCurrentStoryboard(&storyboard);
		}

		CAnimationGroup* pGroup = NULL;
		CAnimationBaseObject* pObject = NULL;

		if (storyboard != NULL)
		{
			pGroup = m_pAnimationController->FindAnimationGroup(storyboard);
			if (pGroup == NULL)
			{
				TRACE("Got OnValueChanged event for a storyboard, which does not belong to any Animation Group.\n");
				return E_FAIL;
			}

			pObject = pGroup->FindAnimationObject(variable);

			if (pObject == NULL)
			{
				TRACE("Got OnValueChanged event from an animation variable, which does not belong to any Animation Group.\n");
				return E_FAIL;
			}
		}
		else
		{
			m_pAnimationController->FindAnimationObject(variable, &pObject, &pGroup);
		}

		m_pAnimationController->OnAnimationValueChanged(pGroup, pObject, variable, newValue, previousValue);
		return S_OK;
	}
};

/// <summary>
/// Implements a call back, which is called by Animation API when the value of an animation variable changes.
/// </summary>
/// <remarks>
/// This event handler is created and passed to IUIAnimationVariable::SetVariableIntegerChangeHandler method, 
/// when you call CAnimationVariable::EnableIntegerValueChangedEvent or CAnimationBaseObject::EnableIntegerValueChangedEvent
/// (which enables this event for all animation variables encapsulated in an animation object).
/// </remarks>
class CAnimationVariableIntegerChangeHandler : public CUIAnimationVariableIntegerChangeHandlerBase<CAnimationVariableIntegerChangeHandler>
{
	CAnimationController* m_pAnimationController;

public:
	/// <summary>
	/// Constructs a CAnimationVariableIntegerChangeHandler object.
	/// </summary>
	CAnimationVariableIntegerChangeHandler () : m_pAnimationController(NULL)
	{
	}

	/// <summary>
	/// Creates an instance of CAnimationVariableIntegerChangeHandler callback.
	/// </summary>
	/// <returns>
	/// If the method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.
	/// </returns>
	/// <param name="pAnimationController">A pointer to animation controller, which will receive events.</param>
	/// <param name="ppManagerEventHandler">Output. If the method succeeds it contains a pointer to COM object that will handle 
	/// variable integer change events.</param>
	static COM_DECLSPEC_NOTHROW HRESULT CreateInstance(CAnimationController* pAnimationController, IUIAnimationVariableIntegerChangeHandler **ppHandler)
	{
		CAnimationVariableIntegerChangeHandler *pHandler = NULL;
		HRESULT hr = CUIAnimationCallbackBase::CreateInstance(ppHandler, &pHandler);
		if (SUCCEEDED(hr))
		{
			pHandler->SetAnimationController (pAnimationController);
		}

		return hr;
	}

	/// <summary>
	/// Stores a pointer to animation controller to route events.
	/// </summary>
	/// <param name="pAnimationController">A pointer to animation controller, which will receive events.</param>
	void SetAnimationController(CAnimationController* pAnimationController)
	{
		m_pAnimationController = pAnimationController;
	}

	/// <summary>
	/// Called when a value of an animation variable has changed.
	/// </summary>
	/// <returns>
	/// S_OK if the method succeeds; otherwise E_FAIL.
	/// </returns>
	/// <param name="storyboard">The storyboard that is animating the variable.</param>
	/// <param name="variable">The animation variable that was updated.</param>
	/// <param name="newValue">The new rounded value.</param>
	/// <param name="previousValue">The previous rounded value.</param>
	IFACEMETHOD(OnIntegerValueChanged)
    (
        __in IUIAnimationStoryboard *storyboard,
        __in IUIAnimationVariable *variable,
        __in INT32 newValue,
        __in INT32 previousValue
    )
	{
		if (m_pAnimationController == NULL)
		{
			TRACE("An instance of OnIntegerValueChanged event handler has not been initialized.\n");
			return E_FAIL;
		}

		if (storyboard == NULL && variable != NULL)
		{
			(void)variable->GetCurrentStoryboard(&storyboard);
		}

		CAnimationGroup* pGroup = NULL;
		CAnimationBaseObject* pObject = NULL;

		if (storyboard != NULL)
		{
			pGroup = m_pAnimationController->FindAnimationGroup(storyboard);
			if (pGroup == NULL)
			{
				TRACE("Got OnIntegerValueChanged event for a storyboard, which does not belong to any Animation Group.\n");
				return E_FAIL;
			}

			pObject = pGroup->FindAnimationObject(variable);

			if (pObject == NULL)
			{
				TRACE("Got OnIntegerValueChanged event from an animation variable, which does not belong to any Animation Group.\n");
				return E_FAIL;
			}
		}
		else
		{
			m_pAnimationController->FindAnimationObject(variable, &pObject, &pGroup);
		}
		
		m_pAnimationController->OnAnimationIntegerValueChanged(pGroup, pObject, variable, newValue, previousValue);
		return S_OK;
	}
};

/// <summary>
/// Implements a callback, which is called by Animation API when storyboard's status is changed or storyboard is updated.
/// </summary>
/// <remarks>
/// This event handler is created and passed to IUIAnimationStoryboard::SetStoryboardEventHandler method, 
/// when you call CAnimationController::EnableStoryboardEventHandler.
/// </remarks>
class CAnimationStoryboardEventHandler : public CUIAnimationStoryboardEventHandlerBase<CAnimationStoryboardEventHandler>
{
	CAnimationController* m_pAnimationController;
public:
	/// <summary>
	/// Constructs a CAnimationStoryboardEventHandler object.
	/// </summary>
	CAnimationStoryboardEventHandler() : m_pAnimationController(NULL)
	{
	}

	/// <summary>
	/// Creates an instance of CAnimationStoryboardEventHandler callback.
	/// </summary>
	/// <returns>
	/// If the method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.
	/// </returns>
	/// <param name="pAnimationController">A pointer to animation controller, which will receive events.</param>
	/// <param name="ppManagerEventHandler">Output. If the method succeeds it contains a pointer to COM object that will handle 
	/// storyboard events.</param>
	static COM_DECLSPEC_NOTHROW HRESULT CreateInstance(CAnimationController* pAnimationController, IUIAnimationStoryboardEventHandler **ppHandler)
	{
		CAnimationStoryboardEventHandler* pHandler = NULL;
		HRESULT hr = CUIAnimationCallbackBase::CreateInstance(ppHandler, &pHandler);
		if (SUCCEEDED(hr))
		{
			pHandler->SetAnimationController (pAnimationController);
		}

		return hr;
	}

	/// <summary>
	/// Stores a pointer to animation controller to route events.
	/// </summary>
	/// <param name="pAnimationController">A pointer to animation controller, which will receive events.</param>
	void SetAnimationController(CAnimationController* pAnimationController)
	{
		m_pAnimationController = pAnimationController;
	}

	/// <summary>
	/// Handles OnStoryboardStatusChanged events, which occur when a storyboard's status changes
	/// </summary>
	/// <returns>
	/// S_OK if the method succeeds; otherwise E_FAIL.
	/// </returns>
	/// <param name="storyboard">A pointer to storyboard whose status has changed.</param>
	/// <param name="newStatus">Specifies new storyboard status.</param>
	/// <param name="previousStatus">Specifies previous storyboard status.</param>
    IFACEMETHOD(OnStoryboardStatusChanged)
    (
        __in IUIAnimationStoryboard *storyboard,                        // The storyboard that changed status
        __in UI_ANIMATION_STORYBOARD_STATUS newStatus,                  // The new status
        __in UI_ANIMATION_STORYBOARD_STATUS previousStatus              // The previous status 
    ) 
	{
		if (m_pAnimationController == NULL)
		{
			TRACE("An instance of OnStoryboardStatusChanged event handler has not been initialized.\n");
			return E_FAIL;
		}

		CAnimationGroup* pGroup = m_pAnimationController->FindAnimationGroup(storyboard);
		if (pGroup == NULL)
		{
			TRACE("Got an event from storyboard, which does not belong to any Animation Group.\n");
			return E_FAIL;
		}
		m_pAnimationController->OnStoryboardStatusChanged(pGroup, newStatus, previousStatus);
		return S_OK;
	}
    
	/// <summary>
    /// Handles OnStoryboardUpdated events, which occur when a storyboard is updated
	/// </summary>
	/// <returns>
	/// S_OK if the method succeeds; otherwise E_FAIL.
	/// </returns>
	/// <param name="storyboard">A pointer to storyboard, which was updated.</param>
    IFACEMETHOD(OnStoryboardUpdated)
    (
        __in IUIAnimationStoryboard *storyboard                         // The storyboard that was updated
    ) 
	{
		if (m_pAnimationController == NULL)
		{
			TRACE("An instance of OnStoryboardUpdated event handler has not been initialized.\n");
			return E_FAIL;
		}
		
		CAnimationGroup* pGroup = m_pAnimationController->FindAnimationGroup(storyboard);
		if (pGroup == NULL)
		{
			TRACE("Got an event from storyboard, which does not belong to any Animation Group.\n");
			return E_FAIL;
		}
		m_pAnimationController->OnStoryboardUpdated(pGroup);
		return S_OK;
	}
};

class PriorityComparisonMethodCancel
{
public:
	static BOOL Method(CAnimationController* pController, CAnimationGroup* pGroupScheduled, CAnimationGroup* pGroupNew, UI_ANIMATION_PRIORITY_EFFECT priorityEffect)
	{
		return pController->OnHasPriorityCancel(pGroupScheduled, pGroupNew, priorityEffect);
	}
};

class PriorityComparisonMethodConclude
{
public:
	static BOOL Method(CAnimationController* pController, CAnimationGroup* pGroupScheduled, CAnimationGroup* pGroupNew, UI_ANIMATION_PRIORITY_EFFECT priorityEffect)
	{
		return pController->OnHasPriorityConclude(pGroupScheduled, pGroupNew, priorityEffect);
	}
};

class PriorityComparisonMethodTrim
{
public:
	static BOOL Method(CAnimationController* pController, CAnimationGroup* pGroupScheduled, CAnimationGroup* pGroupNew, UI_ANIMATION_PRIORITY_EFFECT priorityEffect)
	{
		return pController->OnHasPriorityTrim(pGroupScheduled, pGroupNew, priorityEffect);
	}
};

class PriorityComparisonMethodCompress
{
public:
	static BOOL Method(CAnimationController* pController, CAnimationGroup* pGroupScheduled, CAnimationGroup* pGroupNew, UI_ANIMATION_PRIORITY_EFFECT priorityEffect)
	{
		return pController->OnHasPriorityCompress(pGroupScheduled, pGroupNew, priorityEffect);
	}
};

/// <summary>
/// Implements a call back, which is called by Animation API when it needs to resolve scheduling conflicts.
/// </summary>
/// <remarks>
/// This event handler is created and passed to one of IUIAnimationManager's Set methods that deal with priority comparisons, 
/// when you call CAnimationController::EnablePriorityComparisonHandler.
/// </remarks>
template <class PriorityComparisonMethod>
class CUIAnimationPriorityComparisonHandler : public CUIAnimationPriorityComparisonBase<CUIAnimationPriorityComparisonHandler<PriorityComparisonMethod>>
{
	CAnimationController* m_pAnimationController;
public:
	/// <summary>
	/// Creates an instance of CUIAnimationPriorityComparisonHandler callback.
	/// </summary>
	/// <returns>
	/// If the method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.
	/// </returns>
	/// <param name="pAnimationController">A pointer to animation controller, which will receive events.</param>
	/// <param name="ppManagerEventHandler">Output. If the method succeeds it contains a pointer to COM object that will handle 
	/// priority comparison events.</param>
	static COM_DECLSPEC_NOTHROW HRESULT CreateInstance(CAnimationController* pAnimationController, IUIAnimationPriorityComparison **ppHandler)
	{
		CUIAnimationPriorityComparisonHandler<PriorityComparisonMethod>* pHandler = NULL;
		HRESULT hr = CUIAnimationCallbackBase::CreateInstance(ppHandler, &pHandler);
		if (SUCCEEDED(hr))
		{
			pHandler->SetAnimationController (pAnimationController);
		}

		return hr;
	}

	/// <summary>
	/// Stores a pointer to animation controller to route events.
	/// </summary>
	/// <param name="pAnimationController">A pointer to animation controller, which will receive events.</param>
	void SetAnimationController(CAnimationController* pAnimationController)
	{
		m_pAnimationController = pAnimationController;
	}

	/// <summary>
	/// Determines the relative priority between a scheduled storyboard and a new storyboard.
	/// </summary>
	/// <returns>
	/// Should return S_OK if pStoryboardNew has priority; should return S_FALSE if pStoryboardScheduled has priority.
	/// </returns>
	/// <param name="pStoryboardScheduled">Currently scheduled storyboard.</param>
	/// <param name="pStoryboardNew">New storyboard that conflicts with scheduled storyboard.</param>
	/// <param name="priorityEffect">Potential effect on attempt to schedule storyboard if HasPriority returns S_FALSE.</param>
	IFACEMETHOD(HasPriority)
    (
        __in IUIAnimationStoryboard *pStoryboardScheduled,
        __in IUIAnimationStoryboard *pStoryboardNew,
        __in UI_ANIMATION_PRIORITY_EFFECT priorityEffect
    ) 
	{
		if (m_pAnimationController == NULL)
		{
			TRACE("An instance of HasPriority event handler has not been initialized.\n");
			return E_FAIL;
		}

		CAnimationGroup* pGroupScheduled = m_pAnimationController->FindAnimationGroup(pStoryboardScheduled);
		if (pGroupScheduled == NULL)
		{
			TRACE("Got a HasPriority event for a storyboard that does not belong to any group.\n");
			return E_FAIL;
		}

		CAnimationGroup* pGroupNew = m_pAnimationController->FindAnimationGroup(pStoryboardNew);
		if (pGroupNew == NULL)
		{
			TRACE("Got a HasPriority event for a storyboard that does not belong to any group.\n");
			return E_FAIL;
		}
		BOOL bResult = PriorityComparisonMethod::Method(m_pAnimationController, pGroupScheduled, pGroupNew, priorityEffect);
		return bResult ? S_OK : S_FALSE;
	}
};

/// <summary>
/// Implements a call back, which is called by Animation API when timing events occur.
/// </summary>
/// <remarks>
/// This event handler is created and passed to IUIAnimationTimer::SetTimerEventHandler when you call 
/// CAnimationController::EnableAnimationTimerEventHandler.
/// </remarks>
class CAnimationTimerEventHandler : public CUIAnimationTimerEventHandlerBase<CAnimationTimerEventHandler>
{
	CAnimationController* m_pAnimationController;
public:

	/// <summary>
	/// Creates an instance of CAnimationTimerEventHandler callback.
	/// </summary>
	/// <returns>
	/// If the method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.
	/// </returns>
	/// <param name="pAnimationController">A pointer to animation controller, which will receive events.</param>
	/// <param name="ppManagerEventHandler">Output. If the method succeeds it contains a pointer to COM object that will handle 
	/// animation timer events.</param>
	static COM_DECLSPEC_NOTHROW HRESULT CreateInstance(CAnimationController* pAnimationController, IUIAnimationTimerEventHandler **ppTimerEventHandler)
    {
        CAnimationTimerEventHandler* pHandler = NULL;
        HRESULT hr = CUIAnimationCallbackBase::CreateInstance(ppTimerEventHandler, &pHandler);

        if (SUCCEEDED(hr))
        {
            pHandler->SetAnimationController (pAnimationController);
        }
        
        return hr;
    }

	/// <summary>
	/// Stores a pointer to animation controller to route events.
	/// </summary>
	/// <param name="pAnimationController">A pointer to animation controller, which will receive events.</param>
	void SetAnimationController(CAnimationController* pAnimationController)
	{
		m_pAnimationController = pAnimationController;
	}

	/// <summary>
	/// Handles events that occur before an animation update begins. 
	/// </summary>
	/// <returns>
	/// S_OK if the method succeeds; otherwise E_FAIL.
	/// </returns>
	IFACEMETHOD(OnPreUpdate)()
    {
		if (m_pAnimationController == NULL)
		{
			TRACE("An instance of CAnimationTimerEventHandler event handler has not been initialized.\n");
			return E_FAIL;
		}

        m_pAnimationController->OnAnimationTimerPreUpdate();
        return S_OK;
    }

	/// <summary>
	/// Handles events that occur after an animation update is finished. 
	/// </summary>
	/// <returns>
	/// S_OK if the method succeeds; otherwise E_FAIL.
	/// </returns>
    IFACEMETHOD(OnPostUpdate)()
    {
		if (m_pAnimationController == NULL)
		{
			TRACE("An instance of CAnimationTimerEventHandler event handler has not been initialized.\n");
			return E_FAIL;
		}
		
        m_pAnimationController->OnAnimationTimerPostUpdate();
        return S_OK;
    }

	/// <summary>
	/// Handles events that occur when the rendering frame rate for an animation falls below the minimum desirable frame rate. 
	/// </summary>
	/// <returns>
	/// S_OK if the method succeeds; otherwise E_FAIL.
	/// </returns>
    IFACEMETHOD(OnRenderingTooSlow)(UINT32 fps)
    {
		if (m_pAnimationController == NULL)
		{
			TRACE("An instance of CAnimationTimerEventHandler event handler has not been initialized.\n");
			return E_FAIL;
		}
		
        m_pAnimationController->OnAnimationTimerRenderingTooSlow(fps);
        return S_OK;
    }
};

//---------------------------------
// Transition class definitions
//---------------------------------
/// <summary>
/// Implements an accelerate-decelerate transition.
/// </summary>
/// <remarks>
/// During an accelerate-decelerate transition, the animation variable speeds up and then slows down over the 
/// duration of the transition, ending at a specified value. You can control how quickly the variable accelerates and 
/// decelerates independently, by specifying different acceleration and deceleration ratios.
/// When the initial velocity is zero, the acceleration ratio is the fraction of the duration that the variable will 
/// spend accelerating; likewise with the deceleration ratio. If the initial velocity is non-zero, it is the 
/// fraction of the time between the velocity reaching zero and the end of transition. The acceleration ratio and 
/// the deceleration ratio should sum to a maximum of 1.0. 
/// Because all transitions are cleared automatically, it's recommended to allocated them using operator new.
/// The encapsulated IUIAnimationTransition COM object is created by CAnimationController::AnimateGroup, until then
/// it's NULL. Changing member variables after creation of this COM object has no effect. 
/// </remarks>
class CAccelerateDecelerateTransition : public CBaseTransition
{
public:
	/// <summary>
	/// Constructs a transition object.
	/// </summary>
	/// <param name="duration">The duration of the transition. </param> 
	/// <param name="finalValue">The value of the animation variable at the end of the transition. </param> 
	/// <param name="accelerationRatio">The ratio of the time spent accelerating to the duration.</param> 
	/// <param name="decelerationRatio">The ratio of the time spent decelerating to the duration. </param> 
	CAccelerateDecelerateTransition(UI_ANIMATION_SECONDS duration, DOUBLE finalValue, DOUBLE accelerationRatio = 0.3,
		DOUBLE decelerationRatio = 0.3) : m_duration(duration), m_finalValue(finalValue), 
		m_accelerationRatio(accelerationRatio), m_decelerationRatio(decelerationRatio)
	{
		m_type = ACCELERATE_DECELERATE;
	}

public:
	/// <summary>
	/// The duration of the transition.
	/// </summary>
	UI_ANIMATION_SECONDS m_duration;

	/// <summary>
	/// The value of the animation variable at the end of the transition.
	/// </summary>
	DOUBLE m_finalValue;

	/// <summary>
	/// The ratio of the time spent accelerating to the duration.
	/// </summary>
	DOUBLE m_accelerationRatio;

	/// <summary>
	/// The ratio of the time spent decelerating to the duration.
	/// </summary>
	DOUBLE m_decelerationRatio;

	/// <summary>
	/// Calls the transition library to create encapsulated transition COM object.
	/// </summary>
	/// <returns>
	/// TRUE if transition is created successfully; otherwise FALSE.
	/// </returns>
	/// <param name="pLibrary">A pointer to transition library, which is responsible for creation of standard transitions.</param>
	/// <param name="pFactory">A pointer to transition factory, which is responsible for creation of custom transitions.</param>
	virtual BOOL Create(IUIAnimationTransitionLibrary* pLibrary, IUIAnimationTransitionFactory* /*pFactory*/)
	{
		Clear();

		if (pLibrary != NULL)
		{
			HRESULT hr = pLibrary->CreateAccelerateDecelerateTransition(m_duration, m_finalValue, m_accelerationRatio, 
				m_decelerationRatio, &m_transition);
			return SUCCEEDED(hr);
		}
		return FALSE;
	}
};

/// <summary>
/// Encapsulates a constant transition.
/// </summary>
/// <remarks>
/// During a constant transition, the value of an animation variable remains at the initial value over the duration 
/// of the transition.
/// Because all transitions are cleared automatically, it's recommended to allocated them using operator new.
/// The encapsulated IUIAnimationTransition COM object is created by CAnimationController::AnimateGroup, until then
/// it's NULL. Changing member variables after creation of this COM object has no effect. 
/// </remarks>
class CConstantTransition : public CBaseTransition
{
public: 
	/// <summary>
	/// Constructs a transition object and initializes its duration.
	/// </summary>
	/// <param name="duration">The duration of the transition. </param>
	CConstantTransition (UI_ANIMATION_SECONDS duration) : m_duration(duration)
	{
		m_type = CONSTANT;
	}

	/// <summary>
	/// The duration of the transition.
	/// </summary>
	UI_ANIMATION_SECONDS m_duration;

	/// <summary>
	/// Calls the transition library to create encapsulated transition COM object.
	/// </summary>
	/// <returns>
	/// TRUE if transition is created successfully; otherwise FALSE.
	/// </returns>
	/// <param name="pLibrary">A pointer to transition library, which is responsible for creation of standard transitions.</param>
	/// <param name="pFactory">A pointer to transition factory, which is responsible for creation of custom transitions.</param>
	virtual BOOL Create(IUIAnimationTransitionLibrary* pLibrary, IUIAnimationTransitionFactory* /*pFactory*/)
	{
		Clear();

		if (pLibrary != NULL)
		{
			HRESULT hr = pLibrary->CreateConstantTransition(m_duration, &m_transition);
			return SUCCEEDED(hr);
		}
		return FALSE;
	}
};

/// <summary>
/// Encapsulates a cubic transition.
/// </summary>
/// <remarks>
/// During a cubic transition, the value of the animation variable changes from its initial value to a specified 
/// final value over the duration of the transition, ending at a specified velocity. 
/// Because all transitions are cleared automatically, it's recommended to allocated them using operator new.
/// The encapsulated IUIAnimationTransition COM object is created by CAnimationController::AnimateGroup, until then
/// it's NULL. Changing member variables after creation of this COM object has no effect. 
/// </remarks>
class CCubicTransition : public CBaseTransition
{
public:
	/// <summary>
	/// Constructs a transition object and initializes its parameters.
	/// </summary>
	/// <param name="duration">The duration of the transition.</param>
	/// <param name="finalValue">The value of the animation variable at the end of the transition.</param>
	/// <param name="finalVelocity">The velocity of the variable at the end of the transition.</param>
	CCubicTransition(UI_ANIMATION_SECONDS duration, DOUBLE finalValue, DOUBLE finalVelocity) : m_duration(duration),
		m_dblFinalValue(finalValue), m_dblFinalVelocity(finalVelocity)
	{
		m_type = CUBIC;
	}

	/// <summary>
	/// The duration of the transition.
	/// </summary>
	UI_ANIMATION_SECONDS m_duration;

	/// <summary>
	/// The value of the animation variable at the end of the transition.
	/// </summary>
	DOUBLE m_dblFinalValue;

	/// <summary>
	/// The velocity of the variable at the end of the transition.
	/// </summary>
	DOUBLE m_dblFinalVelocity;

	/// <summary>
	/// Calls the transition library to create encapsulated transition COM object.
	/// </summary>
	/// <returns>
	/// TRUE if transition is created successfully; otherwise FALSE.
	/// </returns>
	/// <param name="pLibrary">A pointer to transition library, which is responsible for creation of standard transitions.</param>
	/// <param name="pFactory">A pointer to transition factory, which is responsible for creation of custom transitions.</param>
	virtual BOOL Create(IUIAnimationTransitionLibrary* pLibrary, IUIAnimationTransitionFactory* /*pFactory*/)
	{
		Clear();

		if (pLibrary != NULL)
		{
			HRESULT hr = pLibrary->CreateCubicTransition(m_duration, m_dblFinalValue, m_dblFinalVelocity, &m_transition);
			return SUCCEEDED(hr);
		}
		return FALSE;
	}
};

/// <summary>
/// Encapsulates a discrete transition.
/// </summary>
/// <remarks>
/// During a discrete transition, the animation variable remains at the initial value for a specified delay time, 
/// then switches instantaneously to a specified final value and remains at that value for a given hold time.
/// Because all transitions are cleared automatically, it's recommended to allocated them using operator new.
/// The encapsulated IUIAnimationTransition COM object is created by CAnimationController::AnimateGroup, until then
/// it's NULL. Changing member variables after creation of this COM object has no effect. 
/// </remarks>
class CDiscreteTransition : public CBaseTransition
{
public:
	/// <summary>
	/// Constructs a discrete transition object and initializes its parameters.
	/// </summary>
	/// <param name="delay">The amount of time by which to delay the instantaneous switch to the final value.</param>
	/// <param name="dblFinalValue">The value of the animation variable at the end of the transition. </param>
	/// <param name="hold">The amount of time by which to hold the variable at its final value.</param>
	CDiscreteTransition(UI_ANIMATION_SECONDS delay, DOUBLE dblFinalValue, UI_ANIMATION_SECONDS hold) : m_delay(delay),
		m_dblFinalValue(dblFinalValue), m_hold(hold)
	{
		m_type = DISCRETE;
	}

	/// <summary>
	/// The amount of time by which to delay the instantaneous switch to the final value.
	/// </summary>
	UI_ANIMATION_SECONDS m_delay;

	/// <summary>
	/// The value of the animation variable at the end of the transition. 
	/// </summary>
	DOUBLE m_dblFinalValue;

	/// <summary>
	/// The amount of time by which to hold the variable at its final value.
	/// </summary>
	UI_ANIMATION_SECONDS m_hold;

	/// <summary>
	/// Calls the transition library to create encapsulated transition COM object.
	/// </summary>
	/// <returns>
	/// TRUE if transition is created successfully; otherwise FALSE.
	/// </returns>
	/// <param name="pLibrary">A pointer to transition library, which is responsible for creation of standard transitions.</param>
	/// <param name="pFactory">A pointer to transition factory, which is responsible for creation of custom transitions.</param>
	virtual BOOL Create(IUIAnimationTransitionLibrary* pLibrary, IUIAnimationTransitionFactory* /*pFactory*/)
	{
		Clear();

		if (pLibrary != NULL)
		{
			HRESULT hr = pLibrary->CreateDiscreteTransition(m_delay, m_dblFinalValue, m_hold, &m_transition);
			return SUCCEEDED(hr);
		}
		return FALSE;
	}
};

/// <summary>
/// Encapsulates an instantaneous transition.
/// </summary>
/// <remarks>
/// During an instantaneous transition, the value of the animation variable changes instantly from its current 
/// value to a specified final value. The duration of this transition is always zero.
/// Because all transitions are cleared automatically, it's recommended to allocated them using operator new.
/// The encapsulated IUIAnimationTransition COM object is created by CAnimationController::AnimateGroup, until then
/// it's NULL. Changing member variables after creation of this COM object has no effect. 
/// </remarks>
class CInstantaneousTransition : public CBaseTransition
{
public:
	/// <summary>
	/// Constructs a transition object and initializes its final value. 
	/// </summary>
	/// <param name="dblFinalValue">The value of the animation variable at the end of the transition.</param>
	CInstantaneousTransition(DOUBLE dblFinalValue) : m_dblFinalValue(dblFinalValue)
	{
		m_type = INSTANTENEOUS;
	}

	/// <summary>
	/// The value of the animation variable at the end of the transition. 
	/// </summary>
	DOUBLE m_dblFinalValue;

	/// <summary>
	/// Calls the transition library to create encapsulated transition COM object.
	/// </summary>
	/// <returns>
	/// TRUE if transition is created successfully; otherwise FALSE.
	/// </returns>
	/// <param name="pLibrary">A pointer to transition library, which is responsible for creation of standard transitions.</param>
	/// <param name="pFactory">A pointer to transition factory, which is responsible for creation of custom transitions.</param>
	virtual BOOL Create(IUIAnimationTransitionLibrary* pLibrary, IUIAnimationTransitionFactory* /*pFactory*/)
	{
		Clear();

		if (pLibrary != NULL)
		{
			HRESULT hr = pLibrary->CreateInstantaneousTransition(m_dblFinalValue, &m_transition);
			return SUCCEEDED(hr);
		}
		return FALSE;
	}
};

/// <summary>
/// Encapsulates a linear transition.
/// </summary>
/// <remarks>
/// During a linear transition, the value of the animation variable transitions linearly from its initial value to a specified final value.
/// Because all transitions are cleared automatically, it's recommended to allocated them using operator new.
/// The encapsulated IUIAnimationTransition COM object is created by CAnimationController::AnimateGroup, until then
/// it's NULL. Changing member variables after creation of this COM object has no effect. 
/// </remarks>
class CLinearTransition : public CBaseTransition
{
public:
	/// <summary>
	/// Constructs a linear transition object and initializes it with duration and final value.
	/// </summary>
	/// <param name="duration">The duration of the transition.</param>
	/// <param name="dblFinalValue">The value of the animation variable at the end of the transition.</param>
	CLinearTransition(UI_ANIMATION_SECONDS duration, DOUBLE dblFinalValue) : m_duration(duration), m_dblFinalValue(dblFinalValue)
	{
		m_type = LINEAR;
	}

	/// <summary>
	/// The duration of the transition.
	/// </summary>
	UI_ANIMATION_SECONDS m_duration; 

	/// <summary>
	/// The value of the animation variable at the end of the transition.
	/// </summary>
	DOUBLE m_dblFinalValue;

	/// <summary>
	/// Calls the transition library to create encapsulated transition COM object.
	/// </summary>
	/// <returns>
	/// TRUE if transition is created successfully; otherwise FALSE.
	/// </returns>
	/// <param name="pLibrary">A pointer to transition library, which is responsible for creation of standard transitions.</param>
	/// <param name="pFactory">A pointer to transition factory, which is responsible for creation of custom transitions.</param>
	virtual BOOL Create(IUIAnimationTransitionLibrary* pLibrary, IUIAnimationTransitionFactory* /*pFactory*/)
	{
		Clear();

		if (pLibrary != NULL)
		{
			HRESULT hr = pLibrary->CreateLinearTransition(m_duration, m_dblFinalValue, &m_transition);
			return SUCCEEDED(hr);
		}
		return FALSE;
	}
};

/// <summary>
/// Encapsulates a linear-speed transition.
/// </summary>
/// <remarks>
/// During a linear-speed transition, the value of the animation variable changes at a specified rate. 
/// The duration of the transition is determined by the difference between the initial value and the specified final value.
/// Because all transitions are cleared automatically, it's recommended to allocated them using operator new.
/// The encapsulated IUIAnimationTransition COM object is created by CAnimationController::AnimateGroup, until then
/// it's NULL. Changing member variables after creation of this COM object has no effect. 
/// </remarks>
class CLinearTransitionFromSpeed : public CBaseTransition
{
public:
	/// <summary>
	/// Constructs a linear-speed transition object and initializes it with speed and final value.
	/// </summary>
	/// <param name="dblSpeed">The absolute value of the variable's velocity.</param>
	/// <param name="dblFinalValue">The value of the animation variable at the end of the transition.</param>
	CLinearTransitionFromSpeed(DOUBLE dblSpeed, DOUBLE dblFinalValue) : m_dblSpeed(dblSpeed), m_dblFinalValue(dblFinalValue)
	{
		m_type = LINEAR_FROM_SPEED;
	}

	/// <summary>
	/// The absolute value of the variable's velocity.
	/// </summary>
	DOUBLE m_dblSpeed;

	/// <summary>
	/// The value of the animation variable at the end of the transition.
	/// </summary>
	DOUBLE m_dblFinalValue;

	/// <summary>
	/// Calls the transition library to create encapsulated transition COM object.
	/// </summary>
	/// <returns>
	/// TRUE if transition is created successfully; otherwise FALSE.
	/// </returns>
	/// <param name="pLibrary">A pointer to transition library, which is responsible for creation of standard transitions.</param>
	/// <param name="pFactory">A pointer to transition factory, which is responsible for creation of custom transitions.</param>
	virtual BOOL Create(IUIAnimationTransitionLibrary* pLibrary, IUIAnimationTransitionFactory* /*pFactory*/)
	{
		Clear();

		if (pLibrary != NULL)
		{
			HRESULT hr = pLibrary->CreateLinearTransitionFromSpeed(m_dblSpeed, m_dblFinalValue, &m_transition);
			return SUCCEEDED(hr);
		}
		return FALSE;
	}
};

/// <summary>
/// Encapsulates a smooth-stop transition. 
/// </summary>
/// <remarks>
/// A smooth-stop transition slows down as it approaches a given final value, and reaches it with a velocity of zero. 
/// The duration of the transition is determined by the initial velocity, the difference between the initial and final values, 
/// and the specified maximum duration. If there is no solution consisting of a single parabolic arc, 
/// this method creates a cubic transition.
/// Because all transitions are cleared automatically, it's recommended to allocated them using operator new.
/// The encapsulated IUIAnimationTransition COM object is created by CAnimationController::AnimateGroup, until then
/// it's NULL. Changing member variables after creation of this COM object has no effect. 
/// </remarks>
class CSmoothStopTransition : public CBaseTransition
{
public:
	/// <summary>
	/// Constructs a smooth-stop transition and initializes its maximum duration and final value. 
	/// </summary>
	/// <param name="maximumDuration">The maximum duration of the transition.</param>
	/// <param name="dblFinalValue">The value of the animation variable at the end of the transition.</param>
	CSmoothStopTransition(UI_ANIMATION_SECONDS maximumDuration, DOUBLE dblFinalValue) : m_maximumDuration(maximumDuration),
		m_dblFinalValue(dblFinalValue)
	{
		m_type = SMOOTH_STOP;
	}

	/// <summary>
	/// The maximum duration of the transition.
	/// </summary>
	UI_ANIMATION_SECONDS m_maximumDuration;

	/// <summary>
	/// The value of the animation variable at the end of the transition. 
	/// </summary>
	DOUBLE m_dblFinalValue;

	/// <summary>
	/// Calls the transition library to create encapsulated transition COM object.
	/// </summary>
	/// <returns>
	/// TRUE if transition is created successfully; otherwise FALSE.
	/// </returns>
	/// <param name="pLibrary">A pointer to transition library, which is responsible for creation of standard transitions.</param>
	/// <param name="pFactory">A pointer to transition factory, which is responsible for creation of custom transitions.</param>
	virtual BOOL Create(IUIAnimationTransitionLibrary* pLibrary, IUIAnimationTransitionFactory* /*pFactory*/)
	{
		Clear();

		if (pLibrary != NULL)
		{
			HRESULT hr = pLibrary->CreateSmoothStopTransition(m_maximumDuration, m_dblFinalValue, &m_transition);
			return SUCCEEDED(hr);
		}
		return FALSE;
	}
};

/// <summary>
/// Encapsulates a parabolic-acceleration transition.
/// </summary>
/// <remarks>
/// During a parabolic-acceleration transition, the value of the animation variable changes from the initial value 
/// to the final value ending at a specified velocity. You can control how quickly the variable reaches the final 
/// value by specifying the rate of acceleration.
/// Because all transitions are cleared automatically, it's recommended to allocated them using operator new.
/// The encapsulated IUIAnimationTransition COM object is created by CAnimationController::AnimateGroup, until then
/// it's NULL. Changing member variables after creation of this COM object has no effect. 
/// </remarks>
class CParabolicTransitionFromAcceleration : public CBaseTransition
{
public:
	/// <summary>
	/// Constructs a parabolic-acceleration transition and initializes it with specified parameters.
	/// </summary>
	/// <param name="dblFinalValue">The value of the animation variable at the end of the transition. </param>
	/// <param name="dblFinalVelocity">The velocity of the animation variable at the end of the transition. </param>
	/// <param name="dblAcceleration">The acceleration of the animation variable during the transition.</param>
	CParabolicTransitionFromAcceleration(DOUBLE dblFinalValue, DOUBLE dblFinalVelocity, DOUBLE dblAcceleration) :
	  m_dblFinalValue(dblFinalValue), m_dblFinalVelocity(dblFinalVelocity), m_dblAcceleration(dblAcceleration)
	{
		m_type = PARABOLIC_FROM_ACCELERATION;
	}

	/// <summary>
	/// The value of the animation variable at the end of the transition. 
	/// </summary>
	DOUBLE m_dblFinalValue;

	/// <summary>
	/// The velocity of the animation variable at the end of the transition. 
	/// </summary>
	DOUBLE m_dblFinalVelocity;

	/// <summary>
	/// The acceleration of the animation variable during the transition.
	/// </summary>
	DOUBLE m_dblAcceleration;

	/// <summary>
	/// Calls the transition library to create encapsulated transition COM object.
	/// </summary>
	/// <returns>
	/// TRUE if transition is created successfully; otherwise FALSE.
	/// </returns>
	/// <param name="pLibrary">A pointer to transition library, which is responsible for creation of standard transitions.</param>
	/// <param name="pFactory">A pointer to transition factory, which is responsible for creation of custom transitions.</param>
	virtual BOOL Create(IUIAnimationTransitionLibrary* pLibrary, IUIAnimationTransitionFactory* /*pFactory*/)
	{
		Clear();

		if (pLibrary != NULL)
		{
			HRESULT hr = pLibrary->CreateParabolicTransitionFromAcceleration(m_dblFinalValue, m_dblFinalVelocity, m_dblAcceleration, &m_transition);
			return SUCCEEDED(hr);
		}
		return FALSE;
	}
};

/// <summary>
/// Encapsulates a reversal transition.
/// </summary>
/// <remarks>
/// A reversal transition smoothly changes direction over a given duration. 
/// The final value will be the same as the initial value and the final velocity will be the negative of the initial velocity.
/// Because all transitions are cleared automatically, it's recommended to allocated them using operator new.
/// The encapsulated IUIAnimationTransition COM object is created by CAnimationController::AnimateGroup, until then
/// it's NULL. Changing member variables after creation of this COM object has no effect. 
/// </remarks>
class CReversalTransition : public CBaseTransition
{
public:
	/// <summary>
	/// Constructs a reversal transition object and initializes its duration.
	/// </summary>
	/// <param name="duration">The duration of the transition. </param>
	CReversalTransition(UI_ANIMATION_SECONDS duration) : m_duration(duration)
	{
		m_type = REVERSAL;
	}

	/// <summary>
	/// The duration of the transition. 
	/// </summary>
	UI_ANIMATION_SECONDS m_duration;

	/// <summary>
	/// Calls the transition library to create encapsulated transition COM object.
	/// </summary>
	/// <returns>
	/// TRUE if transition is created successfully; otherwise FALSE.
	/// </returns>
	/// <param name="pLibrary">A pointer to transition library, which is responsible for creation of standard transitions.</param>
	/// <param name="pFactory">A pointer to transition factory, which is responsible for creation of custom transitions.</param>
	virtual BOOL Create(IUIAnimationTransitionLibrary* pLibrary, IUIAnimationTransitionFactory* /*pFactory*/)
	{
		Clear();

		if (pLibrary != NULL)
		{
			HRESULT hr = pLibrary->CreateReversalTransition(m_duration, &m_transition);
			return SUCCEEDED(hr);
		}
		return FALSE;
	}
};

/// <summary>
/// Encapsulates a sinusoidal-range transition, with a given range of oscillation. 
/// </summary>
/// <remarks>
/// The value of the animation variable fluctuates between the specified minimum and maximum values over the entire 
/// duration of a sinusoidal-range transition. The slope parameter is used to disambiguate between the two possible 
/// sine waves specified by the other parameters.
/// Because all transitions are cleared automatically, it's recommended to allocated them using operator new.
/// The encapsulated IUIAnimationTransition COM object is created by CAnimationController::AnimateGroup, until then
/// it's NULL. Changing member variables after creation of this COM object has no effect. 
/// </remarks>
class CSinusoidalTransitionFromRange : public CBaseTransition
{
public:
	/// <summary>
	/// Constructs a transition object.
	/// </summary>
	/// <param name="duration">The duration of the transition.</param>
	/// <param name="dblMinimumValue">The value of the animation variable at a trough of the sinusoidal wave.</param>
	/// <param name="dblMaximumValue">The value of the animation variable at a peak of the sinusoidal wave.</param>
	/// <param name="period">The period of oscillation of the sinusoidal wave in seconds. </param>
	/// <param name="slope">The slope at the start of the transition. </param>
	CSinusoidalTransitionFromRange(UI_ANIMATION_SECONDS duration, DOUBLE dblMinimumValue, DOUBLE dblMaximumValue, 
		UI_ANIMATION_SECONDS period, UI_ANIMATION_SLOPE slope) : m_duration(duration), m_dblMinimumValue(dblMinimumValue),
		m_dblMaximumValue(dblMaximumValue), m_period(period), m_slope(slope)
	{
		m_type = SINUSOIDAL_FROM_RANGE;
	}

	/// <summary>
	/// The duration of the transition. 
	/// </summary>
	UI_ANIMATION_SECONDS m_duration; 
	/// <summary>
	/// The value of the animation variable at a trough of the sinusoidal wave.
	/// </summary>
	DOUBLE m_dblMinimumValue; 
	/// <summary>
	/// The value of the animation variable at a peak of the sinusoidal wave.
	/// </summary>
	DOUBLE m_dblMaximumValue; 
	/// <summary>
	/// The period of oscillation of the sinusoidal wave in seconds. 
	/// </summary>
	UI_ANIMATION_SECONDS m_period; 
	/// <summary>
	/// The slope at the start of the transition. 
	/// </summary>
	UI_ANIMATION_SLOPE m_slope;

	/// <summary>
	/// Calls the transition library to create encapsulated transition COM object.
	/// </summary>
	/// <returns>
	/// TRUE if transition is created successfully; otherwise FALSE.
	/// </returns>
	/// <param name="pLibrary">A pointer to transition library, which is responsible for creation of standard transitions.</param>
	/// <param name="pFactory">A pointer to transition factory, which is responsible for creation of custom transitions.</param>
	virtual BOOL Create(IUIAnimationTransitionLibrary* pLibrary, IUIAnimationTransitionFactory* /*pFactory*/)
	{
		Clear();

		if (pLibrary != NULL)
		{
			HRESULT hr = pLibrary->CreateSinusoidalTransitionFromRange(m_duration, m_dblMinimumValue, m_dblMaximumValue, 
				m_period, m_slope, &m_transition);
			return SUCCEEDED(hr);
		}
		return FALSE;
	}
};

/// <summary>
/// Encapsulates a sinusoidal-velocity transition, with an amplitude determined by the animation variable's initial velocity..
/// </summary>
/// <remarks>
/// The value of the animation variable oscillates around the initial value over the entire duration of a 
/// sinusoidal-range transition. The amplitude of the oscillation is determined by the animation variable's velocity 
/// when the transition begins. 
/// Because all transitions are cleared automatically, it's recommended to allocated them using operator new.
/// The encapsulated IUIAnimationTransition COM object is created by CAnimationController::AnimateGroup, until then
/// it's NULL. Changing member variables after creation of this COM object has no effect. 
/// </remarks>
class CSinusoidalTransitionFromVelocity : public CBaseTransition
{
public:
	/// <summary>
	/// Constructs a transition object.
	/// </summary>
	/// <param name="duration">The duration of the transition.</param>
	/// <param name="period">The period of oscillation of the sinusoidal wave in seconds. </param>
	CSinusoidalTransitionFromVelocity(UI_ANIMATION_SECONDS duration, UI_ANIMATION_SECONDS period) : m_duration(duration), m_period(period)
	{
		m_type = SINUSOIDAL_FROM_VELOCITY;
	}

	/// <summary>
	/// The duration of the transition.
	/// </summary>
	UI_ANIMATION_SECONDS m_duration; 
	/// <summary>
	/// The period of oscillation of the sinusoidal wave in seconds.
	/// </summary>
	UI_ANIMATION_SECONDS m_period; 

	/// <summary>
	/// Calls the transition library to create encapsulated transition COM object.
	/// </summary>
	/// <returns>
	/// TRUE if transition is created successfully; otherwise FALSE.
	/// </returns>
	/// <param name="pLibrary">A pointer to transition library, which is responsible for creation of standard transitions.</param>
	/// <param name="pFactory">A pointer to transition factory, which is responsible for creation of custom transitions.</param>
	virtual BOOL Create(IUIAnimationTransitionLibrary* pLibrary, IUIAnimationTransitionFactory* /*pFactory*/)
	{
		Clear();

		if (pLibrary != NULL)
		{
			HRESULT hr = pLibrary->CreateSinusoidalTransitionFromVelocity(m_duration, m_period, &m_transition);
			return SUCCEEDED(hr);
		}
		return FALSE;
	}
};

//---------------------------------
// Support for custom transitions
//---------------------------------
/// <summary>
/// Implements a basic interpolator.
/// </summary>
/// <remarks>
/// Derive a class from CCustomInterpolator and override all necessary methods in order to implement a custom
/// interpolation algorithm. A pointer to this class should be passed as a parameter to CCustomTransition. 
/// </remarks>
class CCustomInterpolator
{
protected:
	/// <summary>
	/// The duration of the transition.
	/// </summary>
	UI_ANIMATION_SECONDS	m_duration;

	/// <summary>
	/// The final value of a variable at the end of the transition.
	/// </summary>
	DOUBLE					m_finalValue;

	/// <summary>
	/// The value of the variable at the start of the transition.
	/// </summary>
	DOUBLE					m_initialValue;
	/// <summary>
	/// The velocity of the variable at the start of the transition.
	/// </summary>
	DOUBLE					m_initialVelocity;

	/// <summary>
	/// The interpolated value.
	/// </summary>
	DOUBLE					m_currentValue;
	/// <summary>
	/// The interpolated velocity.
	/// </summary>
	DOUBLE					m_currentVelocity;
public:
	/// <summary>
	/// Constructs a custom interpolator object and sets all values to default 0.
	/// </summary>
	/// <remarks>
	/// Use CCustomInterpolator::Init to initialize duration and final value later in the code.
	/// </remarks>
	CCustomInterpolator() : m_duration(0.), m_finalValue(0.), m_initialValue(0.), m_initialVelocity(0.), m_currentValue(0.),
		m_currentVelocity(0.)
	{
	}

	/// <summary>
	/// Constructs a custom interpolator object and initializes duration and velocity to specified values.
	/// </summary>
	/// <param name="duration">The duration of the transition.</param>
	/// <param name="finalValue"></param>
	CCustomInterpolator(UI_ANIMATION_SECONDS duration, DOUBLE finalValue) :
	  m_duration(duration), m_finalValue(finalValue), m_initialValue(0.), m_initialVelocity(0.), m_currentValue(0.), m_currentVelocity(0.)
	{
	}

	/// <summary>
	/// Initializes duration and final value.
	/// </summary>
	/// <param name="duration">The duration of the transition.</param>
	/// <param name="finalValue">The final value of a variable at the end of the transition.</param>
	void Init(UI_ANIMATION_SECONDS duration, DOUBLE finalValue)
	{
		m_duration = duration;
		m_finalValue = finalValue;
	}

	/// <summary>
	/// Sets the interpolator's initial value and velocity.
	/// </summary>
	/// <returns>
	/// The basic implementation always returns TRUE. Return FALSE from overridden implementation if you wish to fail the event. 
	/// </returns>
	/// <param name="initialValue">The value of the variable at the start of the transition.</param>
	/// <param name="initialVelocity">The velocity of the variable at the start of the transition.</param>
	virtual BOOL SetInitialValueAndVelocity(DOUBLE initialValue, DOUBLE initialVelocity)
	{
		m_initialValue = initialValue;
		m_initialVelocity = initialVelocity;
		m_currentValue = initialValue;
		m_currentVelocity = initialVelocity;
		return TRUE;
	}

	/// <summary>
    /// Sets the interpolator's duration.
	/// </summary>
	/// <returns>
	/// Basic implementation always returns TRUE. Return FALSE from overridden implementation if you wish to fail the event. 
	/// </returns>
	/// <param name="duration">The duration of the transition.</param>
	virtual BOOL SetDuration(UI_ANIMATION_SECONDS duration)
	{
		m_duration = duration;
		return TRUE;
	}

	/// <summary>
    /// Gets the interpolator's duration.
	/// </summary>
	/// <returns>
	/// Basic implementation always returns TRUE. Return FALSE from overridden implementation if you wish to fail the event. 
	/// </returns>
	/// <param name="duration">Output. The duration of the transition, in seconds.</param>
	virtual BOOL GetDuration(UI_ANIMATION_SECONDS *duration)
	{
		*duration = m_duration;
		return TRUE;
	}

	/// <summary>
    /// Gets the final value to which the interpolator leads.
	/// </summary>
	/// <returns>
	/// Basic implementation always returns TRUE. Return FALSE from overridden implementation if you wish to fail the event. 
	/// </returns>
	/// <param name="value">Output. The final value of a variable at the end of the transition.</param>
	virtual BOOL GetFinalValue(DOUBLE *value) 
	{
		*value = m_finalValue;
		return TRUE;
	}

	/// <summary>
    /// Interpolates the value at a given offset.
	/// </summary>
	/// <returns>
	/// Basic implementation always returns TRUE. Return FALSE from overridden implementation if you wish to fail the event. 
	/// </returns>
	/// <param name="offset">The offset from the start of the transition.
	/// The offset is always greater than or equal to zero and less than the duration of the transition. 
	/// This method is not called if the duration of the transition is zero.</param>
	/// <param name="value">Output. The interpolated value.</param>
	virtual BOOL InterpolateValue(UI_ANIMATION_SECONDS /*offset*/, DOUBLE *value) 
	{
		*value = m_currentValue;
		return TRUE;
	}

	/// <summary>
    /// Interpolates the velocity at a given offset
	/// </summary>
	/// <returns>
	/// Basic implementation always returns TRUE. Return FALSE from overridden implementation if you wish to fail the event. 
	/// </returns>
	/// <param name="offset">The offset from the start of the transition. 
	/// The offset is always greater than or equal to zero and less than or equal to the duration of the transition. 
	/// This method is not called if the duration of the transition is zero. </param>
	/// <param name="velocity">Output. The velocity of the variable at the offset.</param>
	virtual BOOL InterpolateVelocity(UI_ANIMATION_SECONDS /*offset*/, DOUBLE *velocity) 
	{
		*velocity = m_currentVelocity;
		return TRUE;
	}

	/// <summary>
    /// Gets the interpolator's dependencies.
	/// </summary>
	/// <returns>
	/// Basic implementation always returns TRUE. Return FALSE from overridden implementation if you wish to fail the event. 
	/// </returns>
	/// <param name="initialValueDependencies">Output. Aspects of the interpolator that depend on the initial value passed to SetInitialValueAndVelocity.</param>
	/// <param name="initialVelocityDependencies">Output. Aspects of the interpolator that depend on the initial velocity passed to SetInitialValueAndVelocity.</param>
	/// <param name="durationDependencies">Output. Aspects of the interpolator that depend on the duration passed to SetDuration.</param>
	virtual BOOL GetDependencies(UI_ANIMATION_DEPENDENCIES *initialValueDependencies, 
		UI_ANIMATION_DEPENDENCIES *initialVelocityDependencies, UI_ANIMATION_DEPENDENCIES *durationDependencies)
	{
		*initialValueDependencies = UI_ANIMATION_DEPENDENCY_NONE;
		*initialVelocityDependencies = UI_ANIMATION_DEPENDENCY_NONE;
		*durationDependencies = UI_ANIMATION_DEPENDENCY_NONE;
		return TRUE;
	}
};

/// <summary>
/// Implements a callback, which is called by Animation API when it needs to calculate a new value of animation variable.
/// </summary>
/// <remarks>
/// This handler is created and passed to IUIAnimationTransitionFactory::CreateTransition when a CCustomTransition
/// object is being created as a part of animation initialization process (started by CAnimationController::AnimateGroup).
/// Usually you don't need to use this class directly, it just routs all events to a CCustomInterpolator-derived class, whose
/// pointer is passed to constructor of CCustomTransition.
/// </remarks>
class CInterpolatorBase : public CUIAnimationInterpolatorBase<CInterpolatorBase>
{
	CCustomInterpolator* m_pInterpolator;
public:
	/// <summary>
	/// Constructs the CInterpolatorBase object.
	/// </summary>
	CInterpolatorBase() : m_pInterpolator(NULL)
	{
	}

	/// <summary>
	/// Stores  a pointer to custom interpolator, which will be handling events.
	/// </summary>
	/// <param name="pInterpolator">A pointer to custom interpolator.</param>
	void SetCustomInterpolator(CCustomInterpolator* pInterpolator)
	{
		m_pInterpolator = pInterpolator;
	}

	/// <summary>
	/// Creates an instance of CInterpolatorBase and stores a pointer to custom interpolator, which will be handling events.
	/// </summary>
	/// If the method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.
	/// <param name="pInterpolator">A pointer to custom interpolator.</param>
	/// <param name="ppHandler">Output. Contains a pointer to instance of CInterpolatorBase when the function returns.</param>
	static COM_DECLSPEC_NOTHROW HRESULT CreateInstance(CCustomInterpolator* pInterpolator, IUIAnimationInterpolator **ppHandler)
	{
		CInterpolatorBase* pHandler = NULL;
		HRESULT hr = CUIAnimationCallbackBase::CreateInstance(ppHandler, &pHandler);

		if (SUCCEEDED(hr) && pHandler != NULL)
		{
			pHandler->SetCustomInterpolator(pInterpolator);
		}

		return hr;
	}

	/// <summary>
	/// Sets the interpolator's initial value and velocity.
	/// </summary>
	/// <returns>
	/// If the method succeeds, it returns S_OK. It returns E_FAIL if CCustomInterpolator is not
	/// set, or custom implementation returns FALSE from the SetInitialValueAndVelocity method.
	/// </returns>
	/// <param name="initialValue">The value of the variable at the start of the transition.</param>
	/// <param name="initialVelocity">The velocity of the variable at the start of the transition.</param>
    IFACEMETHOD(SetInitialValueAndVelocity)(__in DOUBLE initialValue, __in DOUBLE initialVelocity) 
	{
		if (m_pInterpolator == NULL || !m_pInterpolator->SetInitialValueAndVelocity(initialValue, initialVelocity))
		{
			return E_FAIL;
		}
		return S_OK;
	}
    
	/// <summary>
    /// Sets the interpolator's duration
	/// </summary>
	/// <returns>
	/// If the method succeeds, it returns S_OK. It returns E_FAIL if CCustomInterpolator is not
	/// set, or custom implementation returns FALSE from the SetDuration method.
	/// </returns>
	/// <param name="duration">The duration of the transition.</param>
    IFACEMETHOD(SetDuration)(__in UI_ANIMATION_SECONDS duration)
	{
		if (m_pInterpolator == NULL || !m_pInterpolator->SetDuration(duration))
		{
			return E_FAIL;
		}
		return S_OK;
	}
    
	/// <summary>
    /// Gets the interpolator's duration.
	/// </summary>
	/// <returns>
	/// If the method succeeds, it returns S_OK. It returns E_FAIL if CCustomInterpolator is not
	/// set, or custom implementation returns FALSE from the GetDuration method.
	/// </returns>
	/// <param name="duration">Output. The duration of the transition, in seconds.</param>
    IFACEMETHOD(GetDuration)(__out UI_ANIMATION_SECONDS *duration) 
	{
		if (m_pInterpolator == NULL || !m_pInterpolator->GetDuration(duration))
		{
			return E_FAIL;
		}
		return S_OK;
	}
    
	/// <summary>
    /// Gets the final value to which the interpolator leads.
	/// </summary>
	/// <returns>
	/// If the method succeeds, it returns S_OK. It returns E_FAIL if CCustomInterpolator is not
	/// set, or custom implementation returns FALSE from the GetFinalValue method.
	/// </returns>
	/// <param name="value">Output. The final value of a variable at the end of the transition.</param>
    IFACEMETHOD(GetFinalValue)(__out DOUBLE *value) 
	{
		if (m_pInterpolator == NULL || !m_pInterpolator->GetFinalValue(value))
		{
			return E_FAIL;
		}
		return S_OK;
	}
    
	/// <summary>
    /// Interpolates the value at a given offset
	/// </summary>
	/// <returns>
	/// If the method succeeds, it returns S_OK. It returns E_FAIL if CCustomInterpolator is not
	/// set, or custom implementation returns FALSE from the InterpolateValue method.
	/// </returns>
	/// <param name="offset">The offset from the start of the transition.
	/// The offset is always greater than or equal to zero and less than the duration of the transition. 
	/// This method is not called if the duration of the transition is zero.</param>
	/// <param name="value">Output. The interpolated value.</param>
    IFACEMETHOD(InterpolateValue)(__in UI_ANIMATION_SECONDS offset, __out DOUBLE *value) 
	{
		if (m_pInterpolator == NULL || !m_pInterpolator->InterpolateValue(offset, value))
		{
			return E_FAIL;
		}
		return S_OK;
	}
    
	/// <summary>
    /// Interpolates the velocity at a given offset
	/// </summary>
	/// <returns>
	/// If the method succeeds, it returns S_OK. It returns E_FAIL if CCustomInterpolator is not
	/// set, or custom implementation returns FALSE from the InterpolateVelocity method.
	/// </returns>
	/// <param name="offset">The offset from the start of the transition. 
	/// The offset is always greater than or equal to zero and less than or equal to the duration of the transition. 
	/// This method is not called if the duration of the transition is zero. </param>
	/// <param name="velocity">Output. The velocity of the variable at the offset.</param>
    IFACEMETHOD(InterpolateVelocity)(__in UI_ANIMATION_SECONDS offset, __out DOUBLE *velocity) 
	{
		if (m_pInterpolator == NULL || !m_pInterpolator->InterpolateVelocity(offset, velocity))
		{
			return E_FAIL;
		}
		return S_OK;
	}
    
	/// <summary>
    /// Gets the interpolator's dependencies.
	/// </summary>
	/// <returns>
	/// If the method succeeds, it returns S_OK. It returns E_FAIL if CCustomInterpolator is not
	/// set, or custom implementation returns FALSE from the GetDependencies method.
	/// </returns>
	/// <param name="initialValueDependencies">Output. Aspects of the interpolator that depend on the initial value passed to SetInitialValueAndVelocity.</param>
	/// <param name="initialVelocityDependencies">Output. Aspects of the interpolator that depend on the initial velocity passed to SetInitialValueAndVelocity.</param>
	/// <param name="durationDependencies">Output. Aspects of the interpolator that depend on the duration passed to SetDuration.</param>
    IFACEMETHOD(GetDependencies)(__out UI_ANIMATION_DEPENDENCIES *initialValueDependencies, __out UI_ANIMATION_DEPENDENCIES *initialVelocityDependencies, 
        __out UI_ANIMATION_DEPENDENCIES *durationDependencies) 
	{
		if (m_pInterpolator == NULL || !m_pInterpolator->GetDependencies(initialValueDependencies, initialVelocityDependencies, durationDependencies))
		{
			return E_FAIL;
		}
		return S_OK;
	}
};

/// <summary>
/// Implements custom transition.
/// </summary>
/// <remarks>
/// The CCustomTransitions class allows developers to implement custom transitions. It's created and used 
/// as a standard transition, but its constructor accepts as parameter a pointer to a custom interpolator.
/// Perform the following steps to use custom transitions:
/// 1. Derive a class from CCustomInterpolator and implement at least InterpolateValue method.
/// 2. Ensure that the lifetime of custom interpolator object must be longer than duration of animation where it's used.
/// 3. Instantiate (using operator new) a CCustomTransition object and pass a pointer to custom interpolator in the constructor.
/// 4. Call CCustomTransition::SetInitialValue and CCustomTransition::SetInitialVelocity if these parameters are required for custom interpolation.
/// 5. Pass the pointer to custom transition to AddTransition method of animation object, whose value should be animated with the custom algorithm.
/// 6. When the value of animation object should change Windows Animation API will call InterpolateValue (and other relevant methods) in CCustomInterpolator. 
/// </remarks>
class CCustomTransition : public CBaseTransition
{
protected:
	/// <summary>
	/// Stores a pointer to a custom interpolator.
	/// </summary>
	CCustomInterpolator* 	m_pInterpolator;

	/// <summary>
	/// Specifies whether the initial value was specified with SetInitialValue.
	/// </summary>
	BOOL					m_bInitialValueSpecified;
	/// <summary>
	/// Specifies whether the initial velocity was specified with SetInitialVelocity.
	/// </summary>
	BOOL 					m_bInitialVelocitySpecified;

	/// <summary>
	/// Stores the initial value.
	/// </summary>
	DOUBLE				 	m_initialValue;
	/// <summary>
	/// Stores the initial velocity.
	/// </summary>
	DOUBLE					m_initialVelocity;
public:
	/// <summary>
	/// Constructs a custom transition object.
	/// </summary>
	/// <param name="pInterpolator">A pointer to custom interpolator.</param>
	CCustomTransition(CCustomInterpolator* pInterpolator)
	{
		m_pInterpolator = pInterpolator;
		m_bInitialValueSpecified = FALSE;
		m_bInitialVelocitySpecified = FALSE;
		m_initialValue = 0.;
		m_initialVelocity = 0.;
		m_type = CUSTOM;
	}

	/// <summary>
	/// Sets an initial value, which will be applied to an animation variable associated with this transition.
	/// </summary>
	void SetInitialValue(DOUBLE initialValue)
	{
		m_initialValue = initialValue;
		m_bInitialValueSpecified = TRUE;
	}

	/// <summary>
	/// Sets an initial velocity, which will be applied to an animation variable associated with this transition.
	/// </summary>
	void SetInitialVelocity(DOUBLE initialVelocity)
	{
		m_initialVelocity = initialVelocity;
		m_bInitialVelocitySpecified = TRUE;
	}

	/// <summary>
	/// Calls the transition library to create encapsulated transition COM object.
	/// </summary>
	/// <remarks>
	/// This method also can set initial value and initial velocity to be applied to an animation variable, which is
	/// associated with this transition. For this purpose you have to call SetInitialValue and SetInitialVelocity before
	/// the framework creates the encapsulated transition COM object (it happens when you call CAnimationController::AnimateGroup).
	/// </remarks>
	/// <param name="pLibrary">A pointer to transition library, which is responsible for creation of standard transitions.</param>
	/// <param name="pFactory">A pointer to transition factory, which is responsible for creation of custom transitions.</param>
	virtual BOOL Create(IUIAnimationTransitionLibrary* /*pLibrary*/, IUIAnimationTransitionFactory* pFactory)
	{
		Clear();

		if (pFactory != NULL && m_pInterpolator != NULL)
		{
			ATL::CComPtr<IUIAnimationInterpolator> pHandler;

			if (FAILED(CInterpolatorBase::CreateInstance(m_pInterpolator, &pHandler)))
			{
				TRACE("Failed to create custom transition.\n");
				return FALSE;
			}

			HRESULT hr = pFactory->CreateTransition(pHandler, &m_transition);
			if (FAILED(hr) || m_transition == NULL)
			{
				TRACE1("Transtion factory failed to create custom transition. Error code: %x.\n", hr);
				return FALSE;
			}

			if (m_bInitialValueSpecified)
			{
				hr = m_transition->SetInitialValue(m_initialValue);
				ASSERT(SUCCEEDED(hr));
			}

			if (m_bInitialVelocitySpecified)
			{
				hr = m_transition->SetInitialVelocity(m_initialVelocity);
				ASSERT(SUCCEEDED(hr));
			}

			return TRUE;
		}

		return FALSE;
	}
};

#ifdef _AFX_MINREBUILD
#pragma component(minrebuild, on)
#endif 

#ifdef _AFX_PACKING
#pragma pack(pop)
#endif
