//------------------------------------------------------------------------------
// 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 "Graphics/SceneFilter/SceneLogicCheckFilter/SceneLogicCheckFilter.h"
#include "Core/Utility/StringTokenizer.h"
#include "Graphics/SceneNode/SceneNodeManager.h"
#include "Graphics/Model/ModelManager.h"
#include "Graphics/Mesh/MeshManager.h"
#include "Graphics/MeshData/MeshDataManager.h"
#include "Graphics/Material/MaterialManager.h"
#include "Graphics/Texture/TextureManager.h"
#include "Graphics/Picture/PictureManager.h"

namespace Lamp{

//------------------------------------------------------------------------------
// コンストラクタ
SceneLogicCheckFilter::SceneLogicCheckFilter(Scene* scene) :
	SceneFilterInterface(scene){
}
//------------------------------------------------------------------------------
// デストラクタ
SceneLogicCheckFilter::~SceneLogicCheckFilter(){
}
//------------------------------------------------------------------------------
// フィルタ
bool SceneLogicCheckFilter::filter(const String& command){
	StringTokenizer tokenizer_(command);
	if(!tokenizer_.hasMoreTokens()){
		ErrorOut("SceneLogicCheckFilter::filter() Not found filter name");
		return false;
	}
	String filterName = tokenizer_.getNextToken();
	if(filterName != "SceneLogicCheck"){
		ErrorOut("SceneLogicCheckFilter::filter() Invalid filter name %s",
			filterName.getBytes());
		return false;
	}
	return filterScene();
}
//------------------------------------------------------------------------------
// シーンのフィルタ
bool SceneLogicCheckFilter::filterScene(){
	if(!filterSceneNode()){ return false; }
	if(!filterModel()){ return false; }
	if(!filterMesh()){ return false; }
	if(!filterMeshData()){ return false; }
	if(!filterMaterial()){ return false; }
	if(!filterTexture()){ return false; }
	if(!filterPicture()){ return false; }
	return true;
}
//------------------------------------------------------------------------------
// シーンノードのフィルタ
bool SceneLogicCheckFilter::filterSceneNode(){
	// ルートノードが存在するかどうか
	int count = sceneNodeManager_->getCount();
	if(count < 1){
		ErrorOut("SceneLogicCheckFilter::fiterSceneNode() "
			"ルートノードが存在しません %d", count);
		return false;
	}
	// ルートノード名の確認
	SceneNode* rootNode = sceneNodeManager_->get(0);
	if(rootNode->getName() != "RootNode"){
		ErrorOut("SceneLogicCheckFilter::fiterSceneNode() "
			"ルートノードの名前が違います %s", rootNode->getName().getBytes());
		return false;
	}
	// 各シーンノードのチェック
	for(int i = 1; i < count; i++){
		SceneNode* sceneNode = sceneNodeManager_->get(i);
		// 参照カウンタが1以上かどうか
		if(sceneNode->getReferenceCount() < 1){
			ErrorOut("SceneLogicCheckFilter::fiterSceneNode() "
				"参照されていないシーンノードがあります %s %d",
				sceneNode->getName().getBytes(),
				sceneNode->getReferenceCount());
			return false;
		}
	}
	return true;
}
//------------------------------------------------------------------------------
// モデルのフィルタ
bool SceneLogicCheckFilter::filterModel(){
	int count = modelManager_->getCount();
	// 各モデルのチェック
	for(int i = 0; i < count; i++){
		Model* model = modelManager_->get(i);
		// 参照カウンタが1以上かどうか
		if(model->getReferenceCount() < 1){
			ErrorOut("SceneLogicCheckFilter::filterModel() "
				"参照されていないモデルがあります %s %d",
				model->getName().getBytes(), model->getReferenceCount());
			return false;
		}
		// メッシュが存在するかどうか
		if(model->getMeshCount() == 0){
			ErrorOut("SceneLogicCheckFilter::filterModel() "
				"メッシュを持たないモデルがあります %s",
				model->getName().getBytes());
			return false;
		}
	}
	return true;
}
//------------------------------------------------------------------------------
// メッシュのフィルタ
bool SceneLogicCheckFilter::filterMesh(){
	int count = meshManager_->getCount();
	// 各メッシュのチェック
	for(int i = 0; i < count; i++){
		Mesh* mesh = meshManager_->get(i);
		// 参照カウンタが1以上かどうか
		if(mesh->getReferenceCount() < 1){
			ErrorOut("SceneLogicCheckFilter::filterMesh() "
				"参照されていないメッシュがあります %s %d",
				mesh->getName().getBytes(), mesh->getReferenceCount());
			return false;
		}
		// メッシュデータが存在するかどうか
		if(mesh->getMeshData() == NULL){
			ErrorOut("SceneLogicCheckFilter::filterMesh() "
				"メッシュデータを持っていないメッシュがあります %s",
				mesh->getName().getBytes());
			return false;
		}
		// マテリアルが存在するかどうか
		if(mesh->getMaterial() == NULL){
			ErrorOut("SceneLogicCheckFilter::filterMesh() "
				"マテリアルを持っていないメッシュがあります %s",
				mesh->getName().getBytes());
			return false;
		}
	}
	return true;
}
//------------------------------------------------------------------------------
// メッシュデータのフィルタ
bool SceneLogicCheckFilter::filterMeshData(){
	int count = meshDataManager_->getCount();
	// 各メッシュデータのチェック
	for(int i = 0; i < count; i++){
		MeshData* meshData = meshDataManager_->get(i);
		// 参照カウンタが1以上かどうか
		if(meshData->getReferenceCount() < 1){
			ErrorOut("SceneLogicCheckFilter::filterMeshData() "
				"参照されていないメッシュデータがあります %s %d",
				meshData->getName().getBytes(), meshData->getReferenceCount());
			return false;
		}
	}
	return true;
}
//------------------------------------------------------------------------------
// マテリアルのフィルタ
bool SceneLogicCheckFilter::filterMaterial(){
	int count = materialManager_->getCount();
	// 各マテリアルのチェック
	for(int i = 0; i < count; i++){
		Material* material = materialManager_->get(i);
		// 参照カウンタが1以上かどうか
		if(material->getReferenceCount() < 1){
			ErrorOut("SceneLogicCheckFilter::filterMaterial() "
				"参照されていないマテリアルがあります %s %d",
				material->getName().getBytes(), material->getReferenceCount());
			return false;
		}
	}
// 各テクスチャのUVIndexが存在するか
	return true;
}
//------------------------------------------------------------------------------
// テクスチャのフィルタ
bool SceneLogicCheckFilter::filterTexture(){
	int count = textureManager_->getCount();
	// 各テクスチャのチェック
	for(int i = 0; i < count; i++){
		Texture* texture = textureManager_->get(i);
		// 参照カウンタが1以上かどうか
		if(texture->getReferenceCount() < 1){
			ErrorOut("SceneLogicCheckFilter::filterTexture() "
				"参照されていないテクスチャがあります %s %d",
				texture->getName().getBytes(), texture->getReferenceCount());
			return false;
		}
		// ピクチャが存在するかどうか
		if(texture->getPictureCount() <= 0){
			ErrorOut("SceneLogicCheckFilter::filterTexture() "
				"ピクチャを持っていないテクスチャがあります %s",
				texture->getName().getBytes());
			return false;
		}
	}
	return true;
}
//------------------------------------------------------------------------------
// ピクチャのフィルタ
bool SceneLogicCheckFilter::filterPicture(){
	int count = pictureManager_->getCount();
	// 各ピクチャのチェック
	for(int i = 0; i < count; i++){
		Picture* picture = pictureManager_->get(i);
		// 参照カウンタが1以上かどうか
		if(picture->getReferenceCount() < 1){
			ErrorOut("SceneLogicCheckFilter::filterPicture() "
				"参照されていないピクチャがあります %s %d",
				picture->getName().getBytes(), picture->getReferenceCount());
			return false;
		}
		// 幅、高さが2の累乗かどうか
		DimensionI size = picture->getSize();
		if((!Math::checkPow2(size.width)) || (!Math::checkPow2(size.height))){
			ErrorOut("SceneLogicCheckFilter::filterPicture() "
				"サイズが2の累乗でないピクチャがあります %s %s",
				picture->getName().getBytes(), size.toString().getBytes());
			return false;
		}
	}
	return true;
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
