/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2005 The OGRE Team
Also see acknowledgements in Readme.html

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.
-----------------------------------------------------------------------------
*/

#ifndef __Animation_H__
#define __Animation_H__

#include "OgrePrerequisites.h"
#include "OgreString.h"
#include "OgreIteratorWrappers.h"

namespace Ogre {

    /** An animation sequence. 
    @remarks
        This class defines the interface for a sequence of animation, whether that
        be animation of a mesh, a path along a spline, or possibly more than one
        type of animation in one. An animation is made up of many 'tracks', which are
        the more specific types of animation.
    @par
        You should not create these animations directly. They will be created via a parent
        object which owns the animation, e.g. Skeleton.
    */
    class _OgreExport Animation
    {

    public:
        /** The types of animation interpolation available. */
        enum InterpolationMode
        {
            /** Values are interpolated along straight lines. */
            IM_LINEAR,
            /** Values are interpolated along a spline, resulting in smoother changes in direction. */
            IM_SPLINE
        };

        /** The types of rotational interpolation available. */
        enum RotationInterpolationMode
        {
            /** Values are interpolated linearly. This is faster but does not 
                necessarily give a completely accurate result.
            */
            RIM_LINEAR,
            /** Values are interpolated spherically. This is more accurate but
                has a higher cost.
            */
            RIM_SPHERICAL
        };
        /** You should not use this constructor directly, use the parent object such as Skeleton instead.
        @param name The name of the animation, should be unique within it's parent (e.g. Skeleton)
        @param length The length of the animation in seconds.
        */
        Animation(const String& name, Real length);
        virtual ~Animation();

        /** Gets the name of this animation. */
        const String& getName(void) const;

        /** Gets the total length of the animation. */
        Real getLength(void) const;

        /** Creates an AnimationTrack. 
        @param handle Numeric handle to give the track, used for accessing the track later. 
            Must be unique within this Animation.
        */
        AnimationTrack* createTrack(unsigned short handle);

        /** Creates a new AnimationTrack automatically associated with a Node. 
        @remarks
            This method creates a standard AnimationTrack, but also associates it with a
            target Node which will receive all keyframe effects.
        @param handle Numeric handle to give the track, used for accessing the track later. 
            Must be unique within this Animation.
        @param node A pointer to the Node object which will be affected by this track
        */
        AnimationTrack* createTrack(unsigned short handle, Node* node);

        /** Gets the number of AnimationTrack objects which make up this animation. */
        unsigned short getNumTracks(void) const;

        /** Gets a track by it's handle. */
        AnimationTrack* getTrack(unsigned short handle) const;


        /** Destroys the track with the given handle. */
        void destroyTrack(unsigned short handle);

        /** Removes and destroys all tracks making up this animation. */
        void destroyAllTracks(void);

        /** Applies an animation given a specific time point and weight.
        @remarks
            Where you have associated animation tracks with Node objects, you can eaily apply
            an animation to those nodes by calling this method.
        @param timePos The time position in the animation to apply.
        @param weight The influence to give to this track, 1.0 for full influence, less to blend with
          other animations.
	    @param scale The scale to apply to translations and scalings, useful for 
			adapting an animation to a different size target.
        */
        void apply(Real timePos, Real weight = 1.0, bool accumulate = false, 
			Real scale = 1.0f);

        /** Applies an animation given a specific time point and weight to a given skeleton.
        @remarks
        Where you have associated animation tracks with Node objects, you can eaily apply
        an animation to those nodes by calling this method.
        @param timePos The time position in the animation to apply.
        @param weight The influence to give to this track, 1.0 for full influence, less to blend with
        other animations.
	    @param scale The scale to apply to translations and scalings, useful for 
			adapting an animation to a different size target.
        */
        void apply(Skeleton* skeleton, Real timePos, Real weight = 1.0, 
			bool accumulate = false, Real scale = 1.0f);

        /** Tells the animation how to interpolate between keyframes.
        @remarks
            By default, animations normally interpolate linearly between keyframes. This is
            fast, but when animations include quick changes in direction it can look a little
            unnatural because directions change instantly at keyframes. An alternative is to
            tell the animation to interpolate along a spline, which is more expensive in terms
            of calculation time, but looks smoother because major changes in direction are 
            distributed around the keyframes rather than just at the keyframe.
        @par
            You can also change the default animation behaviour by calling 
            Animation::setDefaultInterpolationMode.
        */
        void setInterpolationMode(InterpolationMode im);

        /** Gets the current interpolation mode of this animation. 
        @remarks
            See setInterpolationMode for more info.
        */
        InterpolationMode getInterpolationMode(void) const;
        /** Tells the animation how to interpolate rotations.
        @remarks
            By default, animations interpolate lieanrly between rotations. This
            is fast but not necessarily completely accurate. If you want more 
            accurate interpolation, use spherical interpolation, but be aware 
            that it will incur a higher cost.
        @par
            You can also change the default rotation behaviour by calling 
            Animation::setDefaultRotationInterpolationMode.
        */
        void setRotationInterpolationMode(RotationInterpolationMode im);

        /** Gets the current rotation interpolation mode of this animation. 
        @remarks
            See setRotationInterpolationMode for more info.
        */
        RotationInterpolationMode getRotationInterpolationMode(void) const;

        // Methods for setting the defaults
        /** Sets the default animation interpolation mode. 
        @remarks
            Every animation created after this option is set will have the new interpolation
            mode specified. You can also change the mode per animation by calling the 
            setInterpolationMode method on the instance in question.
        */
        static void setDefaultInterpolationMode(InterpolationMode im);

        /** Gets the default interpolation mode for all animations. */
        static InterpolationMode getDefaultInterpolationMode(void);

        /** Sets the default rotation interpolation mode. 
        @remarks
            Every animation created after this option is set will have the new interpolation
            mode specified. You can also change the mode per animation by calling the 
            setInterpolationMode method on the instance in question.
        */
        static void setDefaultRotationInterpolationMode(RotationInterpolationMode im);

        /** Gets the default rotation interpolation mode for all animations. */
        static RotationInterpolationMode getDefaultRotationInterpolationMode(void);

        typedef std::map<unsigned short, AnimationTrack*> TrackList;
        typedef ConstMapIterator<TrackList> TrackIterator;

        /// Fast access to NON-UPDATEABLE track list
        const TrackList& _getTrackList(void) const;

        /// Get non-updateable iterator over tracks
        TrackIterator getTrackIterator(void) const
        { return TrackIterator(mTrackList.begin(), mTrackList.end()); }
        
		/** Optimise an animation by removing unnecessary tracks and keyframes.
		@remarks
			When you export an animation, it is possible that certain tracks
			have been keyfamed but actually don't include anything useful - the
			keyframes include no transformation. These tracks can be completely
			eliminated from the animation and thus speed up the animation. 
			In addition, if several keyframes in a row have the same value, 
			then they are just adding overhead and can be removed.
		*/
		void optimise(void);
		


    protected:
        /// Tracks, indexed by handle
        TrackList mTrackList;
        String mName;

        Real mLength;

        InterpolationMode mInterpolationMode;
        RotationInterpolationMode mRotationInterpolationMode;

        static InterpolationMode msDefaultInterpolationMode;
        static RotationInterpolationMode msDefaultRotationInterpolationMode;

        
    };



}


#endif

