//------------------------------------------------------------------------------
// 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 "Framework/System/SceneFramework.h"
#include "Graphics/System/LampGraphics.h"
#include "Graphics/Renderer/Renderer.h"
#include "Graphics/Renderer/InformationRenderer.h"
#include "Graphics/Camera/CameraManager.h"
#include "Graphics/Fog/Fog.h"
#include "Graphics/MeshData/MeshDataManager.h"
#include "Framework/Utility/PS2PadCameraController.h"
#include "Animation/System/AnimationManager.h"
#include "Animation/System/Animation.h"
#include "Input/System/LampInput.h"
#include "Input/Pad/PS2Pad.h"

// ファイル読み込み
#include "Core/InputOutput/FilePath.h"
#include "Graphics/InputOutput/TextSceneLoader.h"
#include "Graphics/InputOutput/BinarySceneLoader.h"
#include "Animation/InputOutput/TextAnimationLoader.h"
#include "Animation/InputOutput/BinaryAnimationLoader.h"

namespace Lamp{

//------------------------------------------------------------------------------
// コンストラクタ
SceneFramework::SceneFramework(const String& name) :
	BasicFramework(name), renderer_(NULL), informationRenderer_(NULL),
	sceneName_(""), scene_(NULL), camera_(NULL), cameraController_(NULL),
	animationManager_(NULL), animation_(NULL), runCount_(0), pad_(NULL){
}
//------------------------------------------------------------------------------
// デストラクタ
SceneFramework::~SceneFramework(){
}
//------------------------------------------------------------------------------
// フレームワークの初期化
bool SceneFramework::frameworkInitialize(HINSTANCE instanceHandle){
	// 基本フレームワーク呼び出し
	if(!BasicFramework::frameworkInitialize(instanceHandle)){ return false; }
	// レンダラ初期化
	renderer_ = new Renderer();
	informationRenderer_ = new InformationRenderer();
	// カメラコントローラ初期化
	cameraController_ = new PS2PadCameraController();
	Joystick* cameraJoystick = cameraController_->searchJoystick();
	// パッド初期化
	int joystickCount = LampInput::getJoystickCount();
	for(int i = 0; i < joystickCount; i++){
		Joystick* joystick = LampInput::getJoystick(i);
		if(joystick == cameraJoystick){ continue; }
		if(!PS2Pad::checkCompatibility(joystick)){ continue; }
		pad_ = new PS2Pad(joystick);
		break;
	}

	// シーン初期化
	scene_ = LampGraphics::createScene(name_);
	// カメラの作成
	camera_ = scene_->getCameraManager()->createCamera("camera");
	scene_->setCurrentCamera(camera_);
	cameraController_->setCamera(camera_);

	// アニメーションマネージャ初期化
	animationManager_ = new AnimationManager();
	return true;
}
//------------------------------------------------------------------------------
// フレームワークの後始末
void SceneFramework::frameworkFinalize(){
	// アニメーションマネージャの破棄
	animationManager_->clear();
	delete animationManager_;

	// シーンの破棄
	scene_->clear();
	LampGraphics::destroyScene(scene_);

	// パッドの破棄
	SafeDelete(pad_);
	// カメラコントローラの破棄
	SafeDelete(cameraController_);
	// レンダラの破棄
	SafeDelete(informationRenderer_);
	SafeDelete(renderer_);
	// 基本フレームワーク呼び出し
	BasicFramework::frameworkFinalize();
}
//------------------------------------------------------------------------------
// フレームワーク実行
void SceneFramework::frameworkRun(){
	BasicFramework::frameworkRun();
	runCount_++;
	// カメラ操作
	cameraController_->control();
}
//------------------------------------------------------------------------------
// フレームワークレンダリング準備
void SceneFramework::frameworkRenderSetup(){
	BasicFramework::frameworkRenderSetup();
	// 時間計測
	float animationTime = (float)runCount_;// 時間の単位が16.6666fmsが1なので
	runCount_ = 0;

	// カリング前アニメーション。シーンノード
	if(animation_ != NULL){
		animation_->animate(animationTime, Animation::maskPreCulling);
	}

	// トラバース、先にカメラの設定を終えている必要がある
	scene_->traverse();

	// レンダリング準備
	renderer_->renderingSetup(scene_);
	informationRenderer_->renderingSetup(scene_);

	// カリング後アニメーション。キャラクタ、パーティクル等
	if(animation_ != NULL){
		animation_->animate(animationTime, Animation::maskPostCulling);
	}
}
//------------------------------------------------------------------------------
// フレームワークレンダリング
void SceneFramework::frameworkRender(){
	BasicFramework::frameworkRender();
	// レンダリング
	renderer_->rendering();
	informationRenderer_->rendering();
}
//------------------------------------------------------------------------------
// シーンのロード
bool SceneFramework::loadScene(const String& sceneName){
	// シーンのクリア
	clearScene();
	// シーンのロード
	bool textFlag_;
	sceneName_ = sceneName;
	if(sceneName_.getSize() == 0){ return false; }
	FilePath sceneFilePath(sceneName_);
	if(!sceneFilePath.existFile()){ return false; }
	if(sceneFilePath.getExtension() == "tsn"){
		TextSceneLoader* loader = new TextSceneLoader();
		loader->load(sceneFilePath.getPath(), scene_);
		delete loader;
		textFlag_ = true;
	}else if(sceneFilePath.getExtension() == "bsn"){
		BinarySceneLoader* loader = new BinarySceneLoader();
		loader->load(sceneFilePath.getPath(), scene_);
		delete loader;
		textFlag_ = false;
	}else{
		return false;
	}
	// アニメーションのロード
	String animationName = sceneName_.getSubstring(0, sceneName_.getSize() - 3);
	FilePath animationFilePath;
	if(textFlag_){ animationName += "tam"; }
	else{ animationName += "bam"; }
	animationFilePath.setPath(animationName);
	if(animationFilePath.existFile()){
		if(textFlag_){
			TextAnimationLoader* animationLoader =
				new TextAnimationLoader();
			animationLoader->load(
				animationFilePath.getPath(), animationManager_);
			delete animationLoader;
		}else{
			BinaryAnimationLoader* animationLoader =
				new BinaryAnimationLoader();
			animationLoader->load(
				animationFilePath.getPath(), animationManager_);
			delete animationLoader;
		}
		// アニメーションのバインド
		animation_ = animationManager_->search(animationFilePath.getName());
		if(animation_ != NULL){
			if(!animation_->bind(scene_)){
				animationManager_->clear();
				animation_ = NULL;
			}
		}
	}
/*
	FilePath animationFilePath;
	animationFilePath.setPath(
		sceneName_.getSubstring(0, sceneName_.getSize() - 3) + "tam");
	if(animationFilePath.existFile()){
		TextAnimationLoader* animationLoader = new TextAnimationLoader();
		animationLoader->load(
			animationFilePath.getPath(), animationManager_);
		delete animationLoader;
		// アニメーションのバインド
		animation_ = animationManager_->search(animationFilePath.getName());
		if(animation_ != NULL){
			if(!animation_->bind(scene_)){
				animationManager_->clear();
				animation_ = NULL;
			}
		}
	}
*/
	// 背景色設定
	backGroundColor_ = scene_->getFog()->getColor();
	// カメラ位置の設定
	float distance = 2.f;
	MeshDataManager* meshDataManager = scene_->getMeshDataManager();
	int meshDataCount = meshDataManager->getCount();
	for(int i = 0; i < meshDataCount; i++){
		MeshData* meshData = meshDataManager->get(i);
		float radius = meshData->getBoundingSphere().getRadius();
		if(radius > distance){ distance = radius; }
	}
	camera_->setTransformation(
		Vector3::zero, Vector3(0.f, distance * 0.5f, distance * 1.5f));
	cameraController_->setTranslationSensibility(distance * 0.05f);
	return true;
}
//------------------------------------------------------------------------------
// シーンのクリア
void SceneFramework::clearScene(){
	scene_->clear();
	camera_ = scene_->getCameraManager()->createCamera("camera");
	camera_->setTransformation(Vector3::zero, Vector3::zero);
	scene_->setCurrentCamera(camera_);
	cameraController_->setCamera(camera_);
	// アニメーションのクリア
	animationManager_->clear();
	animation_ = NULL;
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
