/*
*                    Copyright (c), NXP Semiconductors
*
*                       (C) NXP Semiconductors 2018
*
*         All rights are reserved. Reproduction in whole or in part is
*        prohibited without the written consent of the copyright owner.
*    NXP reserves the right to make changes without notice at any time.
*   NXP makes no warranty, expressed, implied or statutory, including but
*   not limited to any implied warranty of merchantability or fitness for any
*  particular purpose, or that the use will not infringe any third party patent,
*   copyright or trademark. NXP must not be liable for any loss or damage
*                            arising from its use.
*/

/* ********************************************************************************************
* Includes
* ****************************************************************************************** */
#include <stdio.h>
#include <string.h>
#include "Internal/NDEF_Heap.h"
#include "Internal/NDEF_RecordInternals.h"
#include "Records/NDEF_Rec_Text.h"

/* ********************************************************************************************
*  Definitions
* ******************************************************************************************* */

#define TEXT_ENCODING_MASK	0x80
#define TEXT_ENCODING_POS	7
#define TEXT_LANCODE_LEN_MASK	0x1F
#define TEXT_LANCODE_LEN_POS	0
#define TEXT_CLEAR_ENCODING(x)	(x)&=~TEXT_ENCODING_MASK
#define TEXT_CLEAR_LANGCODE_LEN(x)	(x)&=~TEXT_LANCODE_LEN_MASK	

#define TEXT_STATUSBYTE_LEN 1

#define TEXT_FLAGS_INIT_FLAGS 0x00

/* ********************************************************************************************
* Global and Static Variables
* Total Size: NNNbytes
* ******************************************************************************************* */

/* ********************************************************************************************
* Private Functions Prototypes
* ******************************************************************************************* */
static Status_t Text_SetEncoding(NDEF_Rec_Text_t * pRecord, NDEF_Rec_TextEncoding_t eEncoding);
static Status_t Text_SetLanguage(NDEF_Rec_Text_t * pRecord, const uint8_t * pLangCode, uint8_t bLength);
static Status_t Text_SetText(NDEF_Rec_Text_t *pRecord, const uint8_t * pPlainText, uint32_t dwLength);
static Status_t Text_SetTextLen(NDEF_Rec_Text_t *pRecord, uint32_t dwLength);
static Status_t Text_SetHeader(NDEF_Rec_Text_t * pRecord);


/* ********************************************************************************************
* Public Functions
* ******************************************************************************************* */

NDEF_Rec_Text_t * NDEF_Rec_Text_CreateByStr(const char * pLangCode, const char * pPlainText)
{
	NDEF_Rec_Text_t * pRecord;
	uint32_t dwPlainTextLen;
	RETURN_NULL_ON_NULL(pLangCode);
	RETURN_NULL_ON_NULL(pPlainText);
	dwPlainTextLen = strlen(pPlainText);
	pRecord = NDEF_Rec_Text_CreateByArray(pLangCode, Encoding_UTF8, pPlainText, dwPlainTextLen);
	return pRecord;
}


NDEF_Rec_Text_t * NDEF_Rec_Text_CreateByArray(const char * pLangCode, NDEF_Rec_TextEncoding_t eEncoding, const uint8_t * pPlainText, uint32_t dwLength)
{
	NDEF_Rec_Text_t * pRecord;
	Status_t status;
	uint8_t bLanCodeLen;
	uint8_t  bErrorFlag = 0;
	RETURN_NULL_ON_NULL(pLangCode);
	RETURN_NULL_ON_NULL(pPlainText);

	bLanCodeLen = strlen(pLangCode);
	do
	{
		pRecord = INT_MALLOC(sizeof(NDEF_Rec_Text_t));
		BREAK_ON_NULL(pRecord, bErrorFlag);
		memset(pRecord, 0, sizeof(NDEF_Rec_Text_t));

		pRecord->INT_sRecordInfo.eId = Type_Text;

		status = Text_SetEncoding(pRecord, eEncoding);
		BREAK_ON_FAILURE(status);

		status = Text_SetLanguage(pRecord, pLangCode, bLanCodeLen);
		BREAK_ON_FAILURE(status);

		status = Text_SetText(pRecord, pPlainText, dwLength);
		BREAK_ON_FAILURE(status);

		status = Text_SetHeader(pRecord);
		BREAK_ON_FAILURE(status);

	} while (0);
	if (bErrorFlag || status != NDEF_STATUS_SUCCESS)
	{
		NDEF_Rec_Destroy((void **)(&pRecord));
	}
	return pRecord;
}







Status_t NDEF_Rec_Text_GetPlainTextStr(const NDEF_Rec_Text_t * pRecord, char * pText, uint32_t  dwLength)
{
	uint32_t dwPlainTextLen;;

	RETURN_ON_NULL_PARAM(pRecord);
	RETURN_ON_NULL_PARAM(pText);
	RETURN_ON_NULL_MEMBER(pRecord->pPlainText);
	dwPlainTextLen = NDEF_Rec_Text_GetPlainTextLen(pRecord);
	if (dwPlainTextLen + NULL_TERM_LEN > dwLength)
	{
		return NDEF_STATUS_ERROR_BUFF_OVF;
	}
	memcpy(pText, pRecord->pPlainText, dwPlainTextLen);
	pText[dwPlainTextLen] = NULL_TERM;
	return NDEF_STATUS_SUCCESS;
}



Status_t NDEF_Rec_Text_GetPlainTextArray(const NDEF_Rec_Text_t * pRecord, uint8_t * pText, uint32_t  dwLength)
{
	uint32_t dwPlainTextLen;;

	RETURN_ON_NULL_PARAM(pRecord);
	RETURN_ON_NULL_PARAM(pText);
	RETURN_ON_NULL_MEMBER(pRecord->pPlainText);
	dwPlainTextLen = NDEF_Rec_Text_GetPlainTextLen(pRecord);
	if (dwPlainTextLen > dwLength)
	{
		return NDEF_STATUS_ERROR_BUFF_OVF;
	}
	memcpy(pText, pRecord->pPlainText, dwPlainTextLen);
	return NDEF_STATUS_SUCCESS;
}



uint32_t NDEF_Rec_Text_GetPlainTextLen(const NDEF_Rec_Text_t * pRecord)
{
	uint8_t bLangCodeLen;
	uint32_t retval;

	if (pRecord == NULL)
	{
		retval = 0;
	}
	else
	{
		bLangCodeLen = NDEF_Rec_Text_GetLanguageLen(pRecord);
		retval = pRecord->sHeader.dwPayloadLength - (uint32_t)(TEXT_STATUSBYTE_LEN + bLangCodeLen);
	}
	return retval;
}



NDEF_Rec_TextEncoding_t  NDEF_Rec_Text_GetEncoding(const NDEF_Rec_Text_t * pRecord)
{
	NDEF_Rec_TextEncoding_t retval;
	if (pRecord == NULL)
	{
		retval = 0;
	}
	else
	{
		retval = (NDEF_Rec_TextEncoding_t)((pRecord->bStatusByte & TEXT_ENCODING_MASK) >> TEXT_ENCODING_POS);
	}
	return retval;
}

uint8_t NDEF_Rec_Text_GetLanguageLen(const NDEF_Rec_Text_t * pRecord)
{
	uint8_t retval;
	if (pRecord == NULL)
	{
		retval = 0;
	}
	else
	{
		retval = (uint8_t)((pRecord->bStatusByte & TEXT_LANCODE_LEN_MASK) >> TEXT_LANCODE_LEN_POS);
	}
	return retval;
}

Status_t NDEF_Rec_Text_GetLanguageStr(const NDEF_Rec_Text_t * pRecord, char * pLangCode, uint16_t  bLength)
{
	uint8_t	 bLanguageCodeLen;

	RETURN_ON_NULL_PARAM(pRecord);
	RETURN_ON_NULL_PARAM(pLangCode);
	bLanguageCodeLen = NDEF_Rec_Text_GetLanguageLen(pRecord);
	if ((uint16_t)bLanguageCodeLen + NULL_TERM_LEN > bLength)
	{
		return NDEF_STATUS_ERROR_BUFF_OVF;
	}
	memcpy(pLangCode, pRecord->pLanguageCode, bLanguageCodeLen);
	pLangCode[bLanguageCodeLen] = NULL_TERM;
	return NDEF_STATUS_SUCCESS;
}

/* ********************************************************************************************
* Private Functions
* ******************************************************************************************* */
Status_t Text_SetEncoding(NDEF_Rec_Text_t * pRecord, NDEF_Rec_TextEncoding_t eEncoding)
{
	TEXT_CLEAR_ENCODING(pRecord->bStatusByte);
	pRecord->bStatusByte = (uint8_t)(eEncoding << TEXT_ENCODING_POS);
	return NDEF_STATUS_SUCCESS;
}
Status_t Text_SetLanguage(NDEF_Rec_Text_t * pRecord, const uint8_t * pLangCode, uint8_t bLength)
{
	void * pTemp;
	if (bLength)
	{
		pTemp = INT_REALLOC(pRecord->pLanguageCode, bLength);
		RETURN_ON_NULL_MEMBER(pTemp);
		pRecord->pLanguageCode = (uint8_t *)pTemp;

		TEXT_CLEAR_LANGCODE_LEN(pRecord->bStatusByte);
		pRecord->bStatusByte |= (uint8_t)(bLength << TEXT_LANCODE_LEN_POS);
		memcpy(pRecord->pLanguageCode, pLangCode, bLength);
	}
	else
	{
		TEXT_CLEAR_LANGCODE_LEN(pRecord->bStatusByte);
		INT_FREE(pRecord->pLanguageCode);
		pRecord->pLanguageCode = NULL;
	}
	return NDEF_STATUS_SUCCESS;
}



Status_t Text_SetText(NDEF_Rec_Text_t *pRecord, const uint8_t * pPlainText, uint32_t dwLength)
{
	void * pTemp;

	if (dwLength)
	{
		pTemp = INT_REALLOC(pRecord->pPlainText, dwLength);
		RETURN_ON_NULL_MEMBER(pTemp);
		pRecord->pPlainText = (uint8_t *)pTemp;

		Text_SetTextLen(pRecord, dwLength);
		memcpy(pRecord->pPlainText, pPlainText, dwLength);
		pRecord->INT_sRecordInfo.dwHeapUsedByPayload += dwLength;
	}
	else
	{
		Text_SetTextLen(pRecord, dwLength);
		INT_FREE(pRecord->pPlainText);
		pRecord->pPlainText = NULL;
	}
	return NDEF_STATUS_SUCCESS;
}


Status_t Text_SetHeader(NDEF_Rec_Text_t * pRecord)
{
	Status_t status;
	do
	{
		status = NDEF_Rec_SetTnf(pRecord, WellKnownTypeRecord);
		BREAK_ON_FAILURE(status);
		status = NDEF_Rec_SetType(pRecord, TEXT_TYPE_FIELD);
		BREAK_ON_FAILURE(status);
		status = NDEF_Rec_SetFlags(pRecord, TEXT_FLAGS_INIT_FLAGS);
		BREAK_ON_FAILURE(status);
	} while (0);
	return status;
}

Status_t Text_SetTextLen(NDEF_Rec_Text_t *pRecord, uint32_t dwLength)
{
	uint8_t bLanCodeLen;
	bLanCodeLen = NDEF_Rec_Text_GetLanguageLen(pRecord);
	pRecord->sHeader.dwPayloadLength = dwLength + bLanCodeLen + TEXT_STATUSBYTE_LEN;
	return NDEF_STATUS_SUCCESS;
}

/* ********************************************************************************************
* Internal functions - not part of API
* ******************************************************************************************* */
Status_t INT_Text_Free(void *pRecord)
{
	NDEF_Rec_Text_t * pRec;

	RETURN_ON_NULL_PARAM(pRecord);
	pRec = (NDEF_Rec_Text_t *)pRecord;
	INT_FREE(pRec->pPlainText);
	pRec->pPlainText = NULL;
	INT_FREE(pRec->pLanguageCode);
	pRec->pLanguageCode = NULL;

	return NDEF_STATUS_SUCCESS;
}

void * INT_Text_Parse(INT_FetchedHeader_t * pFetchedHeader, const uint8_t * pInput)
{
	NDEF_Rec_Text_t * pRecord = NULL;
	uint32_t dwOffset;
	uint32_t dwPlainTextLen;
	uint8_t bLanguageLen;
	uint8_t bErrorFlag = 0;

	dwOffset = pFetchedHeader->dwOffsetToPayload;
	pRecord = INT_MALLOC(sizeof(NDEF_Rec_Text_t));
	RETURN_NULL_ON_NULL(pRecord);
	memset(pRecord, 0, sizeof(NDEF_Rec_Text_t));
	pRecord->INT_sRecordInfo.eId = Type_Text;
	memcpy(&pRecord->sHeader, &pFetchedHeader->sHeader, sizeof(NDEF_Record_Header_t));
	if (pFetchedHeader->sHeader.dwPayloadLength)
	{
		do
		{
			pRecord->bStatusByte = pInput[dwOffset++];
			bLanguageLen = NDEF_Rec_Text_GetLanguageLen(pRecord);
			pRecord->pLanguageCode = INT_MALLOC(sizeof(uint8_t)*bLanguageLen);
			BREAK_ON_NULL(pRecord->pLanguageCode, bErrorFlag);
			memcpy(pRecord->pLanguageCode, &pInput[dwOffset], bLanguageLen);
			dwOffset += bLanguageLen;
			dwPlainTextLen = NDEF_Rec_Text_GetPlainTextLen(pRecord);
			pRecord->pPlainText = INT_MALLOC(sizeof(uint8_t)*dwPlainTextLen);
			BREAK_ON_NULL(pRecord->pPlainText, bErrorFlag);
			memcpy(pRecord->pPlainText, &pInput[dwOffset], dwPlainTextLen);
		} while (0);

	}
	if (bErrorFlag)
	{
		INT_FREE(pRecord->pLanguageCode);
		INT_FREE(pRecord->pPlainText);
		INT_FREE(pRecord);
	}
	return pRecord;
}

Status_t INT_Text_Serialize(void *pRecord, uint8_t * pOutput, uint32_t * pOffset)
{
	Status_t status;
	uint32_t dwPlainTextLen;
	uint8_t bLangCodeLen;
	uint32_t dwOffset;
	NDEF_Rec_Text_t * pRec;

	pRec = (NDEF_Rec_Text_t *)pRecord;
	dwOffset = *pOffset;

	status = INT_Header_Serialize(pRecord, pOutput, &dwOffset);

	pOutput[dwOffset] = pRec->bStatusByte;
	dwOffset += TEXT_STATUSBYTE_LEN;

	bLangCodeLen = NDEF_Rec_Text_GetLanguageLen(pRec);
	memcpy(&pOutput[dwOffset], pRec->pLanguageCode, bLangCodeLen);
	dwOffset += bLangCodeLen;

	dwPlainTextLen = NDEF_Rec_Text_GetPlainTextLen(pRec);
	memcpy(&pOutput[dwOffset], pRec->pPlainText, dwPlainTextLen);
	dwOffset += dwPlainTextLen;

	*pOffset = dwOffset;
	return status;
}


