/*******************************************************************************
 * Copyright (c) 2005, 2009 Intel Corporation.
 * 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
 *
 * Contributors:
 *    Hoang Nguyen, Intel - Initial API and implementation
 * $Id: dime.c,v 1.18 2009/08/26 14:59:54 jwest Exp $ 
 *
 *******************************************************************************/ 
#include "tptp/TPTPUtils.h"
#include "tptp/TPTPCommon.h"
#include "tptp/TPTPTypes.h"
#include "tptp/TPTPUtils.h"
#include "tptp/TPTPErrorCode.h"
#include "tptp/dime.h"

#include "tptp/TPTPMessageHeader.h"


#include <stdio.h>
#ifndef _WIN32
#include <string.h>
#endif

static void swap(char *bytes, tptp_int32 num_bytes) 
{
	tptp_int32 i, j;
	char c;
	i = 0;
	j = num_bytes-1;

	while (i<j) {
		c = bytes[i];
		bytes[i] = bytes[j];
		bytes[j] = c;
		i = i + 1;
		j = j - 1;
	}
}

tptp_int32 init_dime_header(DIME_HEADER_PTR_T p)
{
	p->version 		= DIME_VERSION;
	p->mb	   		= 0;		/* initialize as 0 */
	p->me	   		= 0;		/* initialize as 0*/
	p->cf	   		= 0;		/* initialize as 0 */
	p->type_t  		= TYPE_T_NONE;		
	p->resrvd  		= RESRVD_VALUE;
	p->options_length 	= 0;	/* not using options */
	p->type_length 		= 0;	/* not using type */
	p->id_length 		= 0;
	p->data_length 		= 0;

	return 0;
}

// TPTP_DIME_LITTLE_ENDIAN is used (rather than LITTLE_ENDIAN) so that it does not conflict with the defines in the OS's endian.h
#if !(defined(__linux__) && defined(__s390__)) && !(defined(_SOLARIS)) && !(defined(_AIX)) && !defined(MVS)
	#define TPTP_DIME_LITTLE_ENDIAN
#endif

tptp_int32 make_dime_header(char *p)
{

	#ifdef TPTP_DIME_LITTLE_ENDIAN
		swap(p+ID_LENGTH_OFFSET, 2);
		swap(p+TYPE_LENGTH_OFFSET, 2);
		swap(p+OPTIONS_LENGTH_OFFSET, 2);
		swap(p+DATA_LENGTH_OFFSET, 4);
	#endif

	return 0 ;
}


tptp_int32 print_dime_header(DIME_HEADER_PTR_T p)
{
	printf(" The id length %x \n", p->id_length);
	printf(" The data length %x \n", p->data_length);

	return 0 ;
}

tptp_int32 construct_dime_file_transfer(DIME_HEADER_PTR_T *p, char *fileName, tptp_int32 dataSize)
{
	return construct_dime_file_transfer_error(p, fileName, dataSize, TPTP_OK);
}

tptp_int32 construct_dime_file_transfer_error(DIME_HEADER_PTR_T *p, char *fileName, tptp_int32 dataSize, int errCode)
{
	tptp_int32 status;
	tptp_int32 fileNameLength = strlen(fileName)+1;
	tptp_int32 dime_len;
	char *q;

#ifdef MVS
	char * nativeFileName = 0;
	native2unicode(&nativeFileName, (char *)fileName, strlen(fileName));
	fileNameLength = strlen(nativeFileName) + 1;
#endif

	dime_len = sizeof(DIME_HEADER_T) + fileNameLength + 1;
	*p = (DIME_HEADER_PTR_T) tptp_malloc(dime_len);
	status = INIT_DIME_HEADER(*p);
	/* (*p)->data_length = buffer_length; */

	(*p)->id_length = fileNameLength;
	q = ((char *) *p + sizeof(DIME_HEADER_T));
#ifdef MVS
	strcpy(q, nativeFileName);
	if(nativeFileName != 0) {
		tptp_free(nativeFileName);
	}
#else
	strcpy(q, fileName);
#endif

	(*p)->data_length = (tptp_uint32) dataSize;
	/*(*p)->data = buffer; we don't add the buffer to avoid the copy */

	(*p)->options_length = 1;
	*(q + fileNameLength) = (char) errCode;

	return dime_len; /* may have to add options + type */
}


tptp_int32 construct_dime_console(DIME_HEADER_PTR_T *p,  PID processId, tptp_int32 consoleType, tptp_int32 dataSize)
{
	char  buffer[128] ;
	char  prefix ;

	switch (consoleType)
	{
		case TPTP_STDOUT: prefix = 'O' ; break ;
		case TPTP_STDIN:  prefix = 'I' ; break ;
		case TPTP_STDERR: prefix = 'E' ; break ;
		default:          prefix = 'U' ; break ;
	}

	buffer[0] = prefix ;
	sprintf(buffer+1, "%lu", (unsigned long)processId) ;

	return (construct_dime_file_transfer(p, buffer, dataSize)) ;
}

void free_dime (DIME_HEADER_PTR_T p) 
{
	tptp_free (p);
}

tptp_int32  is_valid_header(DIME_HEADER_PTR_T p, tptp_int32 amount_read)
{

	if (p->data_length == amount_read - sizeof(DIME_HEADER_T) - p->id_length) {
		return 1;
	} else {
		//printf(" Bad header %d %d %d %d", sizeof(DIME_HEADER_T), p->data_length, p->id_length, amount_read);
		return 0;
	}
}

char *get_dime_id(DIME_HEADER_PTR_T p)
{
	char* fileName;
	char *q;

	fileName = (char *) tptp_malloc(p->id_length);

	q = ((char *) p + sizeof(DIME_HEADER_T));
	memcpy(fileName, q, p->id_length);

	return fileName;
}

tptp_int32 get_dime_length(DIME_HEADER_PTR_T p)
{
	return sizeof(DIME_HEADER_T) + p->id_length + p->options_length;
}

PID get_dime_process_id(DIME_HEADER_PTR_T p)
{
	char *pIdName = get_dime_id(p) ;

	PID processId = TPTP_INVALID_PID ;

	sscanf(pIdName+1, "%lu", &processId) ;

	tptp_free(pIdName) ;

	return processId;
}

tptp_int32 get_dime_console_type(DIME_HEADER_PTR_T p)
{
	tptp_int32 consoleType = -1 ;

	char *pIdName = get_dime_id(p) ;

	switch (pIdName[0])
	{
		case 'O': consoleType = TPTP_STDOUT ; break ;
		case 'I': consoleType = TPTP_STDIN ;  break ;
		case 'E': consoleType = TPTP_STDERR ; break ;
	}

	tptp_free(pIdName) ;

	return consoleType;
}
