#include "ats_BoidGroup.h"
#include "ats_Boid.h"
#include <list>

using namespace std;
using namespace ats;

// コンストラクタ・デストラクタ ------------------------------------------------------------
BoidGroup::BoidGroup(BoundingFrame* f)
{
	if(f){
		m_bounding_frame = f;
	} else {
		throw boid_exception("BoidGroupのコンストラクタはnullポインタを受け付けません。");
	}
}

BoidGroup::~BoidGroup()
{
	for(list<Obj3DD*>::iterator itr=Begin(); itr != End(); itr++){
		delete *itr;
	}
	delete m_bounding_frame;
}


// 位置へのアクセッサ ----------------------------------------------------------------------
const Point3D& BoidGroup::Center() const
{
	return m_center;
}

// 向きへのアクセッサ ------------------------------------------------------------------

const Point3D& BoidGroup::Muki() const
{
	return m_muki;
}

void BoidGroup::Add(Obj3DD *a)
{
	Group3DD::Add(a);

	// Boidであれば親と双方向にアクセスできるようにしておく。
	Boid* b = dynamic_cast<Boid*>(a);
	if(b){
		b->SetParent(this);
	}
}

// フレームアップデート ---------------------------------------------------------------
void BoidGroup::UpdateTime(double time)
{
	for(list<Obj3DD*>::iterator itr=Begin(); itr != End(); itr++){
		(*itr)->UpdateTime(time);
	}

	UpdateSelf(); // グループの平均を計算
}

// グループの位置をアップデート -----------------------------------------------------
void BoidGroup::UpdateSelf()
{
	// 位置と向きと速度を初期化
	m_center.SetXYZ(0,0,0);
	m_muki.SetXYZ(0,0,0);

	// 登録されているオブジェクトの位置と向きを足し合わせる
	for(list<Obj3DD*>::iterator itr=Begin(); itr != End(); itr++){
		// Boidかどうかテスト
		// ポインタを指すイテレータであるから**で実体。
		// 0ならばキャスト失敗
		Boid* b = dynamic_cast<Boid*>(*itr);
		if(b){
			m_center += b->GetCenter();
			m_muki   += b->GetMuki();
		}
	}

	// 平均化
	m_center /= Size();
	m_muki /= Size();
	// 正規化
	m_muki.Normalize();
}


const BoundingFrame& BoidGroup::GetBoundingFrame() const
{
	return *m_bounding_frame;
}

void BoidGroup::SetBoundingFrame(BoundingFrame* a)
{
	if(a){ // nullチェック
		delete m_bounding_frame;
		m_bounding_frame = a;
	}
}

// 中心を描画してあとは基底クラスに任せる --------------------------------------------------
void BoidGroup::Draw()
{
	// 基底クラスに丸投げ
	Group3DD::Draw();

	/*
	Point3D tmp(m_muki + m_center);
	// 描画するのは位置から方向(速度は無視)
	glDisable(GL_LIGHTING);
	glBegin(GL_LINES);
		//glColor3f(1,0,0);
		//glVertex3d(m_center.X(), m_center.Y(), m_center.Z());
		glColor3f(0,0,0);
		glVertex3d(tmp.X(), tmp.Y(), tmp.Z());
	glEnd();
	glEnable(GL_LIGHTING);
	*/
}

// 最も近い同士を計算してやる -------------------------------------------------------------
// キャストの嵐・・・なんとかならない？
/*
template<class TBOID>
void BoidGroup::CalcNear()
{
	
	// 各個体の知る"近い奴"の記録を初期化
	for(list<Obj3DD*>::iterator itr=Begin(); itr != End(); itr++){
		if(typeid(TBOID) == typeid(**itr)){
			dynamic_cast<TBOID*>(*itr)->SetNear(0);
		}
	}

	int count = 0;
	for(itr=Begin(); itr != End(); itr++){
		// すでに最も近い相手が見つかってれば飛ばす。
		if(dynamic_cast<TBOID*>(*itr)->IsNear() == false){
			Obj3DD* min_obj = 0;
			for(list<Obj3DD*>::iterator itr2=Begin(); itr2 != End(); itr2++){
				// Boidかどうかテスト
				// ポインタを指すイテレータであるから**で実体。
				if(typeid(TBOID) == typeid(**itr) && typeid(TBOID) == typeid(**itr2)){
					double min = std::numeric_limits<double>::infinity();
					// 2点間の距離 (A-B).Length()
					double tmp = (dynamic_cast<TBOID*>(*itr)->GetCenter()-dynamic_cast<TBOID*>(*itr2)->GetCenter()).Length();
					if(min > tmp){
						min_obj = *itr2; // オブジェクトをセーブして
						min = tmp;       // 距離もセーブする。
					}
				}
			}
			// その上ダウンキャスト！いいのか？
			if(typeid(TBOID) == typeid(**itr) && typeid(TBOID) == typeid(*min_obj)){
				dynamic_cast<TBOID*>(*itr)->SetNear(dynamic_cast<TBOID*>(min_obj));  // 最も近かったオブジェクトを記憶。
				dynamic_cast<TBOID*>(min_obj)->SetNear(dynamic_cast<TBOID*>(*itr));    // 相手にも記憶。
			}
		}
	}
}
*/
