#include "MW4Headers.hpp"

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

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

#include <Adept\Tool.hpp>

//#############################################################################
//####################     SalvagePlug   ######################################
//#############################################################################

SalvagePlug::SalvagePlug(Subsystem *subsystem, const char *salvage_string) : 
	Plug(Plug::DefaultData)
{
	Check_Pointer(subsystem);
	
	m_subsystem = subsystem;
	m_salvageID = subsystem->GetGameModelResourceID();
	m_dataListID = subsystem->GetDataListResourceID();
	m_count = 1;
	m_newCount = 0;
	m_salvageName = salvage_string;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
SalvagePlug::SalvagePlug(ResourceID salvage_id, ResourceID data_list, const char *salvage_string) : 
	Plug(Plug::DefaultData)
{
	m_subsystem = NULL;
	m_salvageID = salvage_id;
	m_dataListID = data_list;
	m_count = 1;
	m_newCount = 0;
	m_salvageName = salvage_string;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
SalvagePlug::~SalvagePlug()
{
}

//#############################################################################
//###########################    Salvage    ###################################
//#############################################################################

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

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
SalvageManager::SalvageManager(MemoryStream *stream):
	Receiver(DefaultData),
	m_salvageList(NULL, true),
	m_mechSalvageNames(NULL)
{
	m_totalSalvage = 0;

	if(stream)
	{
		Check_Pointer(stream);
		int salvage_count;
		*stream >> salvage_count;
		for(int i=0; i<salvage_count; i++)
		{
			ResourceID salvage_id;
			ResourceID data_id;
			MString salvage_name;
			*stream >> salvage_id;
			*stream >> data_id;
			*stream >> salvage_name;
			AddSalvage(salvage_id, data_id, salvage_name);
		}

		while(stream->GetBytesRemaining() > 0)
		{
			MString mech_name;
			*stream >> mech_name;
			PlugOf<MString> *name_plug = new PlugOf<MString>(mech_name);
			m_mechSalvageNames.Add(name_plug);
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
SalvageManager::~SalvageManager()
{
	Check_Object(this);
	m_salvageList.DeletePlugs();
	m_mechSalvageNames.DeletePlugs();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
SalvageManager*
	SalvageManager::MakeNewSalvageManager(const ResourceID& salvage_resource_id)
{
	SalvageManager *new_salvage;
	if(salvage_resource_id != ResourceID::Null)
	{
		Resource salvage_resource(salvage_resource_id);
		Verify(salvage_resource.DoesResourceExist());
		salvage_resource.LoadData();
		
		new_salvage = new SalvageManager(&salvage_resource);
		Check_Object(new_salvage);
	}
	else
		new_salvage = new SalvageManager(NULL);

	return new_salvage;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
SalvageManager*
	SalvageManager::MakeNewSalvageManager(const char *salvage_name)
{

	SalvageManager *new_salvage;

	Resource salvage_resource(salvage_name);
	if(salvage_resource.DoesResourceExist())
	{
		salvage_resource.LoadData();
		new_salvage = new SalvageManager(&salvage_resource);
		Check_Object(new_salvage);
	}
	else
		new_salvage = new SalvageManager(NULL);

	return new_salvage;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	SalvageManager::ConstructSalvageStream(
		MemoryStream *stream,
		NotationFile *notation_file
	)
{
	Check_Pointer(stream);
	Check_Pointer(notation_file);

	Page *page = notation_file->GetPage("Salvage");
	ChainOf<Note*> *salvage_chain = page->MakeNoteChain("Item");
	Check_Object(salvage_chain);
	Page::NoteIterator salvage_iterator(salvage_chain);
	Note *salvage_entry;
	*stream << salvage_chain->GetSize();
	while((salvage_entry = salvage_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(salvage_entry);
		const char *salvage_name;
		salvage_entry->GetEntry(&salvage_name);
		MString salvage_string = salvage_name;
		Resource data_list(salvage_string);
		Verify(data_list.DoesResourceExist());
		salvage_string += "{gameModel}";
		Resource salvage_resource(salvage_string);
		Verify(salvage_resource.DoesResourceExist());
		*stream << salvage_resource.GetResourceID();
		*stream << data_list.GetResourceID();
		//This is here because they will never have anything here to start...if they do this MUST CHANGE
		//Since this name is bullshit and not the real name
		*stream << salvage_string;
	}

	ChainOf<Note*> *mech_chain = page->MakeNoteChain("Mech");
	Check_Object(mech_chain);
	Page::NoteIterator mech_iterator(mech_chain);
	Note *mech_entry;
	while((mech_entry = mech_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(mech_entry);
		const char *mech_name;
		mech_entry->GetEntry(&mech_name);
		MString mech_string = mech_name;

		*stream << mech_string;
	}

	delete mech_chain;
	delete salvage_chain;
}

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

	SalvagePlug *salvage_item;
	SortedChainIteratorOf<SalvagePlug *, int> iterator(&m_salvageList);
	*stream << m_totalSalvage;
	while((salvage_item = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(salvage_item);
		for(int i=0; i<salvage_item->m_count; i++)
		{
			*stream << salvage_item->m_salvageID;
			*stream << salvage_item->m_dataListID;
			*stream << salvage_item->m_salvageName;
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	SalvageManager::WriteToText(const char *file_name)
{
	NotationFile *salvage_file = new NotationFile(file_name);
	Check_Object(salvage_file);

	STOP(("THIS IS NOT IMPLEMENTED CORRECTLY"));

	Page *page = salvage_file->AddPage("Salvage");
	SalvagePlug *salvage_plug;
	SortedChainIteratorOf<SalvagePlug *, int> iterator(&m_salvageList);
	while((salvage_plug = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(salvage_plug);
		Resource salvage_resource(salvage_plug->m_salvageID);
		Verify(salvage_resource.DoesResourceExist());
		page->AppendEntry("Item", salvage_resource.GetName());
		
	}
	salvage_file->Save();
//	delete salvage_file;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	SalvageManager::GetAndAddComponentSalvage(const char *salvage_string, int number)
{
//	MWTable *sub_table;
	Check_Object(MWApplication::GetInstance());
	Check_Object(MWApplication::GetInstance()->m_subsystemTable);
	
//	sub_table = MWApplication::GetInstance()->m_subsystemTable;

	MWTableEntry *sub_entry = MWApplication::GetInstance()->m_subsystemTable->FindEntry(salvage_string);
	Check_Object(sub_entry);

	Resource model_resource;
	Entity::GetGameModelResourceFromDataListID(&model_resource, sub_entry->GetEntryResourceID());
	Verify(model_resource.DoesResourceExist());

	for(int i=0; i<number; i++)
		AddSalvage(model_resource.GetResourceID(), 
			sub_entry->GetEntryResourceID(), 
			sub_entry->GetEntryName(), 
			true
		);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	SalvageManager::GetAndAddWeaponSalvage(const char *salvage_string, int number)
{
//	MWTable *weapon_table;
	Check_Object(MWApplication::GetInstance());
	Check_Object(MWApplication::GetInstance()->m_weaponsTable);
	
//	weapon_table = MWApplication::GetInstance()->m_weaponsTable;

	MWTableEntry *weapon_entry = MWApplication::GetInstance()->m_weaponsTable->FindEntry(salvage_string);
	Check_Object(weapon_entry);

	Resource model_resource;
	Entity::GetGameModelResourceFromDataListID(&model_resource, weapon_entry->GetEntryResourceID());
	Verify(model_resource.DoesResourceExist());

	for(int i=0; i<number; i++)
		AddSalvage(model_resource.GetResourceID(), 
			weapon_entry->GetEntryResourceID(), 
			weapon_entry->GetEntryName(), 
			true
		);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	SalvageManager::AddSalvage(Subsystem *subsystem, const char *salvage_string, bool is_new)
{
	Check_Object(this);
	Check_Object(subsystem);
	
	const Subsystem::GameModel *sub_model = subsystem->GetGameModel();
	Check_Object(sub_model);

	SalvagePlug *salvage_plug;
	if((salvage_plug = m_salvageList.Find(sub_model->itemID)) != NULL)
	{
		salvage_plug->m_count ++;
	}
	else
	{
		salvage_plug = new SalvagePlug(subsystem, salvage_string);
		m_salvageList.AddValue(salvage_plug, sub_model->itemID);
	}

	if(is_new)
	{
		salvage_plug->m_newCount++;
	}
	m_totalSalvage ++;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	SalvageManager::AddSalvage(const ResourceID& salvage_id, const ResourceID& data_list, const char *salvage_string, bool is_new)
{
	Check_Object(this);

	Resource model_resource(salvage_id);
	Verify(model_resource.DoesResourceExist());
	
	const Subsystem::GameModel *sub_model = 
		Cast_Pointer(Subsystem::GameModel *, model_resource.GetPointer());
	Check_Pointer(sub_model);

	SalvagePlug *salvage_plug;
	if((salvage_plug = m_salvageList.Find(sub_model->itemID)) != NULL)
	{
		salvage_plug->m_count ++;
	}
	else
	{
		salvage_plug = new SalvagePlug(salvage_id, data_list, salvage_string);
		m_salvageList.AddValue(salvage_plug, sub_model->itemID);
	}
	if(is_new)
	{
		salvage_plug->m_newCount++;
	}

	m_totalSalvage ++;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	SalvageManager::RemoveSalvage(Subsystem *subsystem)
{
	Check_Object(this);
	Check_Object(subsystem);
	
	const Subsystem::GameModel *sub_model = subsystem->GetGameModel();
	Check_Object(sub_model);

	SalvagePlug *salvage_plug;
	if((salvage_plug = m_salvageList.Find(sub_model->itemID)) != NULL)
	{
		salvage_plug->m_count --;
		if(salvage_plug->m_count <= 0)
		{
			m_salvageList.Remove(salvage_plug);
			delete salvage_plug;
		}
		m_totalSalvage --;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	SalvageManager::RemoveSalvage(const ResourceID& salvage_id)
{
	Check_Object(this);

	Resource model_resource(salvage_id);
	Verify(model_resource.DoesResourceExist());
	
	const Subsystem::GameModel *sub_model = 
		Cast_Pointer(Subsystem::GameModel *, model_resource.GetPointer());
	Check_Pointer(sub_model);

	SalvagePlug *salvage_plug;
	if((salvage_plug = m_salvageList.Find(sub_model->itemID)) != NULL)
	{
		salvage_plug->m_count --;
		if(salvage_plug->m_count <= 0)
		{
			m_salvageList.Remove(salvage_plug);
			delete salvage_plug;
		}
		m_totalSalvage --;
	}
}

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