/*	Author: Magdin Stoica
	Supervisor: Dr. Ryan Leduc
	
	Project created in conformity with the requirements for the Degree of Master of Engineering in Software Engineering, 
	Computing and Software Department, 
	McMaster University
	2003 - 2007
*/

#include "ProjectIndex.h"
#include "Des.h"
#include "DesInterface.h"
#include "DesSubsystem.h"
#include "Instantiation.h"
#include <map>

namespace DESpot
{

ProjectIndex::ProjectIndex(void)
{
}

//_________________________________________________________________________________________________

ProjectIndex::~ProjectIndex(void)
{
}

//_________________________________________________________________________________________________

void ProjectIndex::addComp(const DesSubsystem& subsys)
{
	addComp(subsys.getName(), eSubsystemComp, &subsys);
}

//_________________________________________________________________________________________________

void ProjectIndex::addComp(const DesInterface& interf)
{
	addComp(interf.getName(), eInterfaceComp, &interf);
}

//_________________________________________________________________________________________________

void ProjectIndex::addComp(const Des& des)
{
	addComp(des.getName(), eDesComp, &des);
}

//_________________________________________________________________________________________________
//add by bini
void ProjectIndex::addComp(const Instantiation& inst)
{
	addComp(inst.getName(), eInstComp, &inst);
}

//_________________________________________________________________________________________________

void ProjectIndex::addComp(const std::wstring& name, ProjectCompType compType, const void* comp)
{
	//ensure the name is not in use
	if (findName(name)&&compType!=eInstComp)
	{
		throw EX("Name already in use. Cannot add component to index")
	}

	//m_index[name] = TypedComp(compType, comp);
	TypedComp temp;
	temp=std::make_pair(compType,comp);
	m_index.insert(std::pair<std::wstring,TypedComp>(name,temp));
}

//_________________________________________________________________________________________________

void ProjectIndex::reIndex(const std::wstring& oldName, const DesSubsystem& subsys)
{
	reIndex(oldName, subsys.getName(), eSubsystemComp, &subsys);
}

//_________________________________________________________________________________________________

void ProjectIndex::reIndex(const std::wstring& oldName, const DesInterface& interf)
{
	reIndex(oldName, interf.getName(), eInterfaceComp, &interf);
}

//_________________________________________________________________________________________________

void ProjectIndex::reIndex(const std::wstring& oldName, const Des& des)
{
	reIndex(oldName, des.getName(), eDesComp, &des);
}

//_________________________________________________________________________________________________
//add by bini
void ProjectIndex::reIndex(const std::wstring& oldName, const Instantiation& inst)
{
	reIndex(oldName, inst.getName(), eInstComp, &inst);
}

//_________________________________________________________________________________________________

void ProjectIndex::reIndex(const std::wstring& oldName, const std::wstring& newName, ProjectCompType compType, const void* comp)
{
	NameIndexMapIt it = m_index.find(oldName);
	if (it == m_index.end())
	{
		throw EX("The old name cannot be found in the index. Cannot reindex component")
	}

	TypedComp indexedComp = it->second;
	if (indexedComp.first != compType || indexedComp.second != comp)
	{
		throw EX("The given old name doesn't match the given component or its type")
	}

	if (m_index.find (newName) != m_index.end())
	{
		throw EX("The new name already exists in the index. Cannot reindex component")
	}

	//erase the old index entry
	m_index.erase(it);

	//add the component under its new entry
	//m_index[newName] = TypedComp(compType, comp);
	TypedComp temp;
	temp=std::make_pair(compType,comp);
	m_index.insert(std::pair<std::wstring,TypedComp>(newName,temp));
}

//_________________________________________________________________________________________________

bool ProjectIndex::findName(const std::wstring& name, TypedComp* out_comp/* = null*/)
{
	NameIndexMapIt compIt = m_index.find(name);	
	if (compIt != m_index.end())
	{
		if (out_comp)
		{
			*out_comp = compIt->second;
		}
		return true;
	}


	return false;
}


//_________________________________________________________________________________________________

bool ProjectIndex::findSubsystem(const std::wstring& name, const DesSubsystem*& out_subsys)
{
	NameIndexMapIt compIt = m_index.find(name);
	if ( compIt != m_index.end())
	{
		TypedComp& typedComp = compIt->second;
		if (typedComp.first != eSubsystemComp)
		{
			throw EX("Des found with the given name is not a subsystem")
		}
		
		out_subsys = reinterpret_cast<const DesSubsystem*>(typedComp.second);
		
		return true;
	}

	return false;
}

//_________________________________________________________________________________________________

bool ProjectIndex::findInterface(const std::wstring& name, const DesInterface*& out_interf)
{
	NameIndexMapIt compIt = m_index.find(name);
	if ( compIt != m_index.end())
	{
		TypedComp& typedComp = compIt->second;
		if (typedComp.first != eInterfaceComp)
		{
			throw EX("Des found with the given name is not an interface")
		}
		
		out_interf = reinterpret_cast<const DesInterface*>(typedComp.second);
		
		return true;
	}

	return false;
}

//_________________________________________________________________________________________________

bool ProjectIndex::findDes(const std::wstring& name, const Des*& out_des)
{
	NameIndexMapIt compIt = m_index.find(name);
	if ( compIt != m_index.end())
	{
		TypedComp& typedComp = compIt->second;
		if (typedComp.first != eInterfaceComp)
		{
			throw EX("Des found with the given name is not a DES")
		}
		
		out_des = reinterpret_cast<const Des*>(typedComp.second);
		
		return true;
	}

	return false;
}

//_________________________________________________________________________________________________
//add by bini
bool ProjectIndex::findInstantiation(const std::wstring& name, const Instantiation*& out_inst)
{
	NameIndexMapIt compIt = m_index.find(name);
	if ( compIt != m_index.end())
	{
		TypedComp& typedComp = compIt->second;
		if (typedComp.first != eInterfaceComp)
		{
			throw EX("Des found with the given name is not a Instantiation")
		}
		
		out_inst = reinterpret_cast<const Instantiation*>(typedComp.second);
		
		return true;
	}

	return false;
}

//_________________________________________________________________________________________________

void ProjectIndex::erase(const std::wstring& name)
{
	NameIndexMapIt compIt = m_index.find(name);
	if (compIt == m_index.end())
	{
		throw EX("Not project component is indexed under this name")
	}
	
	m_index.erase(compIt);
}

} //end of namespace DESpot
