//------------------------------------------------------------------------------
// 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
 */

#ifndef AXIS_3_H_
#define AXIS_3_H_

#include <Core/Primitive/Matrix34.h>
#include <Core/Primitive/Vector3.h>
#include <Core/Primitive/Quaternion.h>

namespace Lamp{

//------------------------------------------------------------------------------
/**
 * 三次元軸
 */
class Axis3{
public:
	/**
	 * コンストラクタ
	 */
	Axis3() : matrix_(Matrix34::unit), quaternion_(Quaternion::identity),
		scale_(Vector3::unitScale), euler_(Vector3::zero),
		translation_(Vector3::zero),
		validEuler_(true), validQuaternion_(true), isChanged_(true){
		// isChanged_(true) 初回の計算は強要する
	}

	/**
	 * コピーコンストラクタ
	 * @param source コピー元
	 */
	Axis3(const Axis3& source) : matrix_(source.matrix_),
		quaternion_(source.quaternion_), scale_(source.scale_),
		euler_(source.euler_), translation_(source.translation_),
		validEuler_(source.validEuler_),
		validQuaternion_(source.validQuaternion_), isChanged_(true){
		// isChanged_(true) 初回の計算は強要する
	}

	/**
	 * デストラクタ
	 */
	virtual ~Axis3(){}

	//--------------------------------------------------------------------------
	/**
	 * スケールの設定
	 * @param scale スケール
	 */
	virtual void setScale(const Vector3& scale){
		if(scale_ == scale){ return; }
		scale_ = scale;
		isChanged_ = true;
	}

	/**
	 * スケールの取得
	 * @return スケール
	 */
	virtual const Vector3& getScale() const{ return scale_; }

	/**
	 * スケールを使用しているか
	 * @return スケールを使用しているならtrue
	 */
	virtual bool isScaled() const{ return (scale_ != Vector3::unitScale); }

	//--------------------------------------------------------------------------
	/**
	 * XYZ回転の設定
	 * @param rotation XYZ回転
	 */
	virtual void setRotationXYZ(const Vector3& rotation){
		if(validEuler_ && (euler_ == rotation)){ return; }
		euler_ = rotation;
		validEuler_ = true;
		validQuaternion_ = false;
		isChanged_ = true;
	}

	/**
	 * XYZ回転の取得
	 * @return XYZ回転
	 */
	virtual const Vector3& getRotationXYZ(){
		if(!validEuler_){
			quaternion_.getRotationXYZ(&euler_);
			validEuler_ = true;
		}
		return euler_;
	}

	//--------------------------------------------------------------------------
	/**
	 * 四元数回転の設定
	 * @param rotation 四元数回転
	 */
	virtual void setRotationQuaternion(const Quaternion& rotation){
		if(validQuaternion_ && (quaternion_ == rotation)){ return; }
		quaternion_ = rotation;
		validEuler_ = false;
		validQuaternion_ = true;
		isChanged_ = true;
	}

	/**
	 * 四元数回転の取得
	 * @return 四元数回転
	 */
	virtual const Quaternion& getRotationQuaternion(){
		if(!validQuaternion_){
			quaternion_.setRotationXYZ(euler_);
			validQuaternion_ = true;
		}
		return quaternion_;
	}

	//--------------------------------------------------------------------------
	/**
	 * 移動の設定
	 * @param translation 移動
	 */
	virtual void setTranslation(const Vector3& translation){
		if(translation_ == translation){ return; }
		translation_ = translation;
		isChanged_ = true;
	}

	/**
	 * 移動の取得
	 * @return 移動
	 */
	virtual const Vector3& getTranslation() const{ return translation_; }

	//--------------------------------------------------------------------------
	/**
	 * 行列の構築
	 * @return 再構築したならばtrue
	 */
	virtual bool buildMatrix(){
		if(isChanged_){
			if(validQuaternion_){
				matrix_.setTransformationQuaternion(
					scale_, quaternion_, translation_);
			}else{
				Assert(validEuler_);
				matrix_.setTransformationXYZ(scale_, euler_, translation_);
			}
			isChanged_ = false;
			return true;
		}
		return false;
	}

	/**
	 * 行列の取得
	 * @return 行列
	 */
	virtual const Matrix34& getMatrix() const{
		Assert(!isChanged_);
		return matrix_;
	}

	//--------------------------------------------------------------------------
	/**
	 * 軸が変更されているか
	 * @return 軸が変更されていればtrue
	 */
	virtual bool isChanged() const{ return isChanged_; }

	//--------------------------------------------------------------------------
protected:
	/// 行列
	Matrix34 matrix_;
	/// 四元数回転
	Quaternion quaternion_;
	/// スケール
	Vector3 scale_;
	/// オイラー回転
	Vector3 euler_;
	/// 移動
	Vector3 translation_;
	/// オイラー回転が有効か
	bool validEuler_;
	/// 四元数回転が有効か
	bool validQuaternion_;
	/// 変更フラグ
	bool isChanged_;

};

//------------------------------------------------------------------------------
} // End of namespace Lamp
#endif // End of AXIS_3_H_
//------------------------------------------------------------------------------
