// *****************************************************************************
// * message.c
// *
// * Code for manipulating the incoming and outgoing messages in a flat
// * memory buffer.
// *
// * Copyright 2010 by Ember Corporation. All rights reserved.              *80*
// *****************************************************************************

#include "app/framework/include/af.h"
#include "app/framework/util/util.h"
#include "app/framework/util/config.h"

//------------------------------------------------------------------------------

// these variables are for storing responses that are created by zcl-utils
// in functions called from emberIncomingMsgHandler. The response is sent
// from emberAfTick (meant to be called immediately after emberTick).
// There is only space for one response as each call to emberTick will
// only result in a single call to emberIncomingMsgHandler. If the device
// receives multiple ZCL messages, the stack will queue these and hand
// these to the application via emberIncomingMsgHandler one at a time.
EmberApsFrame emberAfResponseApsFrame;
EmberNodeId        emberAfResponseDestination;
uint8_t appResponseData[EMBER_AF_RESPONSE_BUFFER_LEN];
uint16_t appResponseLength;

// Used for empty string
static uint16_t zeroLenByte = 0;
static uint8_t* zeroLenBytePtr = (uint8_t *)&zeroLenByte;

//------------------------------------------------------------------------------
// Utilities for adding bytes to the response buffer: appResponseData. These
// functions take care of incrementing appResponseLength.

void emberAfClearResponseData(void)
{
  emberAfResponseType = ZCL_UTIL_RESP_NORMAL;
  // To prevent accidentally sending to someone else,
  // set the destination to ourselves.
  emberAfResponseDestination = emberAfGetNodeId();
  MEMSET(appResponseData, 0, EMBER_AF_RESPONSE_BUFFER_LEN);
  appResponseLength = 0;
  MEMSET(&emberAfResponseApsFrame, 0, sizeof(EmberApsFrame));
}

uint8_t * emberAfPutInt8uInResp(uint8_t value)
{
	//emberAfDebugPrint("try %x max %x\r\n", appResponseLength, EMBER_AF_RESPONSE_BUFFER_LEN);
	if (appResponseLength < EMBER_AF_RESPONSE_BUFFER_LEN) {
		//emberAfDebugPrint("put %x at spot %x\r\n", value, appResponseLength);
		appResponseData[appResponseLength] = value;
		appResponseLength++;
		return &appResponseData[appResponseLength - 1];
	}

	return NULL;
}

uint16_t * emberAfPutInt16uInResp(uint16_t value)
{
	uint8_t * low = emberAfPutInt8uInResp(LOW_BYTE(value));
	uint8_t * high = emberAfPutInt8uInResp(HIGH_BYTE(value));

	if (low && high) {
		return (uint16_t *) low;
	} else {
		return NULL;
	}
}

uint32_t * emberAfPutInt32uInResp(uint32_t value)
{
	uint8_t * a =  emberAfPutInt8uInResp(BYTE_0(value));
	uint8_t * b =  emberAfPutInt8uInResp(BYTE_1(value));
	uint8_t * c =  emberAfPutInt8uInResp(BYTE_2(value));
	uint8_t * d =  emberAfPutInt8uInResp(BYTE_3(value));

	if (a && b && c && d) {
		return (uint32_t *)a;
	} else {
		return NULL;
	}
}

uint32_t * emberAfPutInt24uInResp(uint32_t value)
{
	uint8_t * a = emberAfPutInt8uInResp(BYTE_0(value));
	uint8_t * b = emberAfPutInt8uInResp(BYTE_1(value));
	uint8_t * c = emberAfPutInt8uInResp(BYTE_2(value));

	if (a && b && c) {
		return (uint32_t *) a;
	} else {
		return NULL;
	}
}

uint8_t * emberAfPutBlockInResp(const uint8_t* data, uint16_t length)
{
	if ((appResponseLength + length) < EMBER_AF_RESPONSE_BUFFER_LEN) {
		MEMMOVE(appResponseData + appResponseLength, data, length);
		appResponseLength += length;
		return &appResponseData[appResponseLength - length];
	} else {
		return NULL;
	}
}

uint8_t * emberAfPutStringInResp(const uint8_t *buffer)
{
  uint8_t length = emberAfStringLength(buffer);
  return emberAfPutBlockInResp(buffer, length + 1);
}

uint8_t * emberAfPutDateInResp(EmberAfDate *value)
{
  uint8_t * a = emberAfPutInt8uInResp(value->year);
  uint8_t * b = emberAfPutInt8uInResp(value->month);
  uint8_t * c = emberAfPutInt8uInResp(value->dayOfMonth);
  uint8_t * d = emberAfPutInt8uInResp(value->dayOfWeek);

  if (a && b && c && d) {
    return a;
  } else {
    return NULL;
  }
}

// ------------------------------------
// Utilities for reading from RAM buffers (reading from incoming message
// buffer)
// ------------------------------------

// retrieves an uint32_t which contains between 1 and 4 bytes of relevent data
// depending on number of bytes requested.
uint32_t emberAfGetInt(const uint8_t* message,
							uint16_t currentIndex,
							uint16_t msgLen,
							uint8_t bytes)
{
	uint32_t result = 0;
	uint8_t i = bytes;
	if ((currentIndex + bytes) > msgLen) {
		emberAfDebugPrintln("GetInt, %x bytes short", bytes);
		emberAfDebugFlush();
		return 0;
	}
	while (i > 0) {
		result = (result << 8) + message[(currentIndex + i) - 1];
		i--;
	}
	return result;
}

uint32_t emberAfGetInt32u(const uint8_t* message, uint16_t currentIndex, uint16_t msgLen)
{
	return emberAfGetInt(message, currentIndex, msgLen, 4);
}

uint32_t emberAfGetInt24u(const uint8_t* message, uint16_t currentIndex, uint16_t msgLen)
{
	return emberAfGetInt(message, currentIndex, msgLen, 3);
}

uint16_t emberAfGetInt16u(const uint8_t* message, uint16_t currentIndex, uint16_t msgLen)
{
	return (uint16_t)emberAfGetInt(message, currentIndex, msgLen, 2);
}

uint8_t* emberAfGetString(uint8_t* message, uint16_t currentIndex, uint16_t msgLen)
{
  // Strings must contain at least one byte for the length.
  if (msgLen <= currentIndex) {
    emberAfDebugPrintln("GetString: %p", "buffer too short");
    return zeroLenBytePtr;
  }

  // Starting from the current index, there must be enough bytes in the message
  // for the string and the length byte.
  if (msgLen < currentIndex + emberAfStringLength(&message[currentIndex]) + 1) {
    emberAfDebugPrintln("GetString: %p", "len byte wrong");
    return zeroLenBytePtr;
  }

  return &message[currentIndex];
}

uint8_t* emberAfGetLongString(uint8_t* message, uint16_t currentIndex, uint16_t msgLen)
{
  // Long strings must contain at least two bytes for the length.
  if (msgLen <= currentIndex + 1) {
    emberAfDebugPrintln("GetLongString: %p", "buffer too short");
    return zeroLenBytePtr;
  }

  // Starting from the current index, there must be enough bytes in the message
  // for the string and the length bytes.
  if (msgLen
      < currentIndex + emberAfLongStringLength(&message[currentIndex]) + 2) {
    emberAfDebugPrintln("GetLongString: %p", "len bytes wrong");
    return zeroLenBytePtr;
  }

  return &message[currentIndex];
}

uint8_t emberAfStringLength(const uint8_t *buffer)
{
	// The first byte specifies the length of the string.  A length of 0xFF means
	// the string is invalid and there is no character data.
	return (buffer[0] == 0xFF ? 0 : buffer[0]);
}

uint16_t emberAfLongStringLength(const uint8_t *buffer)
{
	// The first two bytes specify the length of the long string.  A length of
	// 0xFFFF means the string is invalid and there is no character data.
	uint16_t length = emberAfGetInt16u(buffer, 0, 2);
	return (length == 0xFFFF ? 0 : length);
}

uint8_t emberAfGetDate(uint8_t* message,
                       uint16_t currentIndex,
                       uint16_t msgLen,
                       EmberAfDate *destination)
{
  if ((currentIndex + 4) > msgLen) {
    emberAfDebugPrintln("GetDate, %x bytes short", 4);
    emberAfDebugFlush();
    return 0;
  }
  destination->year       = message[(currentIndex + 0)];
  destination->month      = message[(currentIndex + 1)];
  destination->dayOfMonth = message[(currentIndex + 2)];
  destination->dayOfWeek  = message[(currentIndex + 3)];
  return 4;
}
