/** \file AnimationShader.h
 * \brief The header file for the 'AnimationShader' class.
 */

#pragma once
// OSkA Includes
#include "OSkA.h"
// Other Includes
#include <string>

namespace OSkA
{
	/** \brief A AnimationShader provides us with interfaces to use the animation shader.
	 *
	 * The AnimationShader class contains a reference to a
	 * ShaderInterface object and offers a simple interface to
	 * use the shader.
	 *
	 * We have methods to enable/disable the shader, to set a absolute
	 * point of time, or to add an relativ amount of time. And we have
	 * also methods to set the actual shader parameters(as the bone
	 * weights and animation transforms).
	 */
	class AnimationShader
	{
	public:
		/** \brief Default Constructor
		 */
		AnimationShader();
		/** \brief Destructor
		 */
		~AnimationShader();

		/** \brief Set the time.
		 * \param time	The new time.
		 */
		void setGlobalTime(float time);
		/** \brief Adds a amount of time to the actual time.
		 *
		 * \param time	The amout of time to be added.
		 */
		void addGlobalTime(float time);
		/** \brief Returns the actual time
		 *
		 * \return The actual shader time
		 */
		float getGlobalTime();

		/** \brief Enable the Shader.
		 */
		void enable();
		/** \brief Disable the Shader.
		 */
		void disable();

		/** \brief Sets the actual ShaderInterface object
		 *
		 * This method sets the actual ShaderInterface object. The AnimationShader
		 * will just store the pointer and will take care of freeing the
		 * ShaderInterface objects memory.
		 * \param actualShader	Pointer to the actual shader object.
		 */
		void setActualShader(ShaderInterface* actualShader, bool useTexture);
		/** \brief Returns the actual ShaderInterface object
		 *
		 * This method returns the actual ShaderInterface object. The object
		 * refered by the returned pointer is the same as used by this
		 * class, so by affecting the object you will affect this class.
		 * \return Pointer to the actual ShaderInferface object.
		 */
		ShaderInterface* getActualShader();

		/** \brief Sets the bone weights for the actual animation.
		 *
		 * This methods sets the actual bone data by passing them to
		 * the actual ShaderInferface object.
		 * \param boneAssignements The BoneCooker containing the bone weights.
		 */
		void setBoneAssignements(BoneCooker* boneAssignements);
		/** \brief Sets the animation texture.
		 *
		 * This method sets the actual animation texture by passing it to the actual
		 * ShaderInterface object.
		 * Mind that after calling this method, the active texture unit
		 * will be those you have defined by the texUnit parameter.
		 * \param animation The AnimationCooker containing the animation texture.
		 * \param texUnit	The texture unit the animation texture will be bound to.
		 */
		void setAnimationTexture(AnimationCooker* animation, unsigned int texUnit);
		/** \brief Sets the active animation of the actual texture
		 *
		 * This methods passes offset information to the actual ShaderInterface object.
		 * Otherwise the Shader won't be able to find the right animation (of possibly
		 * many) in the texture.
		 * \param animation The AnimationCooker containing the animation
		 * \param animationIndex The index of the animation that shall be used
		 */
		void setActiveAnimation(AnimationCooker* animation, int animationIndex);
		/** \brief Sets the animation time data.
		 *
		 * This methods passes time information to the actual ShaderInterface object.
		 * You will have to assure that you have the correct actual time (see methods
		 * setTime and addTime) to keep the shader synchronized with the rest of your
		 * program.
		 * \param animation The AnimationCooker contain time data.
		 * \param animationIndex The index of the animation that shall be used
		 */
		void setAnimationTime(AnimationCooker* animation, int animationIndex);

		/** \brief Sets the actual animation data
		 *
		 * This methods passes the actual animation data as a uniform to the
		 * shader. This method will be used when the animation data is not
		 * stored in a texture.
		 * \param animation The AnimationCooker containing data.
		 * \param animationIndex The index of the animation that shall be used
		 */
		void setAnimationUniform(AnimationCooker* animation, int animationIndex);
	private:
		/** \brief The actual ShaderInterface object.
		 */
		ShaderInterface* actualShader;

		/** \brief Shader attribute location for 'oskaInfluences'
		 */
		int locInfluences;
		/** \brief Shader attribute location for 'oskaWeights'
		 */
		int locWeights;

		/** \brief Shader uniform location for 'oskaAnimationTex'
		 */
		int locAnimation;
		/** \brief Shader uniform location for 'oskaTime1'
		 */
		int locTime1;
		/** \brief Shader uniform location for 'oskaTime2'
		 */
		int locTime2;
		/** \brief Shader uniform location for 'oskaTime1Factor'
		 */
		int locTime1Factor;
		/** \brief Shader uniform location for 'oskaOffset'
		 */
		int locOffset;
		/** \brief Shader uniform location for 'oskaBones'
		 */
		int locBones;

		/** \brief The internal shader time.
		 *
		 * The shader has an internal time, cause it might be used for
		 * multiple animations, and so we just have to update the time onces per
		 * frame.
		 */
		float globalTime;
	};
}
