#include "pch.h"
#include "AGCGlobal.h"
#include "AGCEvent.h"
#include "AGCEventDef.h"
#include "AGCEventData.h"
#include "AGCEventThread.h"
#include "AGCEventIDRange.h"
#include "AGCEventIDRanges.h"
#include "AGCVector.h"
#include "AGCOrientation.h"
#include "AGCWinApp.h"
TC_OBJECT_EXTERN_IMPL(CAGCGlobal)
void CAGCGlobal::FinalRelease()
{
Terminate();
}
const IID* CAGCGlobal::InterpretIID(const void* pvIgc, REFIID iid)
{
if (pvIgc)
{
if (IID_IAGCModel == iid)
{
const ImodelIGC* pModel = reinterpret_cast<const ImodelIGC*>(pvIgc);
switch (pModel->GetObjectType())
{
case OT_ship: return &IID_IAGCShip ;
case OT_station: return &IID_IAGCStation ;
case OT_missile: return &IID_IAGCModel ; case OT_mine: return &IID_IAGCModel ; case OT_probe: return &IID_IAGCProbe ;
case OT_asteroid: return &IID_IAGCAsteroid;
case OT_projectile: return &IID_IAGCModel ; case OT_warp: return &IID_IAGCAleph ;
case OT_treasure: return &IID_IAGCModel ; case OT_buoy: return &IID_IAGCModel ; case OT_chaff: return &IID_IAGCModel ; default:
ZError("CAGCGlobal::InterpretIID(): non-model type specified\n");
}
}
}
return &iid;
}
STDMETHODIMP_(void) CAGCGlobal::RegisterObjectCreator(REFIID riid,
PFNAGCCreator pfnCreator)
{
assert(pfnCreator);
XLock lock(this);
std::pair<XAGCCreatorMapIt, bool> result =
m_mapCreator.insert(std::make_pair(riid, pfnCreator));
if (!result.second)
result.first->second = pfnCreator;
}
STDMETHODIMP_(void) CAGCGlobal::RevokeObjectCreator(REFIID riid)
{
assert(!"NOT IMPLEMENTED!");
}
STDMETHODIMP CAGCGlobal::GetAGCObject(const void* pvIgc, REFIID riid,
void** ppUnk)
{
XLock lock(this);
const IID* piid = InterpretIID(pvIgc, riid);
XIgcToAGCMapIt it = m_map.find(const_cast<void*>(pvIgc));
if (m_map.end() != it)
{
return it->second->QueryInterface(*piid, ppUnk);
}
XAGCCreatorMapIt itCreator = m_mapCreator.find(*piid);
if (m_mapCreator.end() == itCreator)
{
assert(false);
return E_UNEXPECTED;
}
PFNAGCCreator pfn = itCreator->second;
assert(pfn);
RETURN_FAILED((*pfn)(const_cast<void*>(pvIgc), *piid, ppUnk));
AddAGCObject(const_cast<void*>(pvIgc), IUnknownPtr((IUnknown*)*ppUnk));
return S_OK;
}
STDMETHODIMP_(void) CAGCGlobal::AddAGCObject(const void* pvIgc,
IUnknown* pUnkAGC)
{
XLock lock(this);
assert(m_map.end() == m_map.find(const_cast<void*>(pvIgc)));
assert(NULL != IAGCPrivatePtr(pUnkAGC));
#ifdef _DEBUG
std::pair<XIgcToAGCMapIt, bool> result =
#endif
m_map.insert(std::make_pair(const_cast<void*>(pvIgc), pUnkAGC));
assert(result.second);
}
STDMETHODIMP_(void) CAGCGlobal::RemoveAGCObject(const void* pvIgc,
boolean bForceDestruct)
{
XLock lock(this);
XIgcToAGCMapIt it = m_map.find(pvIgc);
if (m_map.end() != it)
{
IUnknownPtr spUnk(it->second);
m_map.erase(it);
if (bForceDestruct)
::CoDisconnectObject(spUnk, 0);
}
}
STDMETHODIMP_(void) CAGCGlobal::SetEventSinksAreGITCookies(
boolean bEventSinksAreGITCookies)
{
XLock lock(this);
#ifdef _DEBUG
if (m_RegEvents.size())
assert(!m_bEventSinksAreGITCookies == !bEventSinksAreGITCookies);
#endif m_bEventSinksAreGITCookies = !!bEventSinksAreGITCookies;
}
STDMETHODIMP_(boolean) CAGCGlobal::GetEventSinksAreGITCookies()
{
XLock lock(this);
return m_bEventSinksAreGITCookies;
}
STDMETHODIMP_(void) CAGCGlobal::RegisterEvent(AGCEventID eventID,
AGCUniqueID uniqueID, IAGCEventSink* pEventSink)
{
#ifdef _DEBUG
{
if (GetEventSinksAreGITCookies())
{
IAGCEventSinkPtr spEventSink;
GetInterfaceFromGlobal(reinterpret_cast<DWORD>(pEventSink),
IID_IAGCEventSink, (void**)&spEventSink);
}
}
#endif XLock lock(this);
TCINT64 nKey = MakeKey(eventID, uniqueID);
XRegEventsIt itID = m_RegEvents.find(nKey);
if (m_RegEvents.end() != itID)
{
XEventSinks& vecEvents = itID->second;
for (XEventSinksIt it = vecEvents.begin(); it != vecEvents.end(); ++it)
if (*it == pEventSink)
return;
}
else
{
itID = m_RegEvents.insert(std::make_pair(nKey, XEventSinks())).first;
}
XEventSinks& vecEvents = itID->second;
vecEvents.push_back(pEventSink);
}
STDMETHODIMP_(boolean) CAGCGlobal::RevokeEvent(AGCEventID eventID,
AGCUniqueID uniqueID, IAGCEventSink* pEventSink)
{
#ifdef _DEBUG
{
if (GetEventSinksAreGITCookies())
{
IAGCEventSinkPtr spEventSink;
GetInterfaceFromGlobal(reinterpret_cast<DWORD>(pEventSink),
IID_IAGCEventSink, (void**)&spEventSink);
}
}
#endif XLock lock(this);
XRegEventsIt itID = m_RegEvents.find(MakeKey(eventID, uniqueID));
if (m_RegEvents.end() != itID)
{
XEventSinks& vecEvents = itID->second;
for (XEventSinksIt it = vecEvents.begin(); it != vecEvents.end(); ++it)
{
if (*it == pEventSink)
{
vecEvents.erase(it);
if (vecEvents.empty())
m_RegEvents.erase(itID);
return true;
}
}
}
return false;
}
STDMETHODIMP_(void) CAGCGlobal::RegisterEventRanges(
IAGCEventIDRanges* pRanges, AGCUniqueID uniqueID,
IAGCEventSink* pEventSink)
{
assert(pRanges);
XLock lock(this);
for (const CAGCEventDef::XEventDef* it = CAGCEventDef::begin();
CAGCEventDef::end() != it; ++it)
{
if (0 == it->m_nIndent)
{
range<AGCEventID> theRange(it->m_id, it->m_id);
if (m_EventIDRanges.find(theRange) != m_EventIDRanges.end())
{
VARIANT_BOOL bIntersects;
ZSucceeded(pRanges->get_IntersectsWithValue(it->m_id, &bIntersects));
if (bIntersects)
RegisterEvent(it->m_id, uniqueID, pEventSink);
}
}
}
}
STDMETHODIMP_(void) CAGCGlobal::RevokeEventRanges(IAGCEventIDRanges* pRanges,
AGCUniqueID uniqueID, IAGCEventSink* pEventSink)
{
assert(pRanges);
XLock lock(this);
for (const CAGCEventDef::XEventDef* it = CAGCEventDef::begin();
CAGCEventDef::end() != it; ++it)
{
if (0 == it->m_nIndent)
{
range<AGCEventID> theRange(it->m_id, it->m_id);
if (m_EventIDRanges.find(theRange) != m_EventIDRanges.end())
{
VARIANT_BOOL bIntersects;
ZSucceeded(pRanges->get_IntersectsWithValue(it->m_id, &bIntersects));
if (bIntersects)
RevokeEvent(it->m_id, uniqueID, pEventSink);
}
}
}
}
STDMETHODIMP_(int) CAGCGlobal::RevokeAllEvents(IAGCEventSink* pEventSink)
{
#ifdef _DEBUG
{
if (GetEventSinksAreGITCookies())
{
IAGCEventSinkPtr spEventSink;
GetInterfaceFromGlobal(reinterpret_cast<DWORD>(pEventSink),
IID_IAGCEventSink, (void**)&spEventSink);
}
}
#endif int cRemoved = 0;
XLock lock(this);
for (XRegEventsIt itID = m_RegEvents.begin(); itID != m_RegEvents.end(); ++itID)
{
XEventSinks& vecEvents = itID->second;
for (XEventSinksIt it = vecEvents.begin(); it != vecEvents.end(); ++it)
{
if (*it == pEventSink)
{
vecEvents.erase(it);
++cRemoved;
break;
}
}
}
return cRemoved;
}
STDMETHODIMP_(int) CAGCGlobal::RegisterAllEvents(IAGCEventSink* pEventSink)
{
#ifdef _DEBUG
{
if (GetEventSinksAreGITCookies())
{
IAGCEventSinkPtr spEventSink;
GetInterfaceFromGlobal(reinterpret_cast<DWORD>(pEventSink),
IID_IAGCEventSink, (void**)&spEventSink);
}
}
#endif XLock lock(this);
int cEventIDs = 0;
for (const CAGCEventDef::XEventDef* it = CAGCEventDef::begin();
CAGCEventDef::end() != it; ++it)
{
if (0 == it->m_nIndent)
{
range<AGCEventID> theRange(it->m_id, it->m_id);
if (m_EventIDRanges.find(theRange) != m_EventIDRanges.end())
{
RegisterEvent(it->m_id, AGC_Any_Objects, pEventSink);
++cEventIDs;
}
}
}
return cEventIDs;
}
STDMETHODIMP_(HAGCLISTENERS) CAGCGlobal::EventListeners(AGCEventID idEvent,
AGCUniqueID idSubject, AGCUniqueID idObject1, AGCUniqueID idObject2)
{
XLock lock(this);
XEventSinks* pSinks = NULL;
XRegEventsIt itID_AllObjects = m_RegEvents.find(MakeKey(idEvent, AGC_Any_Objects));
if (itID_AllObjects != m_RegEvents.end())
{
XEventSinksIt itBegin = itID_AllObjects->second.begin();
XEventSinksIt itEnd = itID_AllObjects->second.end();
if (itEnd != itBegin)
{
pSinks = new XEventSinks(itBegin, itEnd);
}
}
if (-1 != idSubject)
{
XRegEventsIt itID1 = m_RegEvents.find(MakeKey(idEvent, idSubject));
if (itID1 != m_RegEvents.end())
{
XEventSinksIt itBegin = itID_AllObjects->second.begin();
XEventSinksIt itEnd = itID_AllObjects->second.end();
if (itEnd != itBegin)
{
if (!pSinks)
pSinks = new XEventSinks(itBegin, itEnd);
else
pSinks->insert(pSinks->end(), itBegin, itEnd);
}
}
}
if (-1 != idObject1)
{
XRegEventsIt itID1 = m_RegEvents.find(MakeKey(idEvent, idObject1));
if (itID1 != m_RegEvents.end())
{
XEventSinksIt itBegin = itID_AllObjects->second.begin();
XEventSinksIt itEnd = itID_AllObjects->second.end();
if (itEnd != itBegin)
{
if (!pSinks)
pSinks = new XEventSinks(itBegin, itEnd);
else
pSinks->insert(pSinks->end(), itBegin, itEnd);
}
}
}
if (-1 != idObject2)
{
XRegEventsIt itID1 = m_RegEvents.find(MakeKey(idEvent, idObject2));
if (itID1 != m_RegEvents.end())
{
XEventSinksIt itBegin = itID_AllObjects->second.begin();
XEventSinksIt itEnd = itID_AllObjects->second.end();
if (itEnd != itBegin)
{
if (!pSinks)
pSinks = new XEventSinks(itBegin, itEnd);
else
pSinks->insert(pSinks->end(), itBegin, itEnd);
}
}
}
return pSinks;
}
STDMETHODIMP_(void) CAGCGlobal::TriggerEvent(HAGCLISTENERS hListeners,
AGCEventID idEvent, LPCSTR pszContext, LPCOLESTR pszSubject,
AGCUniqueID idSubject, AGCUniqueID idObject1, AGCUniqueID idObject2,
long cArgTriplets, void* pvArgs)
{
XLock lock(this);
if (!m_pthEvents)
m_pthEvents = new CAGCEventThread(this);
assert(m_pthEvents);
static CTempTimer timerTriggerEvent("in TriggerEvent", .01f);
timerTriggerEvent.Start();
if (!hListeners)
{
hListeners = EventListeners(idEvent, idSubject, idObject1, idObject2);
if (!hListeners)
goto stopTimer;
}
{
CAGCEventData data(idEvent, pszContext, pszSubject, idSubject,
cArgTriplets, reinterpret_cast<va_list>(pvArgs));
m_pthEvents->QueueEvent(hListeners, data);
}
stopTimer:
timerTriggerEvent.Stop();
}
STDMETHODIMP_(void) CAGCGlobal::TriggerEventSynchronous(HAGCLISTENERS hListeners,
AGCEventID idEvent, LPCSTR pszContext, LPCOLESTR pszSubject,
AGCUniqueID idSubject, AGCUniqueID idObject1, AGCUniqueID idObject2,
long cArgTriplets, void* pvArgs)
{
XLock lock(this);
if (!m_pthEvents)
m_pthEvents = new CAGCEventThread(this);
assert(m_pthEvents);
if (!hListeners)
{
hListeners = EventListeners(idEvent, idSubject, idObject1, idObject2);
if (!hListeners)
return;
}
lock.Unlock();
CAGCEventData data(idEvent, pszContext, pszSubject, idSubject,
cArgTriplets, reinterpret_cast<va_list>(pvArgs));
m_pthEvents->QueueEventSynchronous(hListeners, data);
}
STDMETHODIMP_(void) CAGCGlobal::FreeListeners(HAGCLISTENERS hListeners)
{
FreeListenersImpl(hListeners);
}
STDMETHODIMP_(boolean) CAGCGlobal::IsRegistered(AGCEventID eventID,
AGCUniqueID uniqueID, IAGCEventSink* pEventSink)
{
XLock lock(this);
XRegEventsIt itID = m_RegEvents.find(MakeKey(eventID, uniqueID));
if (m_RegEvents.end() != itID)
{
XEventSinks& vecEvents = itID->second;
for (XEventSinksIt it = vecEvents.begin(); it != vecEvents.end(); ++it)
if (*it == pEventSink)
return true;
}
return false;
}
STDMETHODIMP CAGCGlobal::MakeAGCEvent(AGCEventID idEvent,
LPCSTR pszContext, LPCOLESTR pszSubject, AGCUniqueID idSubject,
long cArgTriplets, void* pvArgs, IAGCEvent** ppEvent)
{
CComObject<CAGCEvent>* pEvent = NULL;
RETURN_FAILED(pEvent->CreateInstance(&pEvent));
IAGCEventPtr spEvent(pEvent);
RETURN_FAILED(pEvent->Init(idEvent, pszContext, pszSubject, idSubject,
cArgTriplets, (va_list)pvArgs));
*ppEvent = spEvent.Detach();
return S_OK;
}
STDMETHODIMP_(void) CAGCGlobal::SetAvailableEventIDRanges(
IAGCEventIDRanges* pRanges)
{
assert(pRanges);
XLock lock(this);
IAGCRangesPrivatePtr spPrivate(pRanges);
ZSucceeded(spPrivate->CopyRangesTo(&m_EventIDRanges));
}
STDMETHODIMP_(void) CAGCGlobal::GetAvailableEventIDRanges(
IAGCEventIDRanges** ppRanges)
{
CComObject<CAGCEventIDRanges>* pRanges = NULL;
ZSucceeded(pRanges->CreateInstance(&pRanges));
IAGCRangesPrivatePtr spPrivate(pRanges);
assert(NULL != spPrivate);
{
XLock lock(this);
ZSucceeded(spPrivate->InitFromRanges(&m_EventIDRanges));
}
(*ppRanges = pRanges)->AddRef();
}
STDMETHODIMP_(WORD) CAGCGlobal::GetEventSeverity(AGCEventID idEvent)
{
const CAGCEventDef::XEventDef* it = CAGCEventDef::find(idEvent);
return (it != CAGCEventDef::end()) ? it->m_wSeverity : 0;
}
STDMETHODIMP_(HINSTANCE) CAGCGlobal::GetResourceInstance()
{
return _Module.GetResourceInstance();
}
STDMETHODIMP CAGCGlobal::MakeAGCVector(const void* pVectorRaw,
IAGCVector** ppVector)
{
CComObject<CAGCVector>* pVector = NULL;
RETURN_FAILED(pVector->CreateInstance(&pVector));
IAGCVectorPtr spVector(pVector);
RETURN_FAILED(pVector->InitFromVector(pVectorRaw));
CLEAROUT(ppVector, (IAGCVector*)spVector);
spVector.Detach();
return S_OK;
}
STDMETHODIMP CAGCGlobal::MakeAGCOrientation(const void* pOrientationRaw,
IAGCOrientation** ppOrientation)
{
CComObject<CAGCOrientation>* pOrientation = NULL;
RETURN_FAILED(pOrientation->CreateInstance(&pOrientation));
IAGCOrientationPtr spOrientation(pOrientation);
RETURN_FAILED(pOrientation->InitFromOrientation(pOrientationRaw));
CLEAROUT(ppOrientation, (IAGCOrientation*)spOrientation);
spOrientation.Detach();
return S_OK;
}
STDMETHODIMP CAGCGlobal::MakeAGCEventIDRange(AGCEventID lower,
AGCEventID upper, IAGCEventIDRange** ppRange)
{
CComObject<CAGCEventIDRange>* pRange = NULL;
RETURN_FAILED(pRange->CreateInstance(&pRange));
IAGCEventIDRangePtr spRange(pRange);
RETURN_FAILED(pRange->InitFromRange(&make_range(lower, upper)));
CLEAROUT(ppRange, (IAGCEventIDRange*)spRange);
spRange.Detach();
return S_OK;
}
STDMETHODIMP CAGCGlobal::RegisterInterfaceInGlobal(IUnknown* pUnk,
REFIID riid, DWORD* pdwCookie)
{
HRESULT hr = GetGIT()->RegisterInterfaceInGlobal(pUnk, riid, pdwCookie);
if (FAILED(hr))
{
assert(!"CAGCGlobal::RegisterInterfaceInGlobal()");
}
return hr;
}
STDMETHODIMP CAGCGlobal::RevokeInterfaceFromGlobal(DWORD dwCookie)
{
HRESULT hr = GetGIT()->RevokeInterfaceFromGlobal(dwCookie);
if (FAILED(hr))
{
assert(!"CAGCGlobal::RevokeInterfaceFromGlobal()");
}
return hr;
}
STDMETHODIMP CAGCGlobal::GetInterfaceFromGlobal(DWORD dwCookie,
REFIID riid, void** ppv)
{
HRESULT hr = GetGIT()->GetInterfaceFromGlobal(dwCookie, riid, ppv);
if (FAILED(hr))
{
assert(!"CAGCGlobal::GetInterfaceFromGlobal()");
}
return hr;
}
STDMETHODIMP_(void) CAGCGlobal::Initialize()
{
CAGCEventDef::Initialize();
}
STDMETHODIMP_(void) CAGCGlobal::Terminate()
{
CAGCEventThread* pthEvents;
{
XLock lock(this);
pthEvents = m_pthEvents;
}
if (pthEvents)
{
delete pthEvents;
XLock lock(this);
m_pthEvents = NULL;
}
CAGCEventDef::Terminate();
}
STDMETHODIMP_(void) CAGCGlobal::SetDebugHook(IAGCDebugHook* pdh)
{
g_app.SetDebugHook(pdh);
}