/*
*                    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_Uri.h"

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


#define URI_FLAGS_INIT_FLAGS 0x00


#define URI_ID_CODE_LEN 1
#define URI_SET_URIFIELD_LEN(x) pRecord->sHeader.dwPayloadLength=(URI_ID_CODE_LEN+(x))
#define URI_GET_URIFIELD_LEN(x) (x)=(pRecord->sHeader.dwPayloadLength - URI_ID_CODE_LEN)
#define URIPREFIX_LIST_SIZE	(sizeof(pUriPrefix)/sizeof(*pUriPrefix))
#define URI_GET_URIPREFIX_LEN(x,y) ((y)=strlen(pUriPrefix[(x)]))

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

static const char * pUriPrefix[] = { NULL_TERM, "http://www.", "https://www.", "http://", "https://", "tel:", "mailto:", "ftp://anonymous:anonymous@", "ftp://ftp.",
"ftps://", "sftp://", "smb://", "nfs://", "ftp://", "dav://", "news:", "telnet://", "imap:", "rtsp://", "urn:", "pop:", "sip:", "sips:", "tftp:", "btspp://", "btl2cap://",
"btgoep://", "tcpobex://", "irdaobex://", "file://", "urn:epc:id:", "urn:epc:tag:", "urn:epc:pat:", "urn:epc:raw:", "urn:epc:", "urn:nfc:" };

/* ********************************************************************************************
* Private Functions Prototypes
* ******************************************************************************************* */
static Status_t Uri_SetHeader(NDEF_Rec_Uri_t * pRecord);
static Status_t Uri_SetUri(NDEF_Rec_Uri_t * pRecord, const uint8_t * pUriField, uint32_t dwLength);
static Status_t Uri_SetIdCode(NDEF_Rec_Uri_t * pRecord, uint8_t  bIdCode);
static  uint32_t Uri_GetUriFieldLen(const NDEF_Rec_Uri_t * pRecord);


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

NDEF_Rec_Uri_t * NDEF_Rec_Uri_CreateByStr(uint8_t bIdCode, const char * pUriField)
{
	NDEF_Rec_Uri_t * pRecord = NULL;
	uint32_t dwUriLen;
	if (pUriField != NULL)
	{
		dwUriLen = strlen(pUriField);
		pRecord = NDEF_Rec_Uri_CreateByArray(bIdCode, pUriField, dwUriLen);
	}
	return pRecord;
}


NDEF_Rec_Uri_t * NDEF_Rec_Uri_CreateByArray(uint8_t bIdCode, const uint8_t * pUriField, uint32_t dwLength)
{
	NDEF_Rec_Uri_t * pRecord;
	Status_t status;
	RETURN_NULL_ON_NULL(pUriField);
	uint8_t  bErrorFlag = 0;
	do
	{
		pRecord = INT_MALLOC(sizeof(NDEF_Rec_Uri_t));
		BREAK_ON_NULL(pRecord, bErrorFlag);
		memset(pRecord, 0, sizeof(NDEF_Rec_Uri_t));

		pRecord->INT_sRecordInfo.eId = Type_Uri;

		status = Uri_SetUri(pRecord, pUriField, dwLength);
		BREAK_ON_FAILURE(status);

		status = Uri_SetIdCode(pRecord, bIdCode);
		BREAK_ON_FAILURE(status);

		status = Uri_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_Uri_GetUri(const NDEF_Rec_Uri_t * pRecord, char * pUri, uint32_t  dwLength)
{
	uint8_t	 bUriPrefixLen;
	uint32_t dwUriFieldLen;

	RETURN_ON_NULL_PARAM(pRecord);
	RETURN_ON_NULL_PARAM(pUri);
	RETURN_ON_NULL_MEMBER(pRecord->pUriField);
	URI_GET_URIPREFIX_LEN(pRecord->bIdentifierCode, bUriPrefixLen);
	URI_GET_URIFIELD_LEN(dwUriFieldLen);
	if (bUriPrefixLen + dwUriFieldLen + NULL_TERM_LEN > dwLength)
	{
		return NDEF_STATUS_ERROR_BUFF_OVF;
	}
	memcpy(pUri, pUriPrefix[pRecord->bIdentifierCode], bUriPrefixLen);
	memcpy((pUri + bUriPrefixLen), pRecord->pUriField, dwUriFieldLen);
	pUri[bUriPrefixLen + dwUriFieldLen] = NULL_TERM;
	return NDEF_STATUS_SUCCESS;
}


Status_t NDEF_Rec_Uri_GetUriField(const NDEF_Rec_Uri_t * pRecord, uint8_t * pUriField, uint32_t  dwLength)
{
	uint32_t dwUriFieldLen;

	RETURN_ON_NULL_PARAM(pRecord);
	RETURN_ON_NULL_PARAM(pUriField);
	RETURN_ON_NULL_MEMBER(pRecord->pUriField);
	URI_GET_URIFIELD_LEN(dwUriFieldLen);
	if (dwUriFieldLen > dwLength)
	{
		return NDEF_STATUS_ERROR_BUFF_OVF;
	}
	memcpy(pUriField, pRecord->pUriField, dwUriFieldLen);
	return NDEF_STATUS_SUCCESS;
}


uint32_t NDEF_Rec_Uri_GetUriLen(const NDEF_Rec_Uri_t * pRecord)
{
	uint32_t retval;
	uint8_t prefixlen;
	if (pRecord == NULL)
	{
		retval = 0;
	}
	else
	{
		URI_GET_URIFIELD_LEN(retval);
		URI_GET_URIPREFIX_LEN(pRecord->bIdentifierCode, prefixlen);
		retval += prefixlen;
	}

	return retval;
}


/* ********************************************************************************************
* Private Functions
* ******************************************************************************************* */
Status_t Uri_SetHeader(NDEF_Rec_Uri_t * pRecord)
{
	Status_t status;
	do
	{
		status = NDEF_Rec_SetTnf(pRecord, WellKnownTypeRecord);
		BREAK_ON_FAILURE(status);
		status = NDEF_Rec_SetType(pRecord, URI_TYPE_FIELD);
		BREAK_ON_FAILURE(status);
		status = NDEF_Rec_SetFlags(pRecord, URI_FLAGS_INIT_FLAGS);
		BREAK_ON_FAILURE(status);
	} while (0);
	return status;
}

Status_t Uri_SetUri(NDEF_Rec_Uri_t * pRecord, const uint8_t * pUriField, uint32_t  dwLength)
{
	void * pTemp;

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

		URI_SET_URIFIELD_LEN(dwLength);
		memcpy(pRecord->pUriField, pUriField, dwLength);
		pRecord->INT_sRecordInfo.dwHeapUsedByPayload = dwLength;
	}
	else
	{
		pRecord->INT_sRecordInfo.dwHeapUsedByPayload = dwLength;
		URI_SET_URIFIELD_LEN(dwLength);
		INT_FREE(pRecord->pUriField);
	}
	return NDEF_STATUS_SUCCESS;
}

static Status_t Uri_SetIdCode(NDEF_Rec_Uri_t * pRecord, uint8_t  bIdCode)
{
	pRecord->bIdentifierCode = bIdCode;
	return NDEF_STATUS_SUCCESS;
}

uint32_t Uri_GetUriFieldLen(const NDEF_Rec_Uri_t * pRecord)
{
	uint32_t retval;
	if (pRecord == NULL)
	{
		retval = 0;
	}
	else
	{
		URI_GET_URIFIELD_LEN(retval);
	}
	return retval;
}





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

	RETURN_ON_NULL_PARAM(pRecord);
	pRec = (NDEF_Rec_Uri_t *)pRecord;
	if (pRec->INT_sRecordInfo.dwHeapUsedByPayload != 0)
	{
		INT_FREE(pRec->pUriField);
		pRec->INT_sRecordInfo.dwHeapUsedByPayload = 0;
		pRec->pUriField = NULL;
	}
	return NDEF_STATUS_SUCCESS;
}


Status_t INT_Uri_Serialize(void *pRecord, uint8_t * pOutput, uint32_t *pOffset)
{
	Status_t status;
	uint32_t dwUriFieldLen;
	uint32_t dwOffset;
	NDEF_Rec_Uri_t * pRec;
	pRec = (NDEF_Rec_Uri_t *)pRecord;
	dwOffset = *pOffset;
	status = INT_Header_Serialize(pRecord, pOutput, &dwOffset);
	pOutput[dwOffset] = pRec->bIdentifierCode;
	dwOffset += URI_ID_CODE_LEN;
	dwUriFieldLen = Uri_GetUriFieldLen(pRec);
	memcpy(&pOutput[dwOffset], pRec->pUriField, dwUriFieldLen);
	dwOffset += dwUriFieldLen;
	*pOffset = dwOffset;
	return status;
}

void * INT_Uri_Parse(INT_FetchedHeader_t * pFetchedHeader, const uint8_t * pInput)
{
	NDEF_Rec_Uri_t * pRecord;
	uint8_t bErrorFlag = 0;
	uint32_t dwOffset;
	uint32_t dwUriFieldLen;

	dwOffset = pFetchedHeader->dwOffsetToPayload;
	pRecord = INT_MALLOC(sizeof(NDEF_Rec_Uri_t));
	RETURN_NULL_ON_NULL(pRecord);
	memset(pRecord, 0, sizeof(NDEF_Rec_Uri_t));
	pRecord->INT_sRecordInfo.eId = Type_Uri;
	memcpy(&pRecord->sHeader, &pFetchedHeader->sHeader, sizeof(NDEF_Record_Header_t));
	if (pFetchedHeader->sHeader.dwPayloadLength)
	{
		do
		{
			pRecord->bIdentifierCode = pInput[dwOffset++];
			dwUriFieldLen = pRecord->sHeader.dwPayloadLength - URI_ID_CODE_LEN;
			pRecord->pUriField = INT_MALLOC(sizeof(uint8_t)*dwUriFieldLen);
			BREAK_ON_NULL(pRecord->pUriField, bErrorFlag);
			memcpy(pRecord->pUriField, &pInput[dwOffset], dwUriFieldLen);
		} while (0);
	}
	if (bErrorFlag)
	{
		INT_FREE(pRecord->pUriField);
		INT_FREE(pRecord);
	}
	return pRecord;
}
