/**********************************************************************
 * Copyright (c) 2005, 2009 IBM Corporation and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * $Id: RADataTransfer.c,v 1.4 2009/04/14 20:33:28 jwest Exp $
 * 
 * Contributors: 
 * IBM - Initial API and implementation
 **********************************************************************/

#include <stdlib.h>
#include "RADataTransfer.h"
#include "RASharedMemory.h"   /* 175248 - added */
#include <stdio.h>

#define RA_MESSAGE_HEADER_SIZE  0x000a


/** ALLOCATE_MESSAGE_BLOCK  ************************************************
  * Allocates a block of memory that can be used for a message and returns
  * the address where the caller can start adding data.
  * IMPORTANT:  must use ra_freeMessageBlock to free the memory when done
  * @param  length  - the number of bytes required for the message
  * @returns        - the address where the message can be written to.  NULL if
  *                   there is no available memory.
  */
unsigned char *ra_allocateMessageBlock(ra_uint_t length) {
	ra_uint_t size=length+RA_MESSAGE_HEADER_SIZE;
	void *p=(void*)malloc(size);
	if(p==NULL) {
		return NULL;
	}
	return ((unsigned char*)p+RA_MESSAGE_HEADER_SIZE);
}

/** REALLOCATE_MESSAGE_BLOCK  ************************************************
  * Recieves an existing message block and allocates a block of memory with the
  * newley specified size.  The data in the existing message block is copied
  * to the new message block.
  * IMPORTANT:  must use ra_freeMessageBlock to free the memory when done
  * @param  message - the existing message block.
  * @param  length  - the number of bytes required for the new message
  * @returns        - the address where the message can be written to.  NULL if
  *                   there is no available memory.
  */
unsigned char *ra_reallocateMessageBlock(unsigned char *message,
										 ra_uint_t length) {
	ra_uint_t size=length+RA_MESSAGE_HEADER_SIZE;
	void *p=(void*)realloc((void*)(message-RA_MESSAGE_HEADER_SIZE), size);
	if(p==NULL) {
		if(size==0) {
			return NULL;
		}
		return message;
	}
	return ((unsigned char*)p+RA_MESSAGE_HEADER_SIZE);
}


/** FREE_MESSAGE_BLOCK  ************************************************
  * Free's a block of message memory
  * @param message - the address returned by ra_allocateMessageBlock
  */
void ra_freeMessageBlock(unsigned char *message) {
	free((void*)(message-RA_MESSAGE_HEADER_SIZE));
}


/** WRITE_MESSAGE_BLOCK *************************************************
  * Writes a message to the specified target using the specified format.
  * DNS changed @param from fd - the target SOCKET object to the following
  * @param  dthdl  - the handle of the target to write the data to.
  * @param  format - the format to use
  * @param message - the address of the start of the message.
  * @param  length - the number of bytes to write to fd.
  * @returns       - the number of bytes written to the socket.
  */
/* DNS extern unsigned short ra_writeMessageBlock(SOCKET fd, */
ra_uint_t ra_writeMessageBlock(ra_data_target_hdl_t *dthdl,
										   dataFormat_t format,
										   unsigned char *message,
										   ra_uint_t length) {
	ra_uint_t bytesWritten=0;

	if (!dthdl || !message) {
		return 0; 
	}
	/* Place the majic header */
	message[-10]=(unsigned char)(RA_MAGIC>>24);
	message[-9]=(unsigned char)(RA_MAGIC>>16);
	message[-8]=(unsigned char)(RA_MAGIC>>8);
	message[-7]=(unsigned char)(RA_MAGIC);

	/* Place the endian bits in the header */
	message[-6]=0xff;
	
	/* Place the length in the header */
	message[-5]=(unsigned char)(length>>24 & 0x000000ff);
	message[-4]=(unsigned char)(length>>16 & 0x000000ff);
	message[-3]=(unsigned char)(length>>8  & 0x000000ff);
	message[-2]=(unsigned char)length;

	/* Place the format specifier in the message */
	message[-1]=format;

	/* Write to the proper device */
	if ( dthdl->dtarget == RA_SOCKET ) {
	   bytesWritten=ra_writeToSocket(dthdl->dtargetHdl.socketFD,
							(char*)&message[-RA_MESSAGE_HEADER_SIZE],
							(length+RA_MESSAGE_HEADER_SIZE));

/*    DNS changed return value by subtracting the header size
          because that is what the user expects */
	   if(bytesWritten>0) {
		   return bytesWritten-RA_MESSAGE_HEADER_SIZE;
	   }
	   else {
		   return 0;
	   }
	}
	else if ( dthdl->dtarget == RA_SHAREDMEMORY ) {
	   ra_uint_t length2 = length + RA_MESSAGE_HEADER_SIZE;
      ra_uint_t rc;   /* 194539 */
	   /* Write to the shared memory buffer */
	   rc = ra_writeToShm((OSSRambo *)dthdl->dtargetHdl.shmHdl,   /* 175248 */
					&message[-RA_MESSAGE_HEADER_SIZE],
  					(length2));
/* 194539 begin */
      if (0 != rc ) {
   		ra_setLastError(SHM_WRITE_FAILED, rc);
         return 0;
      }
      else {
/* 194539 end */
         return (length2 - RA_MESSAGE_HEADER_SIZE);
      }  /* 194539 */
   }
/* TO DO DNS - add code to write to a file */
	else {
      return 0;
	}
}
