/* 
Level of Details class
Copyright (C) 2007 Pierre Schwartz

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or any later version.

This program 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "LOD_Animated_scenenode.h"
#include <iostream>


LOD_Animated_scenenode::LOD_Animated_scenenode(std::vector<irr::scene::IAnimatedMesh*>& l_m, 
						   std::vector<irr::f32>& l_d, 
						   irr::scene::ISceneNode *parent, 
						   irr::scene::ISceneManager *smgr, 
						   irr::s32 id)
				:irr::scene::IAnimatedMeshSceneNode(parent, smgr, id){

	// let's create the list of meshes, and their respective areas
	if (l_m.size() != l_d.size())
		return;
	
	int size = l_m.size();
	l_distances = l_d;

	// let's load all the meshes
	for (int i=0; i<size; i++){
		irr::scene::IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(l_m[i], this);
		node->setVisible(false);
		l_nodes.push_back(node);
	}

	// only the first is visible
	l_nodes[0]->setVisible(true);
	current_index = 0;
	current_node = l_nodes[0];
	current_distance = -1;
	Box = current_node->getBoundingBox();

	setVisible(true);
	smgr->registerNodeForRendering(this);

	c = smgr->getActiveCamera();
}

void LOD_Animated_scenenode::OnRegisterSceneNode(){
	if (IsVisible)
		SceneManager->registerNodeForRendering(this);
}

void LOD_Animated_scenenode::render(){
	current_node->render();
}

const irr::core::aabbox3d<irr::f32>& LOD_Animated_scenenode::getBoundingBox() const{
	return Box;
}

void LOD_Animated_scenenode::OnPreRender(){
	SceneManager->registerNodeForRendering(this);
	irr::core::vector3df &v = getAbsolutePosition()-c->getAbsolutePosition();
	
	irr::f64 distance = v.getLength();

	if (distance < current_distance){
		// decrease mesh
		current_node->setVisible(false);
		current_index--;

		current_distance = l_distances[current_index];
		current_node = l_nodes[current_index];
		Box = current_node->getBoundingBox();
		current_node->setVisible(true);
	}else{
		if (current_index+1 < l_distances.size() && distance > l_distances[current_index+1]){
			// increase mesh
			current_node->setVisible(false);
			current_index++;

			current_distance = l_distances[current_index];
			current_node = l_nodes[current_index];
			Box = current_node->getBoundingBox();
			current_node->setVisible(true);
			
			std::cout << current_node->getMesh()->getMesh(0)->getMeshBuffer(0)->getVertexCount() << " " ;
		}		
	}
}

// implementation of IAnimatedMeshSceneNode
void LOD_Animated_scenenode::setMesh(irr::scene::IAnimatedMesh *m){
	// don't do anything. meshes have been set on the constructor, cannot change them
}

void LOD_Animated_scenenode::setCurrentFrame(irr::s32 f){
	// set the current frame for all the meshes
	std::vector<irr::scene::IAnimatedMeshSceneNode*>::iterator i;
	for (i=l_nodes.begin(); i!=l_nodes.end(); i++)
		(*i)->setCurrentFrame(f);
}

bool LOD_Animated_scenenode::setFrameLoop(irr::s32 b, irr::s32 f){
	bool r = true;
	std::vector<irr::scene::IAnimatedMeshSceneNode*>::iterator i;
	for (i=l_nodes.begin(); i!=l_nodes.end(); i++)
		if ((*i)->setFrameLoop(b,f) == false)
			r = false;
	
	return r;
}

void LOD_Animated_scenenode::setAnimationSpeed(irr::s32 f){
	std::vector<irr::scene::IAnimatedMeshSceneNode*>::iterator i;
	for (i=l_nodes.begin(); i!=l_nodes.end(); i++)
		(*i)->setAnimationSpeed(f);
}

irr::scene::IShadowVolumeSceneNode* LOD_Animated_scenenode::addShadowVolumeSceneNode(irr::s32 id, bool zfailmethod, irr::f32 infinity){
	return current_node->addShadowVolumeSceneNode(id, zfailmethod, infinity);
}

irr::scene::ISceneNode* LOD_Animated_scenenode::getMS3DJointNode(const irr::c8 *i){
	return current_node->getMS3DJointNode(i);
}

irr::scene::ISceneNode* LOD_Animated_scenenode::getXJointNode(const irr::c8 *i){
	return current_node->getXJointNode(i);
}

irr::scene::ISceneNode* LOD_Animated_scenenode::getB3DJointNode(const irr::c8 *i){
	return current_node->getB3DJointNode(i);
}

bool LOD_Animated_scenenode::setMD2Animation(irr::scene::EMD2_ANIMATION_TYPE a){
	bool r = true;
	std::vector<irr::scene::IAnimatedMeshSceneNode*>::iterator i;
	for (i=l_nodes.begin(); i!=l_nodes.end(); i++)
		if ((*i)->setMD2Animation(a) == false)
			r = false;

	return r;
}

bool LOD_Animated_scenenode::setMD2Animation(const irr::c8 *c){
	bool r = true;
	std::vector<irr::scene::IAnimatedMeshSceneNode*>::iterator i;
	for (i=l_nodes.begin(); i!=l_nodes.end(); i++)
		if ( (*i)->setMD2Animation(c) == false)
			r = false;

	return r;
}

irr::s32 LOD_Animated_scenenode::getFrameNr(){
	return current_node->getFrameNr();
}

void LOD_Animated_scenenode::setLoopMode(bool b){
	std::vector<irr::scene::IAnimatedMeshSceneNode*>::iterator i;
	for (i=l_nodes.begin(); i!=l_nodes.end(); i++)
		(*i)->setLoopMode(b);
}

void LOD_Animated_scenenode::setAnimationEndCallback(irr::scene::IAnimationEndCallBack* callback){
	std::vector<irr::scene::IAnimatedMeshSceneNode*>::iterator i;
	for (i=l_nodes.begin(); i!=l_nodes.end(); i++)
		(*i)->setAnimationEndCallback(callback);
}

void LOD_Animated_scenenode::setReadOnlyMaterials(bool b){
	std::vector<irr::scene::IAnimatedMeshSceneNode*>::iterator i;
	for (i=l_nodes.begin(); i!=l_nodes.end(); i++)
		(*i)->setReadOnlyMaterials(b);
}

bool LOD_Animated_scenenode::isReadOnlyMaterials(){
	return current_node->isReadOnlyMaterials();
}

irr::scene::IAnimatedMesh* LOD_Animated_scenenode::getMesh(void){
	return current_node->getMesh();
}

void LOD_Animated_scenenode::setMaterialTexture(irr::s32 s, irr::video::ITexture* t){
	std::vector<irr::scene::IAnimatedMeshSceneNode*>::iterator i;
	for (i=l_nodes.begin(); i!=l_nodes.end(); i++)
		(*i)->setMaterialTexture(s, t);
}

void LOD_Animated_scenenode::setMaterialFlag(irr::video::E_MATERIAL_FLAG f, bool b){
	std::vector<irr::scene::IAnimatedMeshSceneNode*>::iterator i;
	for (i=l_nodes.begin(); i!=l_nodes.end(); i++)
		(*i)->setMaterialFlag(f,b);
}