#pragma once

#include <vector>

#include <C2/lm/range3.h>
#include <C2/lm/vector3.h>
#include <C2/lm/cubic_vmatrix.h>


namespace lib_geo
{


//! UniformGrid内の1セル
class UniformGridCell
{
public:
	std::vector<int>  indices; //!< セルに登録されたインデックス列
	lm::range3f       range;   //!< セルのAABB
};


//! 衝突計算の空間分割に使用する均一格子.
//  格子内のセルにインデックスを登録する機能と
//  指定範囲と接触する可能性のあるインデックス列を求める機能.
class UniformGrid
{
public:
	// バッファクリア
	void Clear(void);
	void ClearRange(void);
	void ClearGrid(void);


	// グリッド生成
	void Expand( const lm::vec3f& pos );
	void Expand( const lm::range3f& range );

	void CreateGrid( size_t sx , size_t sy , size_t sz );
	void AddIndex( int index , const lm::vec3f& pos );
	void AddIndex( int index , const lm::range3f& range );


	// データ参照
	void GetCells( const lm::vec3f& pos , std::vector<UniformGridCell*>& cells );
	void GetCells( const lm::vec3f& pos , std::vector<const UniformGridCell*>& cells ) const;

	void GetCells( const lm::range3f& range , std::vector<const UniformGridCell*>& cells ) const;
	void GetCells( const lm::range3f& range , std::vector<UniformGridCell*>& cells );

	void GetIndices( const lm::vec3f& pos , std::vector<int>& indices ) const;
	void GetIndices( const lm::range3f& range , std::vector<int>& indices ) const;


	// accessor
	size_t GetNumCellX(void) const { return m_Grid.size_x(); }
	size_t GetNumCellY(void) const { return m_Grid.size_y(); }
	size_t GetNumCellZ(void) const { return m_Grid.size_z(); }

	lm::range3f& GetRange(void) { return m_TotalRange; }
	const lm::range3f& GetRange(void) const { return m_TotalRange; }

	UniformGridCell& GetCell( size_t idx_x , size_t idx_y , size_t idx_z ){ return m_Grid( idx_x , idx_y , idx_z ); }
	const UniformGridCell& GetCell( size_t idx_x , size_t idx_y , size_t idx_z ) const { return m_Grid( idx_x , idx_y , idx_z ); }

	void GetCellIndex( const lm::vec3f& pos , int& ix , int& iy , int& iz ) const;
	void GetCellIndex( const lm::range3f& range , int& ix0 , int& ix1 , int& iy0 , int& iy1 , int& iz0 , int& iz1 ) const;


protected:
	void GetIndicesFromMatrixIndex( std::vector<int>& indices , int ix0 , int ix1 , int iy0 , int iy1 , int iz0 , int iz1 ) const;


protected:
	lm::cubic_matrix<UniformGridCell> m_Grid;       //!< グリッド
	lm::range3f                       m_TotalRange; //!< グリッド全体のサイズ
};


}
