//------------------------------------------------------------------------------
// Lamp : Open source game middleware
// Copyright (C) 2004  Junpei Ohtani ( Email : junpee@users.sourceforge.jp )
//
// This library 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.1 of the License, or (at your option) any later version.
//
// This library 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 library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//------------------------------------------------------------------------------

/** @file
 * アニメーションヘッダ
 * @author Junpee
 */

#ifndef ANIMATION_H_
#define ANIMATION_H_

namespace Lamp{

class Scene;
class AnimationSet;
class ObjectAnimation;
class CameraAnimation;
class SceneNodeAnimation;
class CharacterModelAnimation;

//------------------------------------------------------------------------------
/**
 * アニメーション
 */
class Animation{
friend class AnimationManager;
public:
	//--------------------------------------------------------------------------
	/// アニメーションマスク
	enum AnimationMask{
		/// カメラアニメーション
		maskCamera =			1 << 0,
		/// シーンノードアニメーション
		maskSceneNode =			1 << 1,
		/// キャラクタモデルアニメーション
		maskCharacterModel =	1 << 2,
		/// カリング前アニメーション
		maskPreCulling =
			maskCamera |
			maskSceneNode,
		/// カリング後アニメーション
		maskPostCulling =
			maskCharacterModel,
		/// 強制アニメーション
		maskForce =
			maskCamera |
			maskSceneNode |
			maskCharacterModel
	};

	//--------------------------------------------------------------------------
	/// データコピーマスク
	enum DataCopyMask{
		/// データコピーしない
		copyNone =				0,
		/// カメラデータコピー
		copyCamera =			1 << 0,
		/// シーンノードデータコピー
		copySceneNode =			1 << 1,
		/// キャラクタモデルデータコピー
		copyCharacterModel =	1 << 2,
	};

	//--------------------------------------------------------------------------
	// バインド
	//--------------------------------------------------------------------------
	/**
	 * バインド
	 * @param scene バインド対象シーン
	 * @return 成功すればtrue
	 */
	virtual bool bind(Scene* scene) = 0;

	/**
	 * バインド解除
	 */
	virtual void unbind() = 0;

	//--------------------------------------------------------------------------
	// シーケンス
	//--------------------------------------------------------------------------
	/**
	 * シーケンス数の取得
	 * @return シーケンス数
	 */
	virtual int getSequenceCount() const = 0;

	/**
	 * シーケンスの設定
	 * @param sequence 設定するシーケンス
	 * @param time 設定する時間
	 */
	virtual void setSequence(int sequence, float time = 0.f) = 0;

	/**
	 * シーケンスの取得
	 * @return シーケンス
	 */
	virtual int getSequence() const = 0;

// ChangeSequenceによるシーケンス補間。何秒で次のシーケンスに完全移行するか指定。
// Rateに対する線形補間やベジェ補間があるといいかも
	//--------------------------------------------------------------------------
	// 時間
	//--------------------------------------------------------------------------
	/**
	 * 時間の設定
	 * @param time 設定する時間
	 */
	virtual void setTime(float time) = 0;

	/**
	 * 時間の取得
	 * @return 時間
	 */
	virtual float getTime() const = 0;

	//--------------------------------------------------------------------------
	// アニメーション
	//--------------------------------------------------------------------------
	/**
	 * アニメーション
	 * @param deltaTime デルタタイム
	 * @param mask アニメーションマスク
	 * @return アニメーションが終了していればtrue
	 */
	virtual bool animate(float deltaTime, AnimationMask mask) = 0;

	/**
	 * 終了しているか
	 * @return 終了していればtrue
	 */
	virtual bool isFinished() const = 0;

	/**
	 * 長さの取得
	 * @return 長さ
	 */
	virtual float getLength() const = 0;

	/**
	 * ループしているか
	 * @return ループしていればtrue
	 */
	virtual bool isLooped() const = 0;

	//--------------------------------------------------------------------------
	// コピー
	//--------------------------------------------------------------------------
	/**
	 * コピー
	 * @param dataCopyMask データコピーマスク
	 * @return コピーされたアニメーション
	 */
	virtual Animation* copy(DataCopyMask dataCopyMask = copyNone) const = 0;

	//--------------------------------------------------------------------------
	// RTTI
	//--------------------------------------------------------------------------
	/**
	 * アニメーションセットかどうか
	 * @return アニメーションセットならtrue
	 */
	virtual bool isAnimationSet() const{ return false; }

	/**
	 * アニメーションセットへのキャスト
	 * @return アニメーションセット。型が違えばNULLを返す。
	 */
	virtual AnimationSet* castAnimationSet() const{
		if(isAnimationSet()){ return (AnimationSet*)this; }
		return NULL;
	}

	//--------------------------------------------------------------------------
	/**
	 * オブジェクトアニメーションかどうか
	 * @return オブジェクトアニメーションならtrue
	 */
	virtual bool isObjectAnimation() const{ return false; }

	/**
	 * オブジェクトアニメーションへのキャスト
	 * @return オブジェクトアニメーション。型が違えばNULLを返す。
	 */
	virtual ObjectAnimation* castObjectAnimation() const{
		if(isObjectAnimation()){ return (ObjectAnimation*)this; }
		return NULL;
	}

	//--------------------------------------------------------------------------
	/**
	 * カメラアニメーションかどうか
	 * @return カメラアニメーションならtrue
	 */
	virtual bool isCameraAnimation() const{ return false; }

	/**
	 * カメラアニメーションへのキャスト
	 * @return カメラアニメーション。型が違えばNULLを返す。
	 */
	virtual CameraAnimation* castCameraAnimation() const{
		if(isCameraAnimation()){ return (CameraAnimation*)this; }
		return NULL;
	}

	//--------------------------------------------------------------------------
	/**
	 * シーンノードアニメーションかどうか
	 * @return シーンノードアニメーションならtrue
	 */
	virtual bool isSceneNodeAnimation() const{ return false; }

	/**
	 * シーンノードアニメーションへのキャスト
	 * @return シーンノードアニメーション。型が違えばNULLを返す。
	 */
	virtual SceneNodeAnimation* castSceneNodeAnimation() const{
		if(isSceneNodeAnimation()){ return (SceneNodeAnimation*)this; }
		return NULL;
	}

	//--------------------------------------------------------------------------
	/**
	 * キャラクタモデルアニメーションかどうか
	 * @return キャラクタモデルアニメーションならtrue
	 */
	virtual bool isCharacterModelAnimation() const{ return false; }

	/**
	 * キャラクタモデルアニメーションへのキャスト
	 * @return キャラクタモデルアニメーション。型が違えばNULLを返す。
	 */
	virtual CharacterModelAnimation* castCharacterModelAnimation() const{
		if(isCharacterModelAnimation()){
			return (CharacterModelAnimation*)this;
		}
		return NULL;
	}

	//--------------------------------------------------------------------------
	// 名前
	//--------------------------------------------------------------------------
	/**
	 * 名前の取得
	 * @return 名前
	 */
	virtual const String& getName() const{ return name_; }

	//--------------------------------------------------------------------------
	// マネージャ
	//--------------------------------------------------------------------------
	/**
	 * マネージャの取得
	 * @return マネージャ
	 */
	virtual AnimationManager* getManager() const{ return manager_; }

	//--------------------------------------------------------------------------
	/**
	 * 有効、無効の設定
	 * @param enabled trueなら有効、falseなら無効
	 */
	virtual void setEnabled(bool enabled){ enabled_ = enabled; }

	/**
	 * 有効、無効の取得
	 * @return trueなら有効、falseなら無効
	 */
	virtual bool isEnabled() const{ return enabled_; }

	//--------------------------------------------------------------------------
protected:
	/**
	 * コンストラクタ
	 * @param name 名前
	 * @param manager アニメーションマネージャ
	 */
	Animation(String name, AnimationManager* manager) :
		 name_(name), manager_(manager), enabled_(true){}

	/**
	 * デストラクタ
	 */
	virtual ~Animation(){}

	/**
	 * 時間の増加
	 * @param deltaTime デルタタイム
	 * @return ループ補正された時間
	 */
	float increasesTime(float deltaTime){
		float time = getTime();
		time += deltaTime;
		setTime(time);
		if(!isLooped()){ return time; }
		return Math::fmod(time, getLength());
	}

	//--------------------------------------------------------------------------
private:
	// コピーコンストラクタの隠蔽
	Animation(const Animation& copy);

	// 代入コピーの隠蔽
	void operator =(const Animation& copy);

	// 名前
	String name_;
	// アニメーションマネージャ
	AnimationManager* manager_;
	// 有効、無効フラグ
	bool enabled_;

};

//------------------------------------------------------------------------------
} // End of namespace Lamp
#endif // End of ANIMATION_H_
//------------------------------------------------------------------------------
