//------------------------------------------------------------------------------
// 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/System/CollisionNode.h"
#include "Collision/System/CollisionScene.h"

namespace Lamp{

//------------------------------------------------------------------------------
// 生成、破棄
//------------------------------------------------------------------------------
// コンストラクタ
CollisionNode::CollisionNode(const String& name, CollisionScene* scene) :
	CollisionObject(name, scene), worldMatrix_(Matrix34::unit),
	globalScaled_(false){
	setGlobalEnabled(true);
}
//------------------------------------------------------------------------------
// デストラクタ
CollisionNode::~CollisionNode(){
}
//------------------------------------------------------------------------------
// コピー
//------------------------------------------------------------------------------
// コリジョンノードのコピー
CollisionNode* CollisionNode::copyCollisionNode() const{
	CollisionNode* destination =
		getScene()->createCollisionNode(getScene()->renameNode(getName()));
	// コリジョンオブジェクトの値をコピー
	copyCollisionObjectValue(destination);
	// メンバのコピー
	destination->axis_ = axis_;
	// 子供のコピー
	int childCount = getChildCount();
	for(int i = 0; i < childCount; i++){
		destination->addChild(getChild(i)->copy());
	}
	return destination;
}
//------------------------------------------------------------------------------
// 再帰的破棄
int CollisionNode::recursiveDestroy(CollisionNode* collisionNode){
	CollisionScene* scene = collisionNode->getScene();
	Assert(collisionNode != scene->getRootNode());
	int result = recursiveDestroyChildren(collisionNode);
	// 親から削除
	CollisionNode* parent = collisionNode->getParent();
	if(parent != NULL){ parent->removeChild(collisionNode); }
	// 引数の破棄
	scene->destroyNode(collisionNode);
	result++;
	return result;
}
//------------------------------------------------------------------------------
// 子の再帰的破棄
int CollisionNode::recursiveDestroyChildren(CollisionNode* collisionNode){
	Assert(collisionNode != NULL);
	int result = 0;
	// 子の破棄
	int childCount = collisionNode->getChildCount();
	for(int i = childCount - 1; i >= 0; i--){
		result += CollisionObject::recursiveDestroy(collisionNode->getChild(i));
	}
	return result;
}
//------------------------------------------------------------------------------
// 走査
//------------------------------------------------------------------------------
// 走査
void CollisionNode::traverseImplement(const Matrix34& parentMatrix,
	bool parentEnabled, bool parentScaled, bool parentChanged){
	// グローバル有効フラグ設定
	bool preGlobalEnabled = isGlobalEnabled();
	bool globalEnabled = (parentEnabled && isEnabled());
	setGlobalEnabled(globalEnabled);
	// 前回がdisabledでdisabledのままならトラバースしない
	if((!preGlobalEnabled) && (!globalEnabled)){ return; }

	// 変更フラグ
	bool globalChanged = (isChanged() || parentChanged);
	setGlobalChanged(globalChanged);
	// 変更フラグのリセット
	setChanged(false);

	// グローバルスケールフラグ設定
	bool globalScaled = (parentScaled || isScaled());
	setGlobalScaled(globalScaled);

	// 行列の計算、ここでaxis_のchangedはリセットされる
	axis_.buildMatrix();
	if(globalChanged){
		worldMatrix_ = parentMatrix * getLocalMatrix();
	}else{
		Assert((parentMatrix * getLocalMatrix()).epsilonEquals(
			worldMatrix_, 0.0001f));
	}

	// 子供を呼ぶ
	int childCount = getChildCount();
	for(int i = 0; i < childCount; i++){
		getChild(i)->traverseImplement(worldMatrix_,
			globalEnabled, globalScaled, globalChanged);
	}
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
