//------------------------------------------------------------------------------
// 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 "Collision/InputOutput/TextCollisionSaver.h"
#include "Core/InputOutput/TextFileWriter.h"
#include "Collision/System/CollisionScene.h"
#include "Collision/System/CollisionNode.h"
#include "Collision/Leaf/StaticSphereCollision.h"
#include "Collision/Leaf/StaticDeformedMeshCollision.h"

namespace Lamp{

//------------------------------------------------------------------------------
// コンストラクタ
TextCollisionSaver::TextCollisionSaver(){
}
//------------------------------------------------------------------------------
// デストラクタ
TextCollisionSaver::~TextCollisionSaver(){
}
//------------------------------------------------------------------------------
// セーブ
void TextCollisionSaver::save(const String& filePath, CollisionScene* scene){
	TextFileWriter* textFileWriter = new TextFileWriter(filePath);
	save(textFileWriter, scene);
	delete textFileWriter;
}
//------------------------------------------------------------------------------
// セーブ
void TextCollisionSaver::save(TextWriter* textWriter, CollisionScene* scene){
	writer_ = textWriter;
	scene_ = scene;

	// ヘッダの書き出し
	writeHeader();

	// ノードリストの書き出し
	int nodeCount = scene_->getNodeCount();
	// ルートノードは書き出さない
	if(nodeCount > 1){
		writeBlockComment("CollisionNode");
		writer_->writeText("CollisionNode {\n");
		for(int i = 1; i < nodeCount; i++){
			CollisionNode* node = scene_->getNode(i);
			writeCollisionNode(node);
		}
		writer_->writeText("}\n\n");
	}

	// リーフリストの書き出し
	int leafCount = scene_->getLeafCount();
	if(leafCount > 0){
		writeBlockComment("CollisionLeaf");
		writer_->writeText("CollisionLeaf {\n");
		for(int i = 0; i < leafCount; i++){
			CollisionLeaf* leaf = scene_->getLeaf(i);
			if(leaf->isStaticSphereCollision()){
				writeStaticSphereCollision(leaf->castStaticSphereCollision());
			}else if(leaf->isStaticDeformedMeshCollision()){
				writeStaticDeformedMeshCollision(
					leaf->castStaticDeformedMeshCollision());
			}else{
				ErrorOut("TextCollisionSaver::save() "
					"対応していないコリジョンリーフです %s",
					leaf->getName().getBytes());
			}
		}
		writer_->writeText("}\n\n");
	}

	// リンクの書き出し
	if((nodeCount + leafCount) > 1){
		writeBlockComment("CollisionNodeLink");
		writer_->writeText("CollisionNodeLink {\n");
		for(int i = 0; i < nodeCount; i++){
			CollisionNode* node = scene_->getNode(i);
			writeCollisionNodeLink(node);
		}
		writer_->writeText("}\n\n");
	}
	writeLineComment();
}
//------------------------------------------------------------------------------
// ヘッダの書き出し
void TextCollisionSaver::writeHeader(){
	writeBlockComment("Header");
	writer_->writeText("Header {\n");
	writer_->writeText("\ttype LampTextCollisionFormat\n");
	writer_->writeText("\tversion 0_1_0\n");
	writer_->writeText("}\n\n");
}
//------------------------------------------------------------------------------
// コリジョンノードの書き出し
void TextCollisionSaver::writeCollisionNode(CollisionNode* node){
	// 名前
	writer_->writeFormat("\t%s {\n", node->getName().getBytes());

	// スケール
	const Vector3& scale = node->getScale();
	writer_->writeFormat("\t\tscale { %.8f %.8f %.8f }\n",
		scale.x, scale.y, scale.z);

	// 回転
	const Vector3& rotation = node->getRotationXYZ();
	writer_->writeFormat("\t\trotation { %.8f %.8f %.8f }\n",
		rotation.x, rotation.y, rotation.z);

	// 移動
	const Vector3& translation = node->getTranslation();
	writer_->writeFormat("\t\ttranslation { %.8f %.8f %.8f }\n",
		translation.x, translation.y, translation.z);

	// 有効、無効
	writer_->writeText("\t\tenabled ");
	writeBool(node->isEnabled());
	writer_->writeText("\n\t}\n\n");
}
//------------------------------------------------------------------------------
// リーフ
//------------------------------------------------------------------------------
// コリジョンリーフの書き出し
void TextCollisionSaver::writeCollisionLeaf(
	CollisionLeaf* leaf, const String& type){
	// 名前
	writer_->writeFormat("\t%s {\n", leaf->getName().getBytes());

	// タイプ
	writer_->writeText("\t\ttype ");
	writer_->writeText(type);

	// コリジョンマスク
	writer_->writeFormat("\n\t\tcollisionMask %u\n", leaf->getCollisionMask());

	// 有効、無効
	writer_->writeText("\t\tenabled ");
	writeBool(leaf->isEnabled());
	writer_->writeText("\n");
}
//------------------------------------------------------------------------------
// 静的球コリジョンの書き出し
void TextCollisionSaver::writeStaticSphereCollision(
	StaticSphereCollision* sphere){
	// コリジョンリーフの書き出し
	writeCollisionLeaf(sphere, "StaticSphere");
	writer_->writeFormat("\t\tsphere { %.8f %.8f %.8f %.8f }\n",
		sphere->getCenter().x, sphere->getCenter().y, sphere->getCenter().z,
		sphere->getRadius());
	writer_->writeText("\t}\n\n");
}
//------------------------------------------------------------------------------
// 静的変形メッシュコリジョンの書き出し
void TextCollisionSaver::writeStaticDeformedMeshCollision(
	StaticDeformedMeshCollision* mesh){
	// コリジョンリーフの書き出し
	writeCollisionLeaf(mesh, "StaticDeformedMesh");

	// バウンディングボックス
	const AxisAlignedBox& box = mesh->getBoundingBox();
	writer_->writeFormat(
		"\t\tboundingBox { %.8f %.8f %.8f } { %.8f %.8f %.8f }\n",
		box.getMinimum().x, box.getMinimum().y, box.getMinimum().z,
		box.getMaximum().x, box.getMaximum().y, box.getMaximum().z);

	// バウンディングスフィア
	const Sphere& sphere = mesh->getBoundingSphere();
	writer_->writeFormat(
		"\t\tboundingSphere { %.8f %.8f %.8f %.8f }\n",
		sphere.getCenter().x, sphere.getCenter().y, sphere.getCenter().z,
		sphere.getRadius());

	// トライアングルリスト
	int triangleCount = mesh->getTriangleCount();
	writer_->writeFormat("\t\ttriangleCount %d {\n", triangleCount);
	for(int i = 0; i < triangleCount; i++){
		const Triangle& triangle = mesh->getTriangle(i);
		const Vector3& vertex0 = triangle.getVertex(0);
		const Vector3& vertex1 = triangle.getVertex(1);
		const Vector3& vertex2 = triangle.getVertex(2);
		writer_->writeFormat(
			"\t\t\t{ %.8f %.8f %.8f } { %.8f %.8f %.8f } { %.8f %.8f %.8f }\n",
			vertex0.x, vertex0.y, vertex0.z, vertex1.x, vertex1.y, vertex1.z,
			vertex2.x, vertex2.y, vertex2.z);
	}
	writer_->writeText("\t\t}\n");
	writer_->writeText("\t}\n\n");
}
//------------------------------------------------------------------------------
// リンク
//------------------------------------------------------------------------------
// コリジョンノードリンクの書き出し
void TextCollisionSaver::writeCollisionNodeLink(CollisionNode* node){
	int childCount = node->getChildCount();
	if(childCount == 0){ return; }
	writer_->writeFormat("\t%s {\n", node->getName().getBytes());
	for(int i = 0; i < childCount; i++){
		CollisionObject* object = node->getChild(i);
		if(object->isCollisionNode()){
			writer_->writeFormat("\t\tnode %s\n", object->getName().getBytes());
		}else{
			writer_->writeFormat("\t\tleaf %s\n", object->getName().getBytes());
		}
	}
	writer_->writeText("\t}\n\n");
}
//------------------------------------------------------------------------------
// ユーティリティ
//------------------------------------------------------------------------------
// boolの書き出し
void TextCollisionSaver::writeBool(bool flag){
	if(flag){
		writer_->writeText("true");
	}else{
		writer_->writeText("false");
	}
}
//------------------------------------------------------------------------------
// 線コメントの書き出し
void TextCollisionSaver::writeLineComment(){
	writer_->writeText("//----------------------------"
		"--------------------------------------------------\n");
}
//------------------------------------------------------------------------------
// ブロックコメントの書き出し
void TextCollisionSaver::writeBlockComment(const String& blockName){
	writeLineComment();
	writer_->writeText("// ");
	writer_->writeText(blockName);
	writer_->writeText(" Block\n");
	writeLineComment();
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
