#include <string.h>

#include "SfsFileOperations.h"
#include "CommLayerData.h"
#include "log.h"

#include "qsee_fs.h"
#include "qsee_sfs.h"

#define MAX_DIR_LEN 128

static inline int32_t _createDir(const char* path)
{
	char dir[MAX_DIR_LEN] = {0};
	int32_t len = 0;

	len = (int32_t)strlen(path);
	--len;
	while (len >= 0 && path[len] != '/') {
		--len;
	}

	if (len <= 0 ) {
		LOGE("Wrong path fomat");
		return WRONG_DATA;
	}

	if (sizeof(dir) <= len) {
		LOGE("Directory path is too long");
		return WRONG_DATA;
	}

	strncpy(dir, path, len);
	dir[len] = '\0';

	return qsee_sfs_mkdir(dir);
}

int32_t getKeySize(const char* path, uint32_t* size)
{
	int32_t fd = qsee_sfs_open(path, O_RDONLY);
	if (fd == 0) {
		LOGE("sfs_open() FAILED! returned = %ld", fd);
		/* assume that open fails when file doesn't exist
		* QSEE API doesn't provide other way to determine wether file exists */
		return NO_KEY_ERROR;
	}

	*size = (uint32_t)qsee_sfs_seek(fd, 0, SEEK_END);
	qsee_sfs_close(fd);

	return NO_ERROR;
}

int32_t readKeyFromSFS(const char* path, uint8_t* keyBlob, uint32_t length, uint32_t pos)
{
	int32_t res = PLATFORM_INTERNAL_ERROR;
	int32_t fd = 0;

	/* qsee_sfs_init( 4096 ); */
	res = _createDir(path);
	if (res != 0) {
		LOGE("sfs_mkdir() FAILED! returned = %ld", res);
		return PLATFORM_INTERNAL_ERROR;
	}

	fd = qsee_sfs_open( path, O_RDONLY );
	if (fd == 0) {
		LOGE("sfs_open() FAILED! path = %s, returned = %ld", path, fd);
		/* assume that open fails when file doesn't exist
		* QSEE API doesn't provide other way to determine wether file exists */
		return NO_KEY_ERROR;
	}

	if (pos != 0)
		qsee_sfs_seek( fd, pos, SEEK_SET );
 
	res = qsee_sfs_read( fd, (char *)keyBlob, length );
	if (res <= 0 || res != length) {
		LOGE("sfs_read() FAILED! returned = %ld", res);
		qsee_sfs_close( fd );
		return SFS_READ_ERROR;
	}

	res = qsee_sfs_close( fd );
	if (res != 0) {
		LOGE("sfs_close() FAILED! returned = %ld", res);
		return PLATFORM_INTERNAL_ERROR;
	}

	return NO_ERROR;
}

int32_t saveKeyToSFS(const char* path, const uint8_t* keyBlob, uint32_t length, const uint8_t* trailer, uint32_t trailerLen)
{
	int32_t res = PLATFORM_INTERNAL_ERROR;
	int32_t fd = 0;

	LOGD("SFS: Writing %u bytes to %s", length, path);

	if ((NULL == path) || (NULL == keyBlob)) {
		LOGE("sfs_mkdir() bad path or data input!");
		return PLATFORM_INTERNAL_ERROR;
	}

	/* qsee_sfs_init(4096); */
	res = _createDir(path);
	if (res != 0) {
		LOGE("sfs_mkdir() FAILED! returned = %ld", res);
		return PLATFORM_INTERNAL_ERROR;
	}

	fd = qsee_sfs_open(path, O_RDWR | O_CREAT | O_TRUNC);
	if (fd == 0) {
		LOGE("sfs_open() FAILED! returned = %ld", fd);
		return PLATFORM_INTERNAL_ERROR;
	}

	res = qsee_sfs_write(fd, (const char*)keyBlob, length);
	if (res <= 0) {
		LOGE("sfs_write() FAILED! returned = %ld", res);
		qsee_sfs_close(fd);
		return PLATFORM_INTERNAL_ERROR;
	}
	LOGE("sfs_write() OK! returned = %ld", res);

	if (trailer && trailerLen > 0) {
		res = qsee_sfs_write(fd, (const char*)trailer, trailerLen);
		if (res <= 0) {
			LOGE("sfs_write() FAILED! returned = %ld", res);
			qsee_sfs_close(fd);
			return PLATFORM_INTERNAL_ERROR;
		}
	}

	res = qsee_sfs_close(fd);
	if (res != 0) {
		LOGE("sfs_close() FAILED! returned = %ld", res);
		return PLATFORM_INTERNAL_ERROR;
	}

	return NO_ERROR;
}

void qsee_oem_set_kdf_derive_key(void **key, int32_t *key_len)
{
	*key_len = 32;
	*key = NULL; 
}

int32_t removeFile(const char* path)
{
	if (qsee_sfs_rm(path) != 0) {
		return PLATFORM_INTERNAL_ERROR;
	} else {
		return NO_ERROR;
	}
}