#include "stdafx.h"
#include "map_manager.h"
#include "inventoryowner.h"
#include "level.h"
#include "actor.h"
#include "GameObject.h"
#include "map_location.h"
#include "xrServer.h"
#include "game_object_space.h"

struct FindLocationBySpotID{
	shared_str	spot_id;
	u16			object_id;
	FindLocationBySpotID(const shared_str& s, u16 id):spot_id(s),object_id(id){}
	bool operator () (const SLocationKey& key){
		return (spot_id==key.spot_type)&&(object_id==key.object_id);
	}
};
struct FindLocationByID{
	u16			object_id;
	FindLocationByID(u16 id):object_id(id){}
	bool operator () (const SLocationKey& key){
		return (object_id==key.object_id);
	}
};

struct FindLocation{
	CMapLocation*			ml;
	FindLocation(CMapLocation* m):ml(m){}
	bool operator () (const SLocationKey& key){
		return (ml==key.location);
	}
};

void SLocationKey::save(IWriter &stream)
{
	stream.w		(&object_id,sizeof(object_id));

	stream.w_stringZ(spot_type);
	stream.w_u8		(0);
	location->save	(stream);
}
	
void SLocationKey::load(IReader &stream)
{
	stream.r		(&object_id,sizeof(object_id));

	stream.r_stringZ(spot_type);
	stream.r_u8		();

	location  = xr_new<CMapLocation>(*spot_type, object_id);

	location->load	(stream);
}

void SLocationKey::destroy()
{
	delete_data(location);
}


CMapManager::CMapManager()
{
}

CMapManager::~CMapManager()
{
	delete_data		(m_deffered_destroy_queue); //from prev frame
}

CMapLocation* CMapManager::AddMapLocation(const shared_str& spot_type, u16 id)
{
	CMapLocation* l = xr_new<CMapLocation>(spot_type.c_str(), id);
	Locations().push_back( SLocationKey(spot_type, id) );
	Locations().back().location = l;
	return l;
}

void CMapManager::Destroy(CMapLocation* ml)
{
	m_deffered_destroy_queue.push_back(ml);
}

void CMapManager::RemoveMapLocation(const shared_str& spot_type, u16 id)
{
	FindLocationBySpotID key(spot_type, id);
	Locations_it it = std::find_if(Locations().begin(),Locations().end(),key);
	if( it!=Locations().end() )
	{
		Destroy					((*it).location);
		Locations().erase		(it);
	}
}

void CMapManager::RemoveMapLocationByObjectID(u16 id) //call on destroy object
{
	FindLocationByID key(id);
	Locations_it it = std::find_if(Locations().begin(), Locations().end(), key);
	while( it!= Locations().end() )
	{
		Destroy					((*it).location);
		Locations().erase		(it);

		it = std::find_if(Locations().begin(), Locations().end(), key);
	}
}

void CMapManager::RemoveMapLocation(CMapLocation* ml)
{
	FindLocation key(ml);

	Locations_it it = std::find_if(Locations().begin(), Locations().end(), key);
	if( it!=Locations().end() )
	{
		Destroy					((*it).location);
		Locations().erase		(it);
	}

}

bool CMapManager::GetMapLocationsForObject(u16 id, xr_vector<CMapLocation*>& res)
{
	res.clear_not_free		();
	Locations_it it			= Locations().begin();
	Locations_it it_e		= Locations().end();
	for(; it!=it_e;++it)
	{
		if((*it).actual && (*it).object_id==id)
			res.push_back((*it).location);
	}
	return (res.size()!=0);
}

bool CMapManager::HasMapLocation(const shared_str& spot_type, u16 id)
{
	CMapLocation* l = GetMapLocation(spot_type, id);
	
	return (l!=NULL);
}

CMapLocation* CMapManager::GetMapLocation(const shared_str& spot_type, u16 id)
{
	FindLocationBySpotID key(spot_type, id);
	Locations_it it = std::find_if(Locations().begin(), Locations().end(), key);
	if( it!=Locations().end() )
		return (*it).location;
	
	return 0;
}

void CMapManager::GetMapLocations(const shared_str& spot_type, u16 id, xr_vector<CMapLocation*>& res)
{
	FindLocationBySpotID key(spot_type, id);
	Locations_it it = std::find_if(Locations().begin(), Locations().end(), key);
	
	while( it!=Locations().end() )
	{
		res.push_back((*it).location);
		it = std::find_if(++it, Locations().end(), key);
	}
}

void CMapManager::Update()
{
	delete_data(m_deffered_destroy_queue); //from prev frame

	Locations_it it			= Locations().begin();
	Locations_it it_e		= Locations().end();

	for(u32 idx=0; it!=it_e;++it,++idx)
	{
		bool bForce		= Device.dwFrame%3 == idx%3;
		(*it).actual	= (*it).location->Update();

		if((*it).actual && bForce)
			(*it).location->CalcPosition();
	}
	std::sort( Locations().begin(),Locations().end() );

	while( (!Locations().empty())&&(!Locations().back().actual) )
	{
		Destroy					(Locations().back().location);
		Locations().pop_back();
	}
}

void CMapManager::DisableAllPointers()
{
	Locations_it it = Locations().begin();
	Locations_it it_e = Locations().end();

	for(; it!=it_e;++it)
		(*it).location->DisablePointer	();
}


Locations&	CMapManager::Locations	() 
{
	return m_locations;
}

void CMapManager::OnObjectDestroyNotify(u16 id)
{
	RemoveMapLocationByObjectID(id);
}

#ifdef DEBUG
void CMapManager::Dump						()
{
	Msg("begin of map_locations dump");
	Locations_it it = Locations().begin();
	Locations_it it_e = Locations().end();
	for(; it!=it_e;++it)
	{
		Msg("spot_type=[%s] object_id=[%d]",*((*it).spot_type), (*it).object_id);
		(*it).location->Dump();
	}

	Msg("end of map_locations dump");
}
#endif