// WorldIterator.cpp : Implementation of cWorldIterator
#include "stdafx.h"
#include "DecalFilters.h"
#include "World.h"
#include "WorldIterator.h"

/////////////////////////////////////////////////////////////////////////////
// cWorldIterator


STDMETHODIMP cWorldIterator::get_Next_Old(IWorldObject **pVal)
{
	return get_Next(pVal, NULL);
}

STDMETHODIMP cWorldIterator::Reset()
{
	m_i = m_objects->begin();

	return S_OK;
}

STDMETHODIMP cWorldIterator::get_Count(long *pVal)
{
	int nCount;
	cWorldDataMap::iterator iSave = m_i;

	m_i = m_objects->begin();

	for (nCount = 0; get_Next(NULL, NULL) == S_OK; nCount++);
	*pVal = nCount;

	m_i = iSave;

	return S_OK;
}


STDMETHODIMP cWorldIterator::get_Quantity(long *pVal)
{
	long nCount=0;
	cWorldDataMap::iterator iSave = m_i;
	
	IWorldObject* pObject = NULL ;

	m_i = m_objects->begin();
		
	while (get_Next(&pObject, NULL) == S_OK) {
		if (pObject) {
			long x ;
			pObject->get_StackMax(&x) ;
			if (x) {
				pObject->get_StackCount(&x) ;	// stackable, get number in stack
			} else {
				x=1 ;			// not stackable, so only count as one
			}
			nCount += x ;
		}
	}

	*pVal = nCount;
	
	m_i = iSave;
	
	return S_OK;
}


STDMETHODIMP cWorldIterator::get_Next(IWorldObject **ppObject, VARIANT_BOOL *pVal)
{
	while (m_i != m_objects->end())
	{
		for (cMatchList::iterator i = m_compares.begin(); i != m_compares.end(); i++)
		{
			// if our match fails, try next object
			if (!(*i)->match(m_i))
				goto next;
		}

		if (pVal) {
			*pVal = VARIANT_TRUE;
		}

		if (ppObject) {
			// Gouru: moved to release ONLY if we are setting a new value...
			// release incoming object so get_Next can be used in a loop
			if (*ppObject && *ppObject != (IWorldObject *)this) {
				(*ppObject)->Release();
			}
			m_i->second->m_p->QueryInterface(ppObject);
		}

		m_i++;
		return S_OK;

next:
		m_i++;
	}

	if (pVal)
		*pVal = VARIANT_FALSE;

	return S_FALSE;
}

STDMETHODIMP cWorldIterator::Pop()
{
	if (!m_compares.empty())
	{
		cMatch *pMatch = m_compares.back();
		delete pMatch;
		m_compares.pop_back();
	}

	return S_OK;
}

STDMETHODIMP cWorldIterator::ByName(BSTR strName)
{
	USES_CONVERSION;

	cMatch *pMatch = new cMatchName(m_objects, std::string(OLE2A(strName)));
	m_compares.push_back(pMatch);

	return S_OK;
}

STDMETHODIMP cWorldIterator::ByNameSubstring(BSTR strSubstring)
{
	USES_CONVERSION;

	cMatch *pMatch = new cMatchNameSubstring(m_objects, std::string(OLE2A(strSubstring)));
	m_compares.push_back(pMatch);

	return S_OK;
}

STDMETHODIMP cWorldIterator::ByType(enum eObjectType Type)
{
	cMatch *pMatch = new cMatchType(m_objects, Type);
	m_compares.push_back(pMatch);

	return S_OK;
}

STDMETHODIMP cWorldIterator::ByContainer(long nContainer)
{
	cMatch *pMatch = new cMatchContainer(m_objects, nContainer);
	m_compares.push_back(pMatch);

	return S_OK;
}

STDMETHODIMP cWorldIterator::ByInventory()
{
	cMatch *pMatch = new cMatchInventory(m_objects);
	m_compares.push_back(pMatch);

	return S_OK;
}

STDMETHODIMP cWorldIterator::ByLandscape()
{
	cMatch *pMatch = new cMatchLandscape(m_objects);
	m_compares.push_back(pMatch);

	return S_OK;
}

STDMETHODIMP cWorldIterator::ByOwner(long nOwner)
{
	cMatch *pMatch = new cMatchOwner(m_objects, nOwner);
	m_compares.push_back(pMatch);

	return S_OK;
}

STDMETHODIMP cWorldIterator::ByAll()
{
	cMatch *pMatch = new cMatchAll(m_objects);
	m_compares.push_back(pMatch);

	return S_OK;
}

void cWorldIterator::Initialize(cWorldDataMap *pMap)
{
	m_objects = pMap;
	m_i = m_objects->begin();
}
