// gfaipc.cpp
//

#ifdef _WIN32
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#endif	//	_WIN32

#include <stdio.h>
#include <string.h>
#include "defines.h"
#include "uuid.h"
#include "shmrot.h"

/////////////////////////////////////////////////////////////////////////////

CShmHandleMap::CShmHandleMap(void)
{
	memset(m_handles, 0, sizeof(m_handles));
}

CShmHandleMap::~CShmHandleMap(void)
{
	for(size_t i = 0; i < _IPCSHM_MAX_HANDLES; i++)
	{
	}
}

HSHM CShmHandleMap::AcquireHandle(CShm *pShm)
{
	HSHM hShm = NULL;

	for(int i = 0; i < _IPCSHM_MAX_HANDLES; i++)
	{
		if(!m_handles[i].pShm)
		{
			m_handles[i].pShm = pShm;
			hShm = &m_handles[i];
			break;
		}
	}

	return hShm;
}

void CShmHandleMap::ReleaseHandle(HSHM hShm)
{
	for(int i = 0; i < _IPCSHM_MAX_HANDLES; i++)
	{
		if(&m_handles[i] == hShm)
		{
			m_handles[i].pShm = NULL;
			break;
		}
	}
}

CShm* CShmHandleMap::LookupShm(const uuid_t &uuid)
{
	for(int i = 0; i < _IPCSHM_MAX_HANDLES; i++)
	{
		if(m_handles[i].pShm)
		{
			const uuid_t &uuid2 = m_handles[i].pShm->Uuid();

			if(!_uuid_compare(&uuid, &uuid2))
				return m_handles[i].pShm;
		}
	}

	return NULL;
}

/////////////////////////////////////////////////////////////////////////////

static CShmROT g_shmRot;
static CShmHandleMap g_shmHandleMap;

/////////////////////////////////////////////////////////////////////////////

HSHM GfaIpcAcquireSHM(const char *pszUuid, size_t nSizeElement, size_t nCntElements, const char *pszDescName)
{
	HSHM hShm = NULL;

	if(!g_shmRot.Created())
	{
		if(!g_shmRot.Create())
		{
			TRACE("GfaIpcAcquireSHM: Failed to create ROT!\n");
			return NULL;
		}
	}

	g_shmRot.Lock();
	CShm *pShm = g_shmRot.AcquireShm(pszUuid, nSizeElement, nCntElements, pszDescName);

	if(pShm)
	{
		hShm = g_shmHandleMap.AcquireHandle(pShm);

		if(!hShm)
		{
			TRACE("GfaIpcAcquireSHM: Failed to acquire handle!\n");
			g_shmRot.ReleaseShm(pShm);
		}
	}

	g_shmRot.Unlock();
	return hShm;
}

/////////////////////////////////////////////////////////////////////////////

void GfaIpcReleaseSHM(HSHM hShm)
{
	if(hShm)
	{
		LPSHM_HANDLE ph = (LPSHM_HANDLE)hShm;
		if(!ph->pShm)
		{
			TRACE("GfaIpcReleaseSHM: Invalid Handle!\n");
			return;
		}
		g_shmRot.Lock();
		g_shmRot.ReleaseShm(ph->pShm);
		g_shmHandleMap.ReleaseHandle(hShm);
		g_shmRot.Unlock();
	}
}

/////////////////////////////////////////////////////////////////////////////

void* GfaIpcAcquirePointer(HSHM hShm)
{
	if(hShm)
	{
		LPSHM_HANDLE ph = (LPSHM_HANDLE)hShm;
		if(!ph->pShm)
		{
			TRACE("GfaIpcAcquirePointer: Invalid Handle!\n");
			return NULL;
		}

		return ph->pShm->Attach();
	}

	TRACE("GfaIpcAcquirePointer: Invalid Handle!\n");
	return NULL;
}

/////////////////////////////////////////////////////////////////////////////

void GfaIpcReleasePointer(HSHM hShm, const void *p)
{
	if(!hShm)
	{
		TRACE("GfaIpcReleasePointer: Invalid Handle!\n");
		return;
	}

	LPSHM_HANDLE ph = (LPSHM_HANDLE)hShm;

	if(!ph->pShm)
	{
		TRACE("GfaIpcReleasePointer: Invalid Handle!\n");
		return;
	}

	ph->pShm->Detach(p);
}

/////////////////////////////////////////////////////////////////////////////

void GfaIpcLockSHM(HSHM hShm)
{
	if(!hShm)
	{
		TRACE("GfaIpcReleasePointer: Invalid Handle!\n");
		return;
	}

	LPSHM_HANDLE ph = (LPSHM_HANDLE)hShm;

	if(!ph->pShm)
	{
		TRACE("GfaIpcReleasePointer: Invalid Handle!\n");
		return;
	}

	ph->pShm->Lock();
}

/////////////////////////////////////////////////////////////////////////////

void GfaIpcUnlockSHM(HSHM hShm)
{
	if(!hShm)
	{
		TRACE("GfaIpcReleasePointer: Invalid Handle!\n");
		return;
	}

	LPSHM_HANDLE ph = (LPSHM_HANDLE)hShm;

	if(!ph->pShm)
	{
		TRACE("GfaIpcReleasePointer: Invalid Handle!\n");
		return;
	}

	ph->pShm->Unlock();
}

/////////////////////////////////////////////////////////////////////////////

void GfaIpcDumpSHMROT(void)
{
	if(!g_shmRot.Created())
	{
		if(!g_shmRot.Create())
		{
			TRACE("GfaIpcDumpSHMROT: Failed to create ROT!\n");
			return;
		}
	}

	g_shmRot.DumpEntries(g_shmHandleMap);
}

/////////////////////////////////////////////////////////////////////////////

long GfaIpcInterlockedIncrement(HSHM hShm, volatile long *pl)
{
	if(!hShm)
	{
		TRACE("GfaIpcInterlockedIncrement: Invalid Handle!\n");
		return 0;
	}

	LPSHM_HANDLE ph = (LPSHM_HANDLE)hShm;

	if(!ph->pShm)
	{
		TRACE("GfaIpcInterlockedIncrement: Invalid Handle!\n");
		return 0;
	}

	return ph->pShm->InterlockedIncrement(pl);
}

/////////////////////////////////////////////////////////////////////////////

long GfaIpcInterlockedDecrement(HSHM hShm, volatile long *pl)
{
	if(!hShm)
	{
		TRACE("GfaIpcInterlockedDecrement: Invalid Handle!\n");
		return 0;
	}

	LPSHM_HANDLE ph = (LPSHM_HANDLE)hShm;

	if(!ph->pShm)
	{
		TRACE("GfaIpcInterlockedDecrement: Invalid Handle!\n");
		return 0;
	}

	return ph->pShm->InterlockedDecrement(pl);
}

/////////////////////////////////////////////////////////////////////////////

long GfaIpcInterlockedCompare(HSHM hShm, volatile long *pl, long comparand)
{
	if(!hShm)
	{
		TRACE("GfaIpcInterlockedCompare: Invalid Handle!\n");
		return 0;
	}

	LPSHM_HANDLE ph = (LPSHM_HANDLE)hShm;

	if(!ph->pShm)
	{
		TRACE("GfaIpcInterlockedCompare: Invalid Handle!\n");
		return 0;
	}

	return ph->pShm->InterlockedCompare(pl, comparand);
}

/////////////////////////////////////////////////////////////////////////////

long GfaIpcInterlockedSet(HSHM hShm, volatile long *pl, long val)
{
	if(!hShm)
	{
		TRACE("GfaIpcInterlockedSet: Invalid Handle!\n");
		return 0;
	}

	LPSHM_HANDLE ph = (LPSHM_HANDLE)hShm;

	if(!ph->pShm)
	{
		TRACE("GfaIpcInterlockedSet: Invalid Handle!\n");
		return 0;
	}

	return ph->pShm->InterlockedSet(pl, val);
}

/////////////////////////////////////////////////////////////////////////////

long GfaIpcInterlockedClear(HSHM hShm, volatile long *pl)
{
	if(!hShm)
	{
		TRACE("GfaIpcInterlockedSet: Invalid Handle!\n");
		return 0;
	}

	LPSHM_HANDLE ph = (LPSHM_HANDLE)hShm;

	if(!ph->pShm)
	{
		TRACE("GfaIpcInterlockedClear: Invalid Handle!\n");
		return 0;
	}

	return ph->pShm->InterlockedClear(pl);
}
