/**
 * @file persistent_object.c
 * @brief GP Persistent object implementation for <t-base
 * @author Iaroslav Makarchuk (i.makarchuk@samsung.com)
 * @date Created Oct 3, 2016
 * @par In Samsung Ukraine R&D Center (SURC) under a contract between
 * @par LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine) and
 * @par "Samsung Elecrtronics Co", Ltd (Seoul, Republic of Korea)
 * @par Copyright: (c) Samsung Electronics Co, Ltd 2015. All rights reserved.
 *
 * This software is proprietary of Samsung Electronics.
 * No part of this software, either material or conceptual may be copied
 * or distributed, transmitted, transcribed, stored in a retrieval system
 * or translated into any human or computer language in any form by any means,
 * electronic, mechanical, manual or otherwise, or disclosed to third parties
 * without the express written permission of Samsung Electronics.
 */

#include "tlStd.h"
#include "TlApi/TlApi.h"
#include <tee_internal_api.h>

#include <tees_log.h>
#include <protocol.h>

extern PersObjectCmd *g_po_cmd_buffer;
extern ProtocolCmd *g_cmd_buffer;

static TEE_Result SendSimpleCommand(uint32_t command_id,
                                    const uint8_t *id, uint32_t id_len) {
  TEE_Result status = TEE_ERROR_BAD_PARAMETERS;

  if (!id || id_len > (MAX_PERSISTENT_OBJECT_ID_LEN - 1)) {
    goto exit;
  }

  TEE_MemFill(g_po_cmd_buffer, 0x00, sizeof(PersObjectCmd));

  g_po_cmd_buffer->cmd_id = command_id;
  g_po_cmd_buffer->id_len = id_len;
  TEE_MemMove(g_po_cmd_buffer->id, id, id_len);

  /* Process request by client */
  tlApiNotify();
  /* Go on working */
  tlApiWaitNotification(TLAPI_INFINITE_TIMEOUT);

  status = g_cmd_buffer->cmd_ret;

exit:
  return status;
}

TEE_Result ReadFromPO(const uint8_t *id,
                      uint32_t id_len,
                      uint8_t *data,
                      uint32_t *data_len,
                      MultibuildFsStoreDataType data_type) {
  TEE_Result status = TEE_ERROR_BAD_PARAMETERS;

  if (!data || !data_len || !id ||
      id_len > (MAX_PERSISTENT_OBJECT_ID_LEN - 1)) {
    goto exit;
  }

  TEE_MemFill(g_po_cmd_buffer, 0x00, sizeof(PersObjectCmd));

  switch (data_type) {
    case MB_FS_STORE_METADATA: {
      g_po_cmd_buffer->cmd_id = PROTOCOL_COMMAND_READMD;
      break;
    }
    case MB_FS_STORE_ATTRIB: {
      g_po_cmd_buffer->cmd_id = PROTOCOL_COMMAND_READATTR;
      break;
    }
    default: {
      g_po_cmd_buffer->cmd_id = PROTOCOL_COMMAND_READF;
    }
    break;
  }

  g_po_cmd_buffer->data_len = *data_len;
  g_po_cmd_buffer->id_len = id_len;
  TEE_MemMove(g_po_cmd_buffer->id, id, id_len);

  /* Process request by client */
  tlApiNotify();
  /* Go on working */
  tlApiWaitNotification(TLAPI_INFINITE_TIMEOUT);

  status = g_cmd_buffer->cmd_ret;

  if (TEE_SUCCESS == status) {
    TEE_MemMove(data, g_po_cmd_buffer->data, g_po_cmd_buffer->data_len);
    *data_len = g_po_cmd_buffer->data_len;
  }

exit:
  return status;
}

TEE_Result WriteToPO(const uint8_t *id,
                     uint32_t id_len,
                     const uint8_t *data,
                     uint32_t data_len,
                     MultibuildFsStoreDataType data_type) {
  TEE_Result status = TEE_ERROR_BAD_PARAMETERS;

  if (!data || !id || id_len > (MAX_PERSISTENT_OBJECT_ID_LEN - 1) ||
      data_len > MAX_PERSISTENT_OBJECT_DATA_LEN) {
    goto exit;
  }

  TEE_MemFill(g_po_cmd_buffer, 0x00, sizeof(PersObjectCmd));

  switch (data_type) {
    case MB_FS_STORE_METADATA: {
      g_po_cmd_buffer->cmd_id = PROTOCOL_COMMAND_WRITEMD;
      break;
    }
    case MB_FS_STORE_ATTRIB: {
      g_po_cmd_buffer->cmd_id = PROTOCOL_COMMAND_WRITEATTR;
      break;
    }
    default: {
      g_po_cmd_buffer->cmd_id = PROTOCOL_COMMAND_WRITEF;
    }
    break;
  }
  TEE_MemMove(g_po_cmd_buffer->data, data, data_len);
  g_po_cmd_buffer->data_len = data_len;
  g_po_cmd_buffer->id_len = id_len;
  TEE_MemMove(g_po_cmd_buffer->id, id, id_len);

  /* Process request by client */
  tlApiNotify();
  /* Go on working */
  tlApiWaitNotification(TLAPI_INFINITE_TIMEOUT);

  status = g_cmd_buffer->cmd_ret;

exit:
  return status;
}

TEE_Result RemovePO(const uint8_t *id, uint32_t id_len) {
  return SendSimpleCommand(PROTOCOL_COMMAND_DELETE, id, id_len);
}

TEE_Result StartObjectUpdate(const void *id, uint32_t id_len) {
  return SendSimpleCommand(PROTOCOL_COMMAND_INIT_UPDATE, id, id_len);
}

TEE_Result CommitObjectUpdate(const void *id, uint32_t id_len) {
  return SendSimpleCommand(PROTOCOL_COMMAND_COMMIT_UPDATE, id, id_len);
}

void AbortObjectUpdate(const void *id, uint32_t id_len) {
  if (TEE_SUCCESS !=
      SendSimpleCommand(PROTOCOL_COMMAND_ABORT_UPDATE, id, id_len)) {
    MB_LOGE("Object update abortion failed\n");
  }
}

TEE_Result ListObjects(uint8_t *data, uint32_t *data_len) {
  TEE_Result status = TEE_ERROR_BAD_PARAMETERS;

  if (!data || !data_len) {
    goto exit;
  }

  TEE_MemFill(g_po_cmd_buffer, 0x00, sizeof(PersObjectCmd));

  g_po_cmd_buffer->cmd_id = PROTOCOL_COMMAND_LIST;
  g_po_cmd_buffer->data_len = *data_len;

  /* Process request by client */
  tlApiNotify();
  /* Go on working */
  tlApiWaitNotification(TLAPI_INFINITE_TIMEOUT);

  status = g_cmd_buffer->cmd_ret;

  if (TEE_SUCCESS == status) {
    TEE_MemMove(data, g_po_cmd_buffer->data, g_po_cmd_buffer->data_len);
    *data_len = g_po_cmd_buffer->data_len;
  }

exit:
  return status;
}
