//------------------------------------------------------------------------------
// 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 CHARACTER_MODEL_ANIMATION_DATA_H_
#define CHARACTER_MODEL_ANIMATION_DATA_H_

#include <Animation/System/AnimationData.h>
#include <Animation/VectorInterpolator/VectorInterpolator.h>
#include <Animation/RotationInterpolator/RotationInterpolator.h>

namespace Lamp{

//------------------------------------------------------------------------------
/**
 * キャラクタモデルアニメーションデータ
 */
class CharacterModelAnimationData : public AnimationData{
friend class AnimationManager;
protected:
	//--------------------------------------------------------------------------
	/**
	 * キャラクタモデルシーケンス
	 */
	class CharacterModelSequence : public Sequence{
	public:
		/**
		 * コンストラクタ
		 */
		CharacterModelSequence() : Sequence(),
			boneCount_(0), scale_(NULL), rotation_(NULL), translation_(NULL){}

		/**
		 * デストラクタ
		 */
		virtual ~CharacterModelSequence(){ clear(); }

		/**
		 * 代入コピー
		 * @param copy コピー元
		 */
		virtual void operator =(const CharacterModelSequence& copy){
			Sequence::operator=(copy);
			int boneCount = copy.boneCount_;
			setBoneCount(boneCount);
			for(int i = 0; i < boneCount; i++){
				if(copy.scale_[i] != NULL){
					scale_[i] = copy.scale_[i]->duplicate();
				}
				if(copy.rotation_[i] != NULL){
					rotation_[i] = copy.rotation_[i]->duplicate();
				}
				if(copy.translation_[i] != NULL){
					translation_[i] = copy.translation_[i]->duplicate();
				}
			}
		}

		/**
		 * 長さの計算
		 */
		virtual void calcLength(){
			// ロード時のボトルネックになる可能性有り
			// calcLength()を明示的に呼ぶようにするか、配列によるデータ設定か
			length_ = 0.f;
			for(int i = 0; i < boneCount_; i++){
				if((scale_[i] != NULL) &&
					(scale_[i]->getLength() > length_)){
					length_ = scale_[i]->getLength();
				}
			}
			for(int i = 0; i < boneCount_; i++){
				if((rotation_[i] != NULL) &&
					(rotation_[i]->getLength() > length_)){
					length_ = rotation_[i]->getLength();
				}
			}
			for(int i = 0; i < boneCount_; i++){
				if((translation_[i] != NULL) &&
					(translation_[i]->getLength() > length_)){
					length_ = translation_[i]->getLength();
				}
			}
		}

		/**
		 * ボーン数の設定
		 * @param boneCount ボーン数
		 */
		virtual void setBoneCount(int boneCount){
			clear();
			boneCount_ = boneCount;
			if(boneCount_ != 0){
				int size = sizeof(VectorInterpolator*) * boneCount_;
				scale_ = new VectorInterpolator*[boneCount_];
				::memset(scale_, 0, size);
				rotation_ = new RotationInterpolator*[boneCount_];
				::memset(rotation_, 0, size);
				translation_ = new VectorInterpolator*[boneCount_];
				::memset(translation_, 0, size);
			}
		}

		/**
		 * クリア
		 */
		virtual void clear(){
			for(int i = boneCount_ - 1; i >= 0; i--){
				SafeDelete(translation_[i]);
				SafeDelete(rotation_[i]);
				SafeDelete(scale_[i]);
			}
			SafeArrayDelete(translation_);
			SafeArrayDelete(rotation_);
			SafeArrayDelete(scale_);
			boneCount_ = 0;
		}

		//----------------------------------------------------------------------
		/// ボーン数
		int boneCount_;
		/// スケール
		VectorInterpolator** scale_;
		/// 回転
		RotationInterpolator** rotation_;
		/// 移動
		VectorInterpolator** translation_;

	};

public:
	//--------------------------------------------------------------------------
	// コピー
	//--------------------------------------------------------------------------
	/**
	 * コピー
	 * @return コピーされたアニメーションデータ
	 */
	virtual AnimationData* copy() const{
		return copyCharacterModelAnimationData();
	}

	/**
	 * キャラクタモデルアニメーションデータのコピー
	 */
	virtual CharacterModelAnimationData*
		copyCharacterModelAnimationData() const;

	//--------------------------------------------------------------------------
	// シーケンス
	//--------------------------------------------------------------------------
	/**
	 * シーケンス数の設定
	 * @param sequenceCount シーケンス数
	 */
	virtual void setSequenceCount(int sequenceCount){
		SafeArrayDelete(sequences_);
		sequenceCount_ = sequenceCount;
		if(sequenceCount_ == 0){ return; }
		sequences_ = new CharacterModelSequence[sequenceCount_];
		if(boneCount_ == 0){ return; }
		for(int i = 0; i < sequenceCount; i++){
			sequences_[i].setBoneCount(boneCount_);
		}
	}

	/**
	 * シーケンス数の取得
	 * @return シーケンス数
	 */
	virtual int getSequenceCount() const{ return sequenceCount_; }

	//--------------------------------------------------------------------------
	// ボーン
	//--------------------------------------------------------------------------
	/**
	 * ボーン数の取得
	 * @return ボーン数
	 */
	virtual int getBoneCount() const{ return boneCount_; }

	/**
	 * ボーン数の設定
	 * @param boneCount ボーン数
	 */
	virtual void setBoneCount(int boneCount){
		if(boneCount_ == boneCount){ return; }
		boneCount_ = boneCount;
		for(int i = 0; i < sequenceCount_; i++){
			sequences_[i].setBoneCount(boneCount_);
		}
	}

	//--------------------------------------------------------------------------
	// スケール
	//--------------------------------------------------------------------------
	/**
	 * スケールの設定
	 * @param sequence シーケンス
	 * @param index ボーンのインデックス
	 * @param scale 設定するスケール
	 */
	virtual void setScale(
		int sequence, int index, VectorInterpolator* scale){
		Assert(sequence >= 0);
		Assert(sequence < sequenceCount_);
		Assert(index >= 0);
		Assert(index < boneCount_);
		CharacterModelSequence& data = sequences_[sequence];
		SafeDelete(data.scale_[index]);
		data.scale_[index] = scale;
		data.calcLength();
	}

	/**
	 * スケールの取得
	 * @param sequence シーケンス
	 * @param index ボーンのインデックス
	 * @return スケール
	 */
	virtual VectorInterpolator* getScale(int sequence, int index) const{
		Assert(sequence >= 0);
		Assert(sequence < sequenceCount_);
		Assert(index >= 0);
		Assert(index < boneCount_);
		return sequences_[sequence].scale_[index];
	}

	//--------------------------------------------------------------------------
	// 回転
	//--------------------------------------------------------------------------
	/**
	 * 回転の設定
	 * @param sequence シーケンス
	 * @param index ボーンのインデックス
	 * @param rotation 設定する回転
	 */
	virtual void setRotation(
		int sequence, int index, RotationInterpolator* rotation){
		Assert(sequence >= 0);
		Assert(sequence < sequenceCount_);
		Assert(index >= 0);
		Assert(index < boneCount_);
		CharacterModelSequence& data = sequences_[sequence];
		SafeDelete(data.rotation_[index]);
		data.rotation_[index] = rotation;
		data.calcLength();
	}

	/**
	 * 回転の取得
	 * @param sequence シーケンス
	 * @param index ボーンのインデックス
	 * @return 回転
	 */
	virtual RotationInterpolator* getRotation(int sequence, int index) const{
		Assert(sequence >= 0);
		Assert(sequence < sequenceCount_);
		Assert(index >= 0);
		Assert(index < boneCount_);
		return sequences_[sequence].rotation_[index];
	}

	//--------------------------------------------------------------------------
	// 移動
	//--------------------------------------------------------------------------
	/**
	 * 移動の設定
	 * @param sequence シーケンス
	 * @param index ボーンのインデックス
	 * @param translation 設定する移動
	 */
	virtual void setTranslation(
		int sequence, int index, VectorInterpolator* translation){
		Assert(sequence >= 0);
		Assert(sequence < sequenceCount_);
		Assert(index >= 0);
		Assert(index < boneCount_);
		CharacterModelSequence& data = sequences_[sequence];
		SafeDelete(data.translation_[index]);
		data.translation_[index] = translation;
		data.calcLength();
	}

	/**
	 * 移動の取得
	 * @param sequence シーケンス
	 * @param index ボーンのインデックス
	 * @return 移動
	 */
	virtual VectorInterpolator* getTranslation(
		int sequence, int index) const{
		Assert(sequence >= 0);
		Assert(sequence < sequenceCount_);
		Assert(index >= 0);
		Assert(index < boneCount_);
		return sequences_[sequence].translation_[index];
	}

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

	//--------------------------------------------------------------------------
protected:
	/**
	 * コンストラクタ
	 * @param name 名前
	 * @param manager アニメーションマネージャ
	 */
	CharacterModelAnimationData(
		const String& name, AnimationManager* manager) :
		AnimationData(name, manager),
		sequenceCount_(0), sequences_(NULL), boneCount_(0){}

	/**
	 * デストラクタ
	 */
	virtual ~CharacterModelAnimationData(){
		SafeArrayDelete(sequences_);
	}

	//--------------------------------------------------------------------------
	/**
	 * シーケンスの取得
	 * @param sequence シーケンス
	 * @return シーケンス
	 */
	virtual Sequence* getSequence(int sequence){
		Assert(sequence >= 0);
		Assert(sequence < sequenceCount_);
		return &sequences_[sequence];
	}

	/**
	 * シーケンスの取得
	 * @param sequence シーケンス
	 * @return シーケンス
	 */
	virtual const Sequence* getSequence(int sequence) const{
		Assert(sequence >= 0);
		Assert(sequence < sequenceCount_);
		return &sequences_[sequence];
	}

	//--------------------------------------------------------------------------
private:
	// シーケンス数
	int sequenceCount_;
	// シーケンス
	CharacterModelSequence* sequences_;
	// ボーン数
	int boneCount_;

};

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