//CObjectManager.cpp


#include <winsock2.h>
#include <iostream.h> // include important C/C++ stuff
#include <conio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h> 
#include <math.h>
#include <io.h>
#include <fcntl.h>
#include <fstream>
#include <cstdlib>


#include "CObjectManager.h"
#include "CGraphicSystem.h"

#include "CMap.h"
#include "CPlayerObject.h"
#include "CBlockObject.h"
#include "CBombObject.h"
#include "CExplosionObject.h"
#include "CAIPlayerObject.h"
#include "CAIBombDangerZone.h"
	/**********************/


bool CObjectManager::Init()
{	

	TotalObjects=0;
	return true;

}

void CObjectManager::Clear()
{

}

///////////////////////////////////////////

/******
This will create an object, put it in the list. That way we dont have to delete anything at the end (ObjectManager does that)
******/


CGameObject* CObjectManager::CreateObject(ObjectType typ)
{
	
	CGameObject* obj;
	STRINGC typeS;

	switch(typ)
	{	

	case typMap:

		obj = new CMap();
		typeS="Map";
		obj->setCheckCollision(false);
		
		break;

	case typPlayer:

		obj = new CPlayerObject();
		CollisionObjects.push_back(obj);
		obj->setCheckCollision(true);

		typeS="Player";

		break;

	case typBlock:

		obj = new CBlockObject();
		obj->setCheckCollision(false);
		typeS="Block";

		break;

	case typBomb:

		obj = new CBombObject();
		CollisionObjects.push_back(obj);
		obj->setCheckCollision(true);

		typeS="Bomb";

		break;

	case typExplosion:

		obj = new CExplosionObject();
		CollisionObjects.push_back(obj);
		obj->setCheckCollision(true);

		typeS="Explosion";

		break;
	
	case typAIPlayer:
	
		obj = new CAIPlayerObject();
		CollisionObjects.push_back(obj);
		obj->setCheckCollision(true);

		typeS="AIPlayer";
						 
		 break;

	case typAIBombDangerZone:

		obj = new CAIBombDangerZone();
		CollisionObjects.push_back(obj);
		obj->setCheckCollision(false);

		break;
		
	default:
			
		Assert(false,"Unknown object type")
		typeS="ERROR";

		break;

	}

	

	obj->ID=++TotalObjects;	//give it unique ID
	insertObject(obj);

	g_Console.AddMessage(STRINGC("Created Object: ") + typeS + STRINGC(". ID: ") + TotalObjects,3);

	return obj;
	

}

ObjectType CObjectManager::getObjTypeFromInt(int i)
{

	if(i==0)
		return typMap;

	if(i==1)
		return typPlayer;
	
	if(i==2)
		return typBlock;
	
	if(i==3)
		return typBomb;

	if(i==4)
		return typExplosion;
	
	if(i==5)
		return typAIPlayer;		
	
	Assert(false,STRINGC("Unknown object type: ") + STRINGC(i));
	return typMap;

}


int CObjectManager::getIntFromObjType(ObjectType o)
{
	if(o==typMap)
		return 0;

	if(o==typPlayer)
		return 1;
	
	if(o==typBlock)
		return 2;
	
	if(o==typBomb)
		return 3;

	if(o==typExplosion)
		return 4;
	
	if(o==typAIPlayer)
		return 5;		
	
	Assert(false,STRINGC("Unknown object type: "));
	return -1;
	
}


//////////////////////////////////////////////////////////////


void CObjectManager::insertObject(CGameObject* obj)
{
	Objects.push_back(obj);
}

void CObjectManager::DestroyObject(CGameObject* obj)
{
	if(obj==NULL)
		return;

	
	//check collision
	for(ObjectListIterator CollisionItor = CollisionObjects.begin(); CollisionItor != CollisionObjects.end() ; ++CollisionItor)
	{
		if((*CollisionItor)->ID==obj->ID)
		{						
			CollisionItor = CollisionObjects.erase(CollisionItor);									
		}
	}



	for(ObjectListIterator itor = Objects.begin(); itor != Objects.end() ; ++itor)
	{
		if((*itor)->ID==obj->ID)
		{
			
			(*itor)->Shutdown();
			delete (*itor);
			itor = Objects.erase(itor);			
			g_Console.AddMessage(STRINGC("Object Deleted. Current Number of Objects: ") + STRINGC((int)Objects.size()),3);
			//Assert(false,"deleted object")
			return;
			
		}
	}

	
	
}


void CObjectManager::RemoveObjectSafe(int ID)
{
	m_ObjectsToBeRemoved.push_front(ID);

}

void CObjectManager::RemoveObjectsInQueue()
{

	//OPTIMIZE!!!

	for(ObjectIDListIterator itor = m_ObjectsToBeRemoved.begin(); itor != m_ObjectsToBeRemoved.end() ; ++itor)
	{
		DestroyObject(GetObjectID((*itor)));
		
	}




}



CGameObject* CObjectManager::GetObjectID(int ID)
{
	

	CGameObject* obj=NULL;

	for(ObjectListIterator itor = Objects.begin(); itor != Objects.end() ; ++itor)
	{
		if((*itor)->ID == ID)
		{
			obj = (*itor);
			break;

		}
	}

	return obj;

}

CGameObject* CObjectManager::GetObjectType(ObjectType objTyp)
{
	//Just like above

	CGameObject* obj=NULL;

	for(ObjectListIterator itor = Objects.begin(); itor != Objects.end() ; ++itor)
	{
		if((*itor)->typ == objTyp)
		{
			obj = (*itor);
			return obj;

		}
	}

	return obj;

}


//////////////////////////////////////////////////////////////////


void CObjectManager::updateObjects()
{

	for(ObjectListIterator itor = Objects.begin(); itor != Objects.end() ; ++itor)
	{	

		if(*itor)
		{
						
			(*itor)->Update();
			
		}
	}
}

////////////////////////////////////////////

void CObjectManager::drawObjects()
{

	for(ObjectListIterator itor = Objects.begin(); itor != Objects.end() ; ++itor)
	{	


		if(*itor)
		{
						
			(*itor)->Draw();									

		}

	}


}


////////////////////////////////////////////

void CObjectManager::collisionDetect()
{
	//Bad C++ OPTIMIZE THIS!!!

	
	for(ObjectListIterator itor = CollisionObjects.begin(); itor !=CollisionObjects.end() ; ++itor)
	{	
		if(*itor)
		{			
			for(ObjectListIterator itor2 = Objects.begin(); itor2 != Objects.end() ; ++itor2)
			{	

				if((*itor2)->ID!=(*itor)->ID)
				{				

					if((*itor)->isInside((*itor2)))
					{

						//g_Console.AddMessage("Collision!");
					
						(*itor)->Collision((*itor2));


						if((*itor2)->getCheckCollision()==false)
						{
							(*itor2)->Collision((*itor));
						}
					}
				}

			}									
		}

	}
}

///////////////////////////////////////////


void CObjectManager::ShutDown()
{
	//lists do not destory objects by default
	for(ObjectListIterator itor = Objects.begin(); itor != Objects.end() ; ++itor)
	{
		(*itor)->Shutdown();
		delete (*itor);
	}
	
	

}

///////////////////////////////////////////

CAIMap* CObjectManager::getAIMap()
{
	CMap* map = (CMap*)this->GetObjectType(typMap);

	int		tileSize	= map->TileWidth;
	int		mapWidth	= map->Width;
	int		mapHeight	= map->Height;

	POINT	anchor=map->getAnchor();

	CAIMap* AIMap = new CAIMap(mapWidth, mapHeight);
	int* data = AIMap->getData();

	for(int x=0; x < mapWidth; x++)
	{
		for(int y=0; y < mapHeight; y++)
		{
			data[x + (y * mapWidth)]=0;
		}
	}

	

	for(ObjectListIterator itor = Objects.begin(); itor != Objects.end() ; ++itor)
	{
		//covert objects X/Y to map cords
		int x = (((*itor)->getX()-anchor.x)/tileSize);
		int y = (((*itor)->getY()-anchor.y)/tileSize);

		data[x + (y * mapWidth)]=getIntFromObjType((*itor)->typ);
		
		
	}
	



	


	return AIMap;	

}