#pragma once

#include "Mix/Private/Container.h"
#include "Mix/Geometry/Sphere.h"
#include "Mix/Private/Scene/Common/OctreeTypes.h"
#include "Mix/Private/Scene/Common/OctreeObject.h"

namespace Mix{ namespace Scene{ namespace Common{

	class Octree;
	class LeavingParticleObject;
	class ActorModelObject;

	class OctreeView
	{
	private:
		Mix::Scene::Common::Octree* m_pOwner;
		Mix::Scene::Common::OCTREE_VIEW_DATA m_Data;

		UInt32 m_NxtClearMask;

		Mix::ContainerT<Mix::Scene::Common::LeavingParticleObject*, Mix::Memory::SECTION_SCENE> m_ValidLeavingParticleObjects;
		Mix::ContainerT<Mix::Scene::Common::ActorModelObject*, Mix::Memory::SECTION_SCENE> m_ValidActorModelObjects;

	private:
		OctreeView( Mix::Scene::Common::Octree* pOwner, const Mix::Scene::Common::OCTREE_VIEW_DATA& data, const wchar_t* pDebugName );
		~OctreeView( void );

		//このビューが有効(使用された)であることを通知
		void Valid( Mix::Scene::Common::OCTREE_VIEW_TYPE type );

		//オブジェクトの破棄
		void DestroyObject( Mix::Scene::Common::LeavingParticleObject* pObj );
		void DestroyObject( Mix::Scene::Common::ActorModelObject* pObj );

		//SC→S→C でソート
		template<typename T>
		static void SortValidObjects( T** list, Int32 first, Int32 last, UInt32 mask )
		{
			const T* pObj = list[( first + last ) >> 1];

			UInt32 sortKey = ( pObj->m_NxtState & mask );

			Int32 i = first;
			Int32 j = last;

			do
			{
				while( ( list[i]->m_NxtState & mask ) > sortKey ) { i++; }
				while( ( list[j]->m_NxtState & mask ) < sortKey ) { j--; }

				if( i <= j )
				{
					MIX_ASSERT( ( i <= last ) && ( j >= first ) );

					T* pTempObj = list[i];

					list[i] = list[j];
					list[j] = pTempObj;

					i++;
					j--;
				}

			}while( i <= j );

			if( first < j ) { OctreeView::SortValidObjects( list, first, j, mask ); }
			if( i < last ) { OctreeView::SortValidObjects( list, i, last, mask ); }
		}

		//フィニッシュ : ステートの適用
		template<typename T>
		static UInt32 ApplyStateObjects( Mix::ContainerT<T*, Mix::Memory::SECTION_SCENE>& list, UInt32 mask, UInt32 invMask, UInt32 nxtClearMask )
		{
			T** ppObj = list.GetBeginPtr();
			T** ppObjEnd = list.GetEndPtr();
			UInt32 validCount = 0;
			UInt32 curState;
			UInt32 nxtState;
			T* pObj;

			//有効なもの
			while( ( ppObj != ppObjEnd ) && ( ( ( *ppObj )->m_NxtState & mask ) != 0 ) )
			{
				pObj = *ppObj;

				curState = pObj->m_CurState;
				nxtState = pObj->m_NxtState & nxtClearMask;
//				nxtState = pObj->m_NxtState;

				pObj->m_CurState = ( curState & invMask ) | ( nxtState & mask );
//				pObj->m_NxtState = nxtState & invMask;

				validCount++;
				ppObj++;
			}

			//無効なもの
			while( ppObj != ppObjEnd )
			{
				pObj = *ppObj;

				curState = pObj->m_CurState;
				nxtState = pObj->m_NxtState & nxtClearMask;
//				nxtState = pObj->m_NxtState;

				pObj->m_CurState = ( curState & invMask ) | ( nxtState & mask );
//				pObj->m_NxtState = nxtState & invMask;

				ppObj++;
			}

			return validCount;
		}

		//すべてのオブジェクトの無効化
		template<typename T>
		static void InvalidateObjects( Mix::ContainerT<T*, Mix::Memory::SECTION_SCENE>& list, UInt32 invMask )
		{
			T** ppObj = list.GetBeginPtr();
			T** ppObjEnd = list.GetEndPtr();
			T* pObj;

			while( ppObj != ppObjEnd )
			{
				pObj = *ppObj;

				pObj->m_CurState &= invMask;
				pObj->m_NxtState &= invMask;

				ppObj++;
			}
		}

	public:
		UInt32 GetID( void ) const;

		void Switch( void );
		void Finish( void );
		void Destroy( void );

#ifdef _DEBUG
		Boolean Debug_HasValidObjects( void ) const;
#endif //_DEBUG

	private:
		static const UInt32 V_OBJECTS_DEF_SIZE;
		static const UInt32 V_OBJECTS_RESIZE_STEP;

		friend class Octree;
	};

}}}
