#include "MW4Headers.hpp"

#if defined( BLACK_KNIGHT )
#include "mechlabheaders_BK.h"
#elif defined( MERCENARIES )
#include "mechlabheaders_MERCS.h"
#elif defined( VENGEANCE )
#include "mechlabheaders_VENG.h"
#endif

#include "BlackMarket.hpp"
#include "Subsystem.hpp"
#include "Mech.hpp"
#include "MWTable.hpp"
#include "MWApplication.hpp"

#include "..\buildnum\buildnum.h"

#include <Adept\Tool.hpp>


BlackMarketManager::ClassData*
	BlackMarketManager::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
	BlackMarketManager::InitializeClass()
{
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			BlackMarketManagerClassID,
			"MechWarrior4::BlackMarketManager",
			Receiver::DefaultData,
			0,
			NULL
		);
	Check_Object(DefaultData);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	BlackMarketManager::TerminateClass()
{
	Check_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BlackMarketManager::BlackMarketManager(MemoryStream *stream):
	Receiver(DefaultData),
	m_chitList(NULL, true)
	
{
	m_totalItems = 0;

	if(stream)
	{
		Check_Pointer (stream);
		int itemCount;
		*stream >> itemCount;
		for (int i=0; i<itemCount; i++)
		{
			int itemID;
			MString itemName;
			
			*stream >> itemID;
			*stream >> itemName;
			AddItem (itemID, itemName);
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BlackMarketManager::~BlackMarketManager()
{
	Check_Object(this);
	m_chitList.DeletePlugs();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	BlackMarketManager::ConstructBlackMarketStream(
		MemoryStream *stream,
		NotationFile *notation_file
	)
{
	//no entries from the text file

	*stream << 0;
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BlackMarketManager*
	BlackMarketManager::MakeNewBlackMarketManager(const ResourceID& blackMarketResourceID)
{
	BlackMarketManager *newBlackMarket;
	if(blackMarketResourceID != ResourceID::Null)
	{
		Resource blackMarketResource (blackMarketResourceID);
		Verify(blackMarketResource.DoesResourceExist());
		blackMarketResource.LoadData();
		
		newBlackMarket = new BlackMarketManager(&blackMarketResource);
		Check_Object(newBlackMarket);
	}
	else
		newBlackMarket = new BlackMarketManager(NULL);

	return newBlackMarket;
}


////////////////////////////
BlackMarketManager*
	BlackMarketManager::MakeNewBlackMarketManager (const char* blackMarketName)
{
	BlackMarketManager * newBlackMarket;
	
	Resource blackMarketResource (blackMarketName);
	if (blackMarketResource.DoesResourceExist())
	{
		blackMarketResource.LoadData();
		newBlackMarket = new BlackMarketManager (&blackMarketResource);
		Check_Object (newBlackMarket);

	}
	else
	{
		newBlackMarket = new BlackMarketManager (NULL);
	}
	return newBlackMarket;
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	BlackMarketManager::Save (MemoryStream *stream)
{
	Check_Object(this);
	Check_Pointer(stream);

	BlackMarketPlug *blackMarket_plug;
	SortedChainIteratorOf<BlackMarketPlug *, int> iterator(&m_chitList);
	*stream << m_totalItems;
	while((blackMarket_plug = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(blackMarket_plug);
		for(int i=0; i<blackMarket_plug->GetCount() ; i++)
		{
			*stream << blackMarket_plug->GetChitTypeID();
			*stream << blackMarket_plug->GetChitName();
		}
	}
}

////////////////////////////////////////////////////////////////////////////////
void BlackMarketManager::AddWeapon (char* szWeaponName)
{
	Check_Object (MWApplication::GetInstance());
	Check_Object (MWApplication::GetInstance()->m_weaponsTable);

#if defined( VENGEANCE ) || defined( BLACK_KNIGHT )
	MWMechPakTableEntry *weaponEntry = MWApplication::GetInstance()->m_weaponsTable->FindEntry (szWeaponName);
#else
	MWTableEntry *weaponEntry = MWApplication::GetInstance()->m_weaponsTable->FindEntry (szWeaponName);
#endif
	Check_Object (weaponEntry);
	Resource modelResource;
	Entity::GetGameModelResourceFromDataListID (&modelResource, weaponEntry->GetEntryResourceID());
	Verify (modelResource.DoesResourceExist());

	const Subsystem::GameModel *weaponModel = 
		Cast_Pointer(Subsystem::GameModel *, modelResource.GetPointer());
	Check_Pointer(weaponModel);
	AddItem (weaponModel->itemID, szWeaponName);

}

///////////////////////////////////////////////////////
void BlackMarketManager::AddMech (char* szMechName)
{
	Check_Object (MWApplication::GetInstance());
	Check_Object (MWApplication::GetInstance()->m_mechChassisTable);

#if defined( BLACK_KNIGHT )
	MWMechPakTableEntry *mechEntry = MWApplication::GetInstance()->m_mechChassisTable->FindEntry (szMechName);
	Check_Object (mechEntry);
#else
	MWTableEntry *mechEntry = MWApplication::GetInstance()->m_mechChassisTable->FindEntry (szMechName);
	Check_Object (mechEntry);
#endif

	Resource modelResource;
	Entity::GetGameModelResourceFromDataListID (&modelResource, mechEntry->GetEntryResourceID());
	Verify (modelResource.DoesResourceExist());

	const Mech::GameModel * mechModel =
		Cast_Pointer (Mech::GameModel*, modelResource.GetPointer());
	Check_Pointer (mechModel);
	AddItem (mechModel->mechID + FirstMechChitID, szMechName ); 
}
/////////////////////////////////////////////////////
void BlackMarketManager::AddItem (int itemID)
{

	//if it a Weapon
	if (itemID < FirstMechChitID)
	{
		AddItem (itemID,MWApplication::GetInstance()->GetWeaponName(itemID));
	}
	else //it is a Mech
	{
			//add the offset since the id that is passed
			//in is offset by the chit ID
		AddItem (itemID, MWApplication::GetInstance()->GetMechName(itemID - FirstMechChitID));
	}
}

void BlackMarketManager::AddItem (int itemID, char* szItemName)
{
	BlackMarketPlug* thisPlug = m_chitList.Find (itemID);
	if (thisPlug != NULL)
	{	
		//there is an entry for this types 
		//add to it
		thisPlug ->Add();
	}
	else
	{
		//there is no entry, create a new plug
		thisPlug = new BlackMarketPlug (itemID, szItemName);
		m_chitList.AddValue (thisPlug, itemID);
	}

	m_totalItems ++;
}
	
int BlackMarketManager::GetWeaponCount (char* szWeaponName)
{
	int weaponCount =0;
	Check_Object (MWApplication::GetInstance());
	Check_Object (MWApplication::GetInstance()->m_weaponsTable);

#if defined( VENGEANCE ) || defined( BLACK_KNIGHT )
	MWMechPakTableEntry *weaponEntry = MWApplication::GetInstance()->m_weaponsTable->FindEntry (szWeaponName);
#else
	MWTableEntry *weaponEntry = MWApplication::GetInstance()->m_weaponsTable->FindEntry (szWeaponName);
#endif
	Check_Object (weaponEntry);
	Resource modelResource;
	Entity::GetGameModelResourceFromDataListID (&modelResource, weaponEntry->GetEntryResourceID());
	Verify (modelResource.DoesResourceExist());

	const Subsystem::GameModel* weaponModel =
		Cast_Pointer (Subsystem::GameModel*, modelResource.GetPointer());
	Check_Pointer (weaponModel);

	BlackMarketPlug* weaponPlug = m_chitList.Find (weaponModel->itemID);
	if (weaponPlug != NULL)
	{
		weaponCount = weaponPlug->GetCount();
	}
	return weaponCount;
}


int BlackMarketManager::GetMechCount (char* szMechName)
{
	int mechCount =0;
	Check_Object (MWApplication::GetInstance());
	Check_Object (MWApplication::GetInstance()->m_mechChassisTable);

#if defined( BLACK_KNIGHT )
	MWMechPakTableEntry* mechEntry = MWApplication::GetInstance()->m_mechChassisTable ->FindEntry (szMechName);
	Check_Object (mechEntry);
#else
	MWTableEntry* mechEntry = MWApplication::GetInstance()->m_mechChassisTable ->FindEntry (szMechName);
	Check_Object (mechEntry);
#endif
	Resource modelResource;
	Entity::GetGameModelResourceFromDataListID (&modelResource, mechEntry->GetEntryResourceID());
	Verify (modelResource.DoesResourceExist());

	const Mech::GameModel* mechModel =	
		Cast_Pointer (Mech::GameModel*, modelResource.GetPointer());
	Check_Pointer (mechModel);
	
	BlackMarketPlug* mechPlug = m_chitList.Find (mechModel->mechID + FirstMechChitID);
	if (mechPlug != NULL)
	{
		mechCount = mechPlug->GetCount ();
	}
	return mechCount;
}


void BlackMarketManager::RemoveWeapon (char* szWeaponName)
{
	Check_Object (MWApplication::GetInstance());
	Check_Object (MWApplication::GetInstance()->m_weaponsTable);

#if defined( VENGEANCE ) || defined( BLACK_KNIGHT )
	MWMechPakTableEntry *weaponEntry = MWApplication::GetInstance()->m_weaponsTable->FindEntry (szWeaponName);
#else
	MWTableEntry *weaponEntry = MWApplication::GetInstance()->m_weaponsTable->FindEntry (szWeaponName);
#endif
	Check_Object (weaponEntry);

	Resource modelResource;
	Entity::GetGameModelResourceFromDataListID (&modelResource, weaponEntry->GetEntryResourceID());
	Verify (modelResource.DoesResourceExist());

	const Subsystem::GameModel *weaponModel = 
		Cast_Pointer(Subsystem::GameModel *, modelResource.GetPointer());
	Check_Pointer(weaponModel);
	RemoveItem (weaponModel->itemID);
	
}


void BlackMarketManager::RemoveMech (char* szMechName)
{
	Check_Object (MWApplication::GetInstance());
	Check_Object (MWApplication::GetInstance()->m_mechChassisTable);

#if defined( BLACK_KNIGHT )
	MWMechPakTableEntry *mechEntry = MWApplication::GetInstance()->m_mechChassisTable->FindEntry (szMechName);
	Check_Object (mechEntry);
#else
	MWTableEntry *mechEntry = MWApplication::GetInstance()->m_mechChassisTable->FindEntry (szMechName);
	Check_Object (mechEntry);
#endif

	Resource modelResource;
	Entity::GetGameModelResourceFromDataListID (&modelResource, mechEntry->GetEntryResourceID());
	Verify (modelResource.DoesResourceExist());

	const Mech::GameModel * mechModel =
		Cast_Pointer (Mech::GameModel*, modelResource.GetPointer());
	Check_Pointer (mechModel);
	RemoveItem (mechModel->mechID + FirstMechChitID ); //add the offset for the Mech chit IDs

}


void BlackMarketManager::RemoveAllWeapons ()
{
	Check_Object (MWApplication::GetInstance());
	Check_Object (MWApplication::GetInstance()->m_weaponsTable);

	BlackMarketPlug *blackMarketPlug;
	SortedChainIteratorOf<BlackMarketPlug *, int> iterator(&m_chitList);
	while((blackMarketPlug = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(blackMarketPlug);
		//if it is a weapon
		if (blackMarketPlug ->GetChitTypeID () < FirstMechChitID)
		{
			m_totalItems -= blackMarketPlug->GetCount();
			m_chitList.Remove (blackMarketPlug);
			delete blackMarketPlug;
		}

	}
}
//////////////////////////////////////////////////////

void BlackMarketManager::RemoveAllMechs ()
{
	Check_Object (MWApplication::GetInstance());
	Check_Object (MWApplication::GetInstance()->m_mechChassisTable);

	BlackMarketPlug* blackMarketPlug;
	SortedChainIteratorOf <BlackMarketPlug*, int> iterator (&m_chitList);
	while ((blackMarketPlug = iterator.ReadAndNext()) != NULL)
	{
		Check_Object (blackMarketPlug);
		//if it is a Mech
		if (blackMarketPlug ->GetChitTypeID() >= FirstMechChitID)
		{
			m_totalItems -= blackMarketPlug->GetCount();
			m_chitList.Remove (blackMarketPlug);
			delete blackMarketPlug;
		}
	}
}
/////////////////////////////////////////////

void BlackMarketManager::RemoveItem (int itemID)
{
	Check_Object (this);
	
	BlackMarketPlug* blackMarketPlug = NULL;
	blackMarketPlug = m_chitList.Find (itemID);
	if (blackMarketPlug != NULL)
	{
		blackMarketPlug->Subtract();
		if (blackMarketPlug->IsEmpty ())
		{
			m_chitList.Remove (blackMarketPlug);
			delete blackMarketPlug;
		}
		m_totalItems --;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	BlackMarketManager::TestInstance()
{
	Verify(IsDerivedFrom(DefaultData));
}
