#ifndef lint
static char *rcsid = "$Id: $";
#endif
/*
//	file name   :	$Source:  $
//	file version:	$Revision:  $
//
//	purpose:
//
//	author(s):		Ian Archer
//	date started:	march 2008
//	date changed:	$Date:  $
//	last change by:	$Author:  $
//
//	Licensed Materials - Property of IBM
//	© Copyright IBM Corporation 2002, 2008. All Rights Reserved.
*/

#include "RiDOSQNX.h"

#ifndef lint
static char *hrcsid = RiDOSQNX_H;
#endif

#include <oxf/RiCTypes.h>
#include <dox/RiDOSWrap.h>
#include <oxf/RiCMemoryManager.h>

#include <oxf/RiCOSQNX.h>

#include <stdio.h>

#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>


/* ******************************************************************** */
/* Remote Queue Connection interface */

/* creation and destruction functions */
RiDOSRemoteQConnection *  RiDOSRemoteQConnection_Create(const RhpString computerName, const RhpAddress queueId)
{
	RiDOSRemoteQConnection* res = (RiDOSRemoteQConnection*)RiCGetMemory(sizeof(RiDOSRemoteQConnection));
	if (res != NULL)
	{
		if (RiDOSRemoteQConnection_Init(res, computerName, queueId) == RiCFALSE)
		{
			RiDOSRemoteQConnection_Destroy(res);
			res = NULL;
		}
	}
	return res;
}

RiCBoolean RiDOSRemoteQConnection_Init(RiDOSRemoteQConnection * const me, const RhpString computerName, const RhpAddress queueKey)
{
	char			   * queueName = (char *) queueKey;
	char			   * QNXName = NULL;
	struct mq_attr		 queueAttr;
	RiCBoolean			 status = RiCFALSE;

	if(me != NULL)
	{
		// Find the queue - the queueKey is actaully the queue name!
		QNXName = RiCQNXOSAllocMem(strlen(queueName) + 1);
		if (QNXName != NULL)
		{
			sprintf(QNXName, "/%s", queueName);

			memset(&queueAttr, 0, sizeof(queueAttr));
			queueAttr.mq_maxmsg = QNX_DOX_MAX_MSGS;
			queueAttr.mq_msgsize = QNX_DOX_MSG_LEN;
			
			me->m_hQueue = mq_open(QNXName, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG, &queueAttr);

			if(me->m_hQueue == -1)
			{
			#ifdef RID_DEBUG
					RiDReportError("RiDOSRemoteQConnection_Init : Failed mq_open()");
			#endif 
			}
			else
			{
				status = RiCTRUE;
			}

			RiCQNXOSFreeMem(QNXName);
		}
		else
		{
		#ifdef RID_DEBUG
				RiDReportError("RiDOSRemoteQConnection_Init : Failed RiCQNXOSAllocMem");
		#endif 
		}
	}

	return status;
}

RiCBoolean RiDOSRemoteQConnection_Destroy(RiDOSRemoteQConnection * const me)
{
	RiCBoolean	status = RiCFALSE;

	if (RiDOSRemoteQConnection_Cleanup(me) == RiCTRUE)
	{
		RiCReturnMemory(me);
		status = RiCTRUE;
	}

	return status;
}

RiCBoolean RiDOSRemoteQConnection_Cleanup(RiDOSRemoteQConnection * const me)
{
	RiCBoolean	status = RiCFALSE;

	if (me != NULL)
	{
		me->m_hQueue = -1;
		status = RiCTRUE;
	}

	return status;
}

RiCBoolean RiDOSRemoteQConnection_SendMessage(RiDOSRemoteQConnection * const me, const RhpAddress msg, RhpPositive messageSize)
{
	RiCBoolean	status = RiCFALSE;

	if (messageSize <= QNX_DOX_MSG_LEN)
	{
		if (mq_send(me->m_hQueue, msg, messageSize, 0) == -1)
		{
			// Send failed, so tidy up
		#ifdef RID_DEBUG
			RiDReportError("RiDOSRemoteQConnection_SendMessage : Failed mq_send()");
		#endif
		}
		else
		{
			status = RiCTRUE;
		}
	}
	else
	{
		// Message is too long!
		#ifdef RID_DEBUG
			RiDReportErrorWithErrno("RiDOSRemoteQConnection_SendMessage : Msg is too big! ", messageSize);
		#endif
	}
	
	return status;
}


/*********************************************************************/
/* RidOSSharedMemory */

RiCBoolean RiDOSSharedMemory_Init(RiDOSSharedMemory* const me, const RhpString name, int blockSize)
{
	char	  *	QNXName = NULL;
	RiCBoolean	status = RiCFALSE;

	if (me != NULL)
	{
		me->m_shMemSize = 0;		// Assume failure!

		//create a Shared Memory region
		QNXName = RiCQNXOSAllocMem(strlen(name) + 1);
		if (QNXName != NULL)
		{
			sprintf(QNXName, "/%s", name);
			me->m_hSharedMemory = shm_open(QNXName, O_RDWR | O_CREAT, S_IRWXU | S_IRWXG);

			if (me->m_hSharedMemory < 0)
			{
			#ifdef RID_DEBUG
				RiDReportErrorWithErrno("RiDOSSharedMemory_Init : shm_open failed ", errno);
			#endif /* RID_DEBUG */
			}
			else
			{
				if (ftruncate(me->m_hSharedMemory, blockSize) == -1)
				{
				#ifdef RID_DEBUG
					RiDReportErrorWithErrno("RiDOSSharedMemory_Init : ftruncate failed ", errno);
				#endif /* RID_DEBUG */
				}
				else
				{
					// Map the requested size into our memory space
					me->m_lclAddr = mmap(0, blockSize, PROT_READ | PROT_WRITE, MAP_SHARED, me->m_hSharedMemory, 0);

					if (me->m_lclAddr == MAP_FAILED)
					{
					#ifdef RID_DEBUG
						RiDReportErrorWithErrno("RiDOSSharedMemory_Init : mmap failed ", errno);
					#endif /* RID_DEBUG */
					}
					else
					{
						status = RiCTRUE;
						me->m_shMemSize = blockSize;
					}
				}
			}
		}
		else
		{
		#ifdef RID_DEBUG
			RiDReportErrorWithErrno("RiDOSSharedMemory_Init : RiCQNXOSAllocMem failed ", errno);
		#endif /* RID_DEBUG */
		}
	}

	return status;
}

RiCBoolean RiDOSSharedMemory_Read(RiDOSSharedMemory* const me, int offset, int size, RhpAddress targetBuffer)
{
	char	  * pLocalBuf = NULL;
	RiCBoolean	status = RiCFALSE;

	if ((me != NULL) && (me->m_hSharedMemory != -1))
	{
		// Validate the size
		if ((offset + size) <= me->m_shMemSize)
		{
			// Copy the data
			pLocalBuf = (char *) me->m_lclAddr;
			memcpy(targetBuffer, pLocalBuf + offset, size);
			status = RiCTRUE;
		}
		else
		{
		#ifdef RID_DEBUG
			RiDReportErrorWithErrno("RiDOSSharedMemory_Read : invalid address!", offset + size);
		#endif /* RID_DEBUG */
		}
	}

	return status;
}

RiCBoolean RiDOSSharedMemory_Write(RiDOSSharedMemory* const me, int offset, int size, const RhpAddress buffer)
{
	char	  * pLocalBuf = NULL;
	RiCBoolean	status = RiCFALSE;

	if ((me != NULL) && (me->m_hSharedMemory != -1))
	{
		// Validate the size
		if ((offset + size) <= me->m_shMemSize)
		{
			// Copy the data
			pLocalBuf = (char *) me->m_lclAddr;
			memcpy(pLocalBuf + offset, buffer, size);
			status = RiCTRUE;
		}
		else
		{
		#ifdef RID_DEBUG
			RiDReportErrorWithErrno("RiDOSSharedMemory_Write : invalid address!", offset + size);
		#endif /* RID_DEBUG */
		}
	}

	return status;
}

RiCBoolean RiDOSSharedMemory_Close(RiDOSSharedMemory* const me)
{
	RiCBoolean	status = RiCFALSE;

	if ((me != NULL) && (me->m_hSharedMemory != -1))
	{
		//close the Shared Memory.
		close(me->m_hSharedMemory);
		me->m_hSharedMemory = -1;
		me->m_shMemSize = 0;

		status = RiCTRUE;
	}

	return status;
}

/* A function that allows the user to implement lock on the shared memory that is used by the instance registry.*/
/*## operation LockSharedMemory() */
void LockSharedMemory()
{

}

/* A function that allows the user to implement unlock on the shared memory that is used by the instance registry.*/
/*## operation UnlockSharedMemory() */
void UnlockSharedMemory()
{

}

/*
// $Log:  $
*/
