/***********************************************************************
    created:    7/8/2010
    author:     Martin Preisler

    purpose:    Defines the interface for the Animation class
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2010 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#ifndef _CEGUIAnimation_h_
#define _CEGUIAnimation_h_

#include "CEGUI/String.h"
#include <vector>
#include <map>

#if defined(_MSC_VER)
#   pragma warning(push)
#   pragma warning(disable : 4251)
#endif

// Start of CEGUI namespace section
namespace CEGUI
{

/*!
\brief
    Defines an 'animation' class

    This is definition of Animation. Can be reused multiple times via
    AnimationInstance class. You can't step this class directly, you have to
    instantiate it via AnimationManager::instantiateAnimation.

    AnimationInstance provides means for stepping the animation and applying
    it to PropertySets.

\par
    Animation itself doesn't contain key frames. It is composed of Affector(s).
    Each Affector affects one Property. So one Animation can affect multiple
    properties.

\see
    AnimationInstance, Affector
*/
class CEGUIEXPORT Animation
{
public:
    //! enumerates possible replay modes
    enum class ReplayMode : int
    {
        //! plays the animation just once, then stops
        PlayOnce,
        //! loops the animation infinitely
        Loop,
        /** infinitely plays the animation forward, when it reaches the end, it
         * plays it backwards, etc...
         */
        Bounce
    };

    /** internal constructor, please only construct animations via
     * AnimationManager::createAnimation method
     */
    Animation(const String& name);

    //! destructor, this destroys all affectors defined inside this animation
    ~Animation(void);

    /*!
    \brief
        Retrieves name of this Animation definition
    */
    const String& getName() const;

    /*!
    \brief
        Sets the replay mode of this animation
    */
    void setReplayMode(ReplayMode mode);

    /*!
    \brief
        Retrieves the replay mode of this animation
    */
    ReplayMode getReplayMode() const;

    /*!
    \brief
        Sets the duration of this animation
    */
    void setDuration(float duration);

    /*!
    \brief
        Retrieves the duration of this animation
    */
    float getDuration() const;

    /*!
    \brief
        Sets whether this animation auto starts or not

    \par
        Auto start means that the animation instances of this definition call
        Start on themselves once their target is set.
    */
    void setAutoStart(bool autoStart);

    /*!
    \brief
        Retrieves auto start.

    \see
        Animation::setAutoStart
    */
    bool getAutoStart() const;

    /*!
    \brief
        Creates a new Affector

    \see
        Affector
    */
    Affector* createAffector(void);

    /*!
    \brief
        Creates a new Affector

    \par
        This is just a helper, finger saving method.
    */
    Affector* createAffector(const String& targetProperty,
                             const String& interpolator);

    /*!
    \brief
        Destroys given Affector
    */
    void destroyAffector(Affector* affector);

    /*!
    \brief
        Retrieves the Affector at given index
    */
    Affector* getAffectorAtIndex(size_t index) const;

    /*!
    \brief
        Retrieves number of Affectors defined in this Animation
    */
    size_t getNumAffectors(void) const;

    /*!
    \brief
        This defined a new auto subscription.

    \param
        eventName the name of the event we want to subscribe to,
        CEGUI::Window::EventClicked for example

    \param
        action is the action that will be invoked on the animation instance if
        this event is fired

    \par
        Auto Subscription does subscribe to event sender (usually target window)
        of Animation Instance when the event source is set.

        Usable action strings:
        - Start
        - Stop
        - Pause
        - Unpause
        - TogglePause
        - Finish

        eventName is the name of the event we want to subscribe to
    */
    void defineAutoSubscription(const String& eventName, const String& action);

    /*!
    \brief
        This undefines previously defined auto subscription.

    \see
        Animation::defineAutoSubscription
    */
    void undefineAutoSubscription(const String& eventName,
                                  const String& action);

    /*!
    \brief
        This undefines all previously defined auto subscriptions.

    \see
        Animation::defineAutoSubscription
    */
    void undefineAllAutoSubscriptions();

    /*!
    \brief
        Subscribes all auto subscriptions with information from given animation
        instance

    \par
        This is internal method! Only use if you know what you're doing!
    */
    void autoSubscribe(AnimationInstance* instance);

    bool hasAutoSubscriptions() const { return !d_autoSubscriptions.empty(); }

    /*!
    \brief
        Unsubscribes all auto subscriptions with information from given
        animation instance

    \par
        This is internal method! Only use if you know what you're doing!
    */
    static void autoUnsubscribe(AnimationInstance* instance);

    /*!
     \brief
        Internal method, causes all properties that are used by this animation
        and it's affectors to be saved

    \par
        So their values are still known after
        they've been affected.
     */
    void savePropertyValues(AnimationInstance* instance);

    /*!
    \brief
        Applies this Animation definition using information from given
        AnimationInstance

    \par
        This is internal method, only use if you know what you're doing!
    */
    void apply(AnimationInstance* instance);

    /*!
    \brief
        Writes an xml representation of this Animation definition to \a out_stream.

    \param xml_stream
        Stream where xml data should be output.
    \param name_override
    	If given, this value overrides the name attribute written to the stream.
    	This is useful when writing out looknfeels
    */
    void writeXMLToStream(XMLSerializer& xml_stream, const String& name_override = "") const;

private:
    //! name of this animation
    String d_name;

    //! currently used replay mode
    ReplayMode d_replayMode;
    //! duration of animation (in seconds)
    float d_duration;
    /** if true, instantiations of this animation call start on themselves when
     * their target is set
     */
    bool d_autoStart;

    //! list of affectors defined in this animation
    std::vector<Affector*> d_affectors;

    /** holds pairs of 2 strings, the left string is the Event that we will
     * subscribe to, the right string is the action that will be invoked to the
     * instance if the event is fired on target window
     */
    std::multimap<String, String> d_autoSubscriptions;
};

} // End of  CEGUI namespace section

#if defined(_MSC_VER)
#   pragma warning(pop)
#endif

#endif  // end of guard _CEGUIAnimation_h_

