//------------------------------------------------------------------------------
// 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
 */

#include "LampBasic.h"
#include "Animation/InputOutput/BinaryAnimationLoader.h"
#include "Core/InputOutput/BinaryFileReader.h"
#include "Core/InputOutput/FilePath.h"
#include "Animation/VectorInterpolator/VectorConstantInterpolator.h"
#include "Animation/VectorInterpolator/VectorArrayInterpolator.h"
#include "Animation/VectorInterpolator/VectorLinearInterpolator.h"
#include "Animation/RotationInterpolator/RotationConstantInterpolator.h"
#include "Animation/RotationInterpolator/EulerArrayInterpolator.h"
#include "Animation/RotationInterpolator/QuaternionArrayInterpolator.h"
#include "Animation/RotationInterpolator/QuaternionLinearInterpolator.h"

#include "Animation/System/AnimationManager.h"
#include "Animation/System/AnimationSet.h"
#include "Animation/Camera/CameraAnimation.h"
#include "Animation/SceneNode/SceneNodeAnimation.h"
#include "Animation/Model/CharacterModelAnimation.h"

namespace Lamp{

//------------------------------------------------------------------------------
// コンストラクタ
BinaryAnimationLoader::BinaryAnimationLoader(){
}
//------------------------------------------------------------------------------
// デストラクタ
BinaryAnimationLoader::~BinaryAnimationLoader(){
}
//------------------------------------------------------------------------------
// ロード
//------------------------------------------------------------------------------
// ロード
void BinaryAnimationLoader::load(
	const String& filePath, AnimationManager* manager){
	FilePath path(filePath);
	if(!path.existFile()){
		ErrorOut("BinaryAnimationLoader::load() File not Found");
	}
	BinaryFileReader* binaryFileReader = new BinaryFileReader(filePath);
	load(binaryFileReader, manager);
	delete binaryFileReader;
}
//------------------------------------------------------------------------------
// ロード
void BinaryAnimationLoader::load(
	BinaryReader* binaryReader, AnimationManager* manager){
	reader_ = binaryReader;
	manager_ = manager;

	// ヘッダの読み込み
	readHeader();

	// 各ブロックの読み込み
	while(true){
		if(reader_->isEnd()){ break; }
		// ブロックヘッダ読み込み
		String blockName = readString();
		int blockSize = reader_->readInt();
		int objectCount = reader_->readInt();
		align();
		// ブロック内容の読み込み
		int blockAddress = reader_->getPosition();
		if(blockName == "AnimationSet"){
			for(int i = 0; i < objectCount; i++){
				readAnimationSet();
			}
		}else if(blockName == "Camera"){
			for(int i = 0; i < objectCount; i++){
				readCameraAnimation();
			}
		}else if(blockName == "CameraData"){
			for(int i = 0; i < objectCount; i++){
				readCameraAnimationData();
			}
		}else if(blockName == "SceneNode"){
			for(int i = 0; i < objectCount; i++){
				readSceneNodeAnimation();
			}
		}else if(blockName == "SceneNodeData"){
			for(int i = 0; i < objectCount; i++){
				readSceneNodeAnimationData();
			}
		}else if(blockName == "CharacterModel"){
			for(int i = 0; i < objectCount; i++){
				readCharacterModelAnimation();
			}
		}else if(blockName == "CharacterModelData"){
			for(int i = 0; i < objectCount; i++){
				readCharacterModelAnimationData();
			}
		}else if(blockName == "AnimationSetLink"){
			for(int i = 0; i < objectCount; i++){
				readAnimationSetLink();
			}
		}else if(blockName == "CameraLink"){
			for(int i = 0; i < objectCount; i++){
				readCameraAnimationLink();
			}
		}else if(blockName == "SceneNodeLink"){
			for(int i = 0; i < objectCount; i++){
				readSceneNodeAnimationLink();
			}
		}else if(blockName == "CharacterModelLink"){
			for(int i = 0; i < objectCount; i++){
				readCharacterModelAnimationLink();
			}
		}else{
			// 知らないブロックを読み飛ばす
			DebugOut("BinaryAnimationLoader::load() "
				"Skip unknown block %s (%d)\n",
				blockName.getBytes(), reader_->getPosition());
			reader_->skip(blockSize);
		}
		// 全てのブロックはアライメントをとる
		align();
		Assert((reader_->getPosition() - blockAddress) == blockSize);
	}
}
//------------------------------------------------------------------------------
// ヘッダの読み込み
void BinaryAnimationLoader::readHeader(){
	String header = readString();
	if(header != "LampBinaryAnimation"){
		ErrorOut("BinaryAnimationLoader::readHeader() Invalid header");
	}
	u_int version = reader_->readUInt();
	if(version != 0x00000900){
		ErrorOut("BinaryAnimationLoader::readHeader() Invalid version");
	}
	// アライメント
	align();
}
//------------------------------------------------------------------------------
// アニメーションセット
//------------------------------------------------------------------------------
// アニメーションセットの読み込み
void BinaryAnimationLoader::readAnimationSet(){
	// 名前
	String name = readString();
	AnimationSet* animation = manager_->createAnimationSet(name);
	// 有効、無効
	animation->setEnabled(reader_->readBool());
	// アライメント
	align();
}
//------------------------------------------------------------------------------
// カメラ
//------------------------------------------------------------------------------
// カメラアニメーションの読み込み
void BinaryAnimationLoader::readCameraAnimation(){
	// 名前
	String name = readString();
	CameraAnimation* animation = manager_->createCamera(name);
	// 有効、無効
	animation->setEnabled(reader_->readBool());
	// ターゲット名
	animation->setTargetName(readString());
	// アライメント
	align();
}
//------------------------------------------------------------------------------
// カメラアニメーションデータの読み込み
void BinaryAnimationLoader::readCameraAnimationData(){
	// 名前
	String name = readString();
	CameraAnimationData* data = manager_->createCameraData(name);
	// シーケンス数
	int sequenceCount = reader_->readInt();
	data->setSequenceCount(sequenceCount);
	// アニメーションデータ
	for(int i = 0; i < sequenceCount; i++){
		// 回転
		data->setRotation(i, readRotationInterpolator());
		// 移動
		data->setTranslation(i, readVectorInterpolator());
	}
	// ループフラグ
	for(int i = 0; i < sequenceCount; i++){
		data->setLooped(i, reader_->readBool());
	}
	// アライメント
	align();
}
//------------------------------------------------------------------------------
// シーンノード
//------------------------------------------------------------------------------
// シーンノードアニメーションの読み込み
void BinaryAnimationLoader::readSceneNodeAnimation(){
	// 名前
	String name = readString();
	SceneNodeAnimation* animation = manager_->createSceneNode(name);
	// 有効、無効
	animation->setEnabled(reader_->readBool());
	// ターゲット名
	animation->setTargetName(readString());
	// アライメント
	align();
}
//------------------------------------------------------------------------------
// シーンノードアニメーションデータの読み込み
void BinaryAnimationLoader::readSceneNodeAnimationData(){
	// 名前
	String name = readString();
	SceneNodeAnimationData* data = manager_->createSceneNodeData(name);
	// シーケンス数
	int sequenceCount = reader_->readInt();
	data->setSequenceCount(sequenceCount);
	// アニメーションデータ
	for(int i = 0; i < sequenceCount; i++){
		// スケール
		data->setScale(i, readVectorInterpolator());
		// 回転
		data->setRotation(i, readRotationInterpolator());
		// 移動
		data->setTranslation(i, readVectorInterpolator());
	}
	// ループフラグ
	for(int i = 0; i < sequenceCount; i++){
		data->setLooped(i, reader_->readBool());
	}
	// アライメント
	align();
}
//------------------------------------------------------------------------------
// キャラクタモデル
//------------------------------------------------------------------------------
// キャラクタモデルアニメーションの読み込み
void BinaryAnimationLoader::readCharacterModelAnimation(){
	// 名前
	String name = readString();
	CharacterModelAnimation* animation = manager_->createCharacterModel(name);
	// 有効、無効
	animation->setEnabled(reader_->readBool());
	// ターゲット名
	animation->setTargetName(readString());
	// ボーン数
	int boneCount = reader_->readInt();
	animation->setBoneCount(boneCount);
	// ボーン名
	for(int i = 0; i < boneCount; i++){
		animation->setBoneName(i, readString());
	}
	// アライメント
	align();
}
//------------------------------------------------------------------------------
// キャラクタモデルアニメーションデータの読み込み
void BinaryAnimationLoader::readCharacterModelAnimationData(){
	// 名前
	String name = readString();
	CharacterModelAnimationData* data =
		manager_->createCharacterModelData(name);
	// シーケンス数
	int sequenceCount = reader_->readInt();
	data->setSequenceCount(sequenceCount);
	// ボーン数
	int boneCount = reader_->readInt();
	data->setBoneCount(boneCount);
	// アニメーションデータ
	for(int i = 0; i < sequenceCount; i++){
		for(int j = 0; j < boneCount; j++){
			// スケール
			data->setScale(i, j, readVectorInterpolator());
			// 回転
			data->setRotation(i, j, readRotationInterpolator());
			// 移動
			data->setTranslation(i, j, readVectorInterpolator());
		}
	}
	// ループフラグ
	for(int i = 0; i < sequenceCount; i++){
		data->setLooped(i, reader_->readBool());
	}
	// アライメント
	align();
}
//------------------------------------------------------------------------------
// リンク
//------------------------------------------------------------------------------
// アニメーションセットリンクの読み込み
void BinaryAnimationLoader::readAnimationSetLink(){
	// アニメーション検索
	String animationName = readString();
	AnimationSet* animation = NULL;
	Animation* searchResult = manager_->search(animationName);
	if(searchResult != NULL){ animation = searchResult->castAnimationSet(); }
	if(animation == NULL){
		ErrorOut("BinaryAnimationLoader::readAnimationSetLink() "
			"AnimationSet not found %s (%d)",
			animationName.getBytes(), reader_->getPosition());
	}
	// 子供検索
	int childCount = reader_->readInt();
	for(int i = 0; i < childCount; i++){
		String childName = readString();
		Animation* child = manager_->search(childName);
		if(child == NULL){
			ErrorOut("BinaryAnimationLoader::readAnimationSetLink() "
				"Child animation not found %s (%d)",
				childName.getBytes(), reader_->getPosition());
		}
		animation->addAnimation(child);
	}
	// アライメント
	align();
}
//------------------------------------------------------------------------------
// カメラアニメーションリンクの読み込み
void BinaryAnimationLoader::readCameraAnimationLink(){
	// アニメーション検索
	String animationName = readString();
	CameraAnimation* animation = NULL;
	Animation* animationSearchResult = manager_->search(animationName);
	if(animationSearchResult != NULL){
		animation = animationSearchResult->castCameraAnimation();
	}
	if(animation == NULL){
		ErrorOut("BinaryAnimationLoader::readCameraAnimationLink() "
			"CameraAnimation not found %s (%d)",
			animationName.getBytes(), reader_->getPosition());
	}
	// データ検索
	CameraAnimationData* data = NULL;
	String dataName = readString();
	AnimationData* dataSearchResult = manager_->searchData(dataName);
	if(dataSearchResult != NULL){
		data = dataSearchResult->castCameraAnimationData();
	}
	if(data == NULL){
		ErrorOut("BinaryAnimationLoader::readCameraAnimationLink() "
			"CameraAnimationData not found %s (%d)",
			dataName.getBytes(), reader_->getPosition());
	}
	// リンク
	animation->setCameraAnimationData(data);
	// アライメント
	align();
}
//------------------------------------------------------------------------------
// シーンノードアニメーションリンクの読み込み
void BinaryAnimationLoader::readSceneNodeAnimationLink(){
	// アニメーション検索
	String animationName = readString();
	SceneNodeAnimation* animation = NULL;
	Animation* animationSearchResult = manager_->search(animationName);
	if(animationSearchResult != NULL){
		animation = animationSearchResult->castSceneNodeAnimation();
	}
	if(animation == NULL){
		ErrorOut("BinaryAnimationLoader::readSceneNodeAnimationLink() "
			"SceneNodeAnimation not found %s (%d)",
			animationName.getBytes(), reader_->getPosition());
	}
	// データ検索
	SceneNodeAnimationData* data = NULL;
	String dataName = readString();
	AnimationData* dataSearchResult = manager_->searchData(dataName);
	if(dataSearchResult != NULL){
		data = dataSearchResult->castSceneNodeAnimationData();
	}
	if(data == NULL){
		ErrorOut("BinaryAnimationLoader::readSceneNodeAnimationLink() "
			"SceneNodeAnimationData not found %s (%d)",
			dataName.getBytes(), reader_->getPosition());
	}
	// リンク
	animation->setSceneNodeAnimationData(data);
	// アライメント
	align();
}
//------------------------------------------------------------------------------
// キャラクタモデルアニメーションリンクの読み込み
void BinaryAnimationLoader::readCharacterModelAnimationLink(){
	// アニメーション検索
	String animationName = readString();
	CharacterModelAnimation* animation = NULL;
	Animation* animationSearchResult = manager_->search(animationName);
	if(animationSearchResult != NULL){
		animation = animationSearchResult->castCharacterModelAnimation();
	}
	if(animation == NULL){
		ErrorOut("BinaryAnimationLoader::readCharacterModelAnimationLink() "
			"CharacterModelAnimation not found %s (%d)",
			animationName.getBytes(), reader_->getPosition());
	}
	// データ検索
	CharacterModelAnimationData* data = NULL;
	String dataName = readString();
	AnimationData* dataSearchResult = manager_->searchData(dataName);
	if(dataSearchResult != NULL){
		data = dataSearchResult->castCharacterModelAnimationData();
	}
	if(data == NULL){
		ErrorOut("BinaryAnimationLoader::readCharacterModelAnimationLink() "
			"CharacterModelAnimationData not found %s (%d)",
			dataName.getBytes(), reader_->getPosition());
	}
	// リンク
	animation->setCharacterModelAnimationData(data);
	// アライメント
	align();
}
//------------------------------------------------------------------------------
// 値の読み込み
//------------------------------------------------------------------------------
// 文字列の読み込み
String BinaryAnimationLoader::readString(){
	String result;
	const int stringBufferSize = 256;
	char stringBuffer[stringBufferSize];
	// サイズの読み込み
	int size = reader_->readInt();
	if(size > stringBufferSize){
		// サイズが大きいのでアロケートして文字列読み込み
		char* allocateBuffer = new char[size];
		reader_->readBytes(allocateBuffer, size);
		result = allocateBuffer;
		delete allocateBuffer;
	}else{
		// 文字列読み込み
		reader_->readBytes(stringBuffer, size);
		result = stringBuffer;
	}
	align();
	return result;
}
//------------------------------------------------------------------------------
// 三次元ベクトルの読み込み
Vector3 BinaryAnimationLoader::readVector3(){
	Vector3 result;
	reader_->readBytes(result.array, sizeof(Vector3));
	return result;
}
//------------------------------------------------------------------------------
// 四元数の読み込み
Quaternion BinaryAnimationLoader::readQuaternion(){
	Quaternion result;
	reader_->readBytes(result.array, sizeof(Quaternion));
	return result;
}
//------------------------------------------------------------------------------
// ベクトル補間の読み込み
//------------------------------------------------------------------------------
// ベクトル補間の読み込み
VectorInterpolator* BinaryAnimationLoader::readVectorInterpolator(){
	VectorInterpolator* result = NULL;
	int type = reader_->readInt();
	if(type == 0){
		result = NULL;
	}else if(type == 1){
		result = readVectorConstantInterpolator();
	}else if(type == 2){
		result = readVectorArrayInterpolator();
	}else if(type == 3){
		result = readVectorLinearInterpolator();
	}else{
		ErrorOut("BinaryAnimationLoader::readVectorInterpolator() "
			"Unsupported interpolater (%d)", reader_->getPosition());
	}
	return result;
}
//------------------------------------------------------------------------------
// ベクトル定数補間の読み込み
VectorInterpolator* BinaryAnimationLoader::readVectorConstantInterpolator(){
	VectorConstantInterpolator* interpolator = new VectorConstantInterpolator();
	// 長さ
	interpolator->setLength(reader_->readFloat());
	// 値
	interpolator->setValue(readVector3());
	return interpolator;
}
//------------------------------------------------------------------------------
// ベクトル配列補間の読み込み
VectorInterpolator* BinaryAnimationLoader::readVectorArrayInterpolator(){
	VectorArrayInterpolator* interpolator = new VectorArrayInterpolator();
	// 値
	int size = reader_->readInt();
	interpolator->setSize(size);
	for(int i = 0; i < size; i++){ interpolator->setValue(i, readVector3()); }
	return interpolator;
}
//------------------------------------------------------------------------------
// ベクトル線形補間の読み込み
VectorInterpolator* BinaryAnimationLoader::readVectorLinearInterpolator(){
	VectorLinearInterpolator* interpolator = new VectorLinearInterpolator();
	// 値
	int keyCount = reader_->readInt();
	interpolator->setKeyCount(keyCount);
	for(int i = 0; i < keyCount; i++){
		float time = reader_->readFloat();
		interpolator->setKey(i, time, readVector3());
	}
	return interpolator;
}
//------------------------------------------------------------------------------
// 回転補間の読み込み
//------------------------------------------------------------------------------
// 回転補間の読み込み
RotationInterpolator* BinaryAnimationLoader::readRotationInterpolator(){
	RotationInterpolator* result = NULL;
	int type = reader_->readInt();
	if(type == 0){
		result = NULL;
	}else if(type == 1){
		result = readRotationConstantInterpolator();
	}else if(type == 2){
		result = readEulerArrayInterpolator();
	}else if(type == 3){
		result = readQuaternionArrayInterpolator();
	}else if(type == 4){
		result = readQuaternionLinearInterpolator();
	}else{
		ErrorOut("BinaryAnimationLoader::readRotationInterpolator() "
			"Unsupported interpolater (%d)", reader_->getPosition());
	}
	return result;
}
//------------------------------------------------------------------------------
// 回転定数補間の読み込み
RotationInterpolator* BinaryAnimationLoader::readRotationConstantInterpolator(){
	RotationConstantInterpolator* interpolator =
		new RotationConstantInterpolator();
	// 長さ
	interpolator->setLength(reader_->readFloat());
	// 値
	interpolator->setQuaternion(readQuaternion());
	return interpolator;
}
//------------------------------------------------------------------------------
// オイラー回転配列補間の読み込み
RotationInterpolator* BinaryAnimationLoader::readEulerArrayInterpolator(){
	EulerArrayInterpolator* interpolator = new EulerArrayInterpolator();
	// 値
	int size = reader_->readInt();
	interpolator->setSize(size);
	for(int i = 0; i < size; i++){ interpolator->setValue(i, readVector3()); }
	return interpolator;
}
//------------------------------------------------------------------------------
// 四元数回転配列補間の読み込み
RotationInterpolator* BinaryAnimationLoader::readQuaternionArrayInterpolator(){
	QuaternionArrayInterpolator* interpolator =
		new QuaternionArrayInterpolator();
	// 値
	int size = reader_->readInt();
	interpolator->setSize(size);
	for(int i = 0; i < size; i++){
		interpolator->setValue(i, readQuaternion());
	}
	return interpolator;
}
//------------------------------------------------------------------------------
// 四元数回転線形補間の読み込み
RotationInterpolator* BinaryAnimationLoader::readQuaternionLinearInterpolator(){
	QuaternionLinearInterpolator* interpolator =
		new QuaternionLinearInterpolator();
	// 値
	int keyCount = reader_->readInt();
	interpolator->setKeyCount(keyCount);
	for(int i = 0; i < keyCount; i++){
		float time = reader_->readFloat();
		interpolator->setKey(i, time, readQuaternion());
	}
	return interpolator;
}
//------------------------------------------------------------------------------
// ユーティリティ
//------------------------------------------------------------------------------
// アライメントを取る
void BinaryAnimationLoader::align(){
	reader_->align(16);
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
