/**
 * @file persistent_object.c
 * @brief GP Persistent object implementation for qsee
 * @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 <comdef.h>
#include <qsee_services.h>

#include <tee_internal_api.h>
#include <tees_log.h>

#include <protocol.h>

PersObjectCmd g_po_cmd_buffer;

extern uint32_t g_listener_id;

static TEE_Result SendSimpleCommand(uint32_t command_id,
                                    const void *id, uint32_t id_len) {
  TEE_Result status = TEE_ERROR_BAD_PARAMETERS;

  if (!id || id_len > (MAX_PERSISTENT_OBJECT_ID_LEN - 1)) {
    goto exit;
  }

  if (g_listener_id == 0) {
    return TEE_ERROR_NOT_SUPPORTED;
  }

  TEE_MemFill(&g_po_cmd_buffer, 0x00, sizeof(g_po_cmd_buffer));

  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);

  qsee_request_service(g_listener_id,
                       &g_po_cmd_buffer, sizeof(g_po_cmd_buffer),
                       &g_po_cmd_buffer, sizeof(g_po_cmd_buffer));
  status = g_po_cmd_buffer.cmd_id;

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;
  }

  if (g_listener_id == 0) {
    return TEE_ERROR_NOT_SUPPORTED;
  }

  TEE_MemFill(&g_po_cmd_buffer, 0x00, sizeof(g_po_cmd_buffer));

  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);

  /* msm8974 API: void qsee_request_service(unsigned int listener_id, void *req,
   * unsigned int req_len, void *rsp, unsigned int rsplen); */
  /* msm8996 API:  int qsee_request_service(unsigned int listener_id, void *req,
   * unsigned int req_len, void *rsp, unsigned int rsplen); */
  qsee_request_service(g_listener_id,
                       &g_po_cmd_buffer, sizeof(g_po_cmd_buffer),
                       &g_po_cmd_buffer, sizeof(g_po_cmd_buffer));
  status = g_po_cmd_buffer.cmd_id;

  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;
  }

  if (g_listener_id == 0) {
    return TEE_ERROR_NOT_SUPPORTED;
  }

  TEE_MemFill(&g_po_cmd_buffer, 0x00, sizeof(g_po_cmd_buffer));
  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);

  /* msm8974 API: void qsee_request_service(unsigned int listener_id, void *req,
   * unsigned int req_len, void *rsp, unsigned int rsplen); */
  /* msm8996 API:  int qsee_request_service(unsigned int listener_id, void *req,
   * unsigned int req_len, void *rsp, unsigned int rsplen); */
  qsee_request_service(g_listener_id,
                       &g_po_cmd_buffer, sizeof(g_po_cmd_buffer),
                       &g_po_cmd_buffer, sizeof(g_po_cmd_buffer));
  status = g_po_cmd_buffer.cmd_id;

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;
  }

  if (g_listener_id == 0) {
    return TEE_ERROR_NOT_SUPPORTED;
  }

  TEE_MemFill(&g_po_cmd_buffer, 0x00, sizeof(g_po_cmd_buffer));

  g_po_cmd_buffer.cmd_id = PROTOCOL_COMMAND_LIST;
  g_po_cmd_buffer.data_len = *data_len;

  qsee_request_service(g_listener_id,
                       &g_po_cmd_buffer, sizeof(g_po_cmd_buffer),
                       &g_po_cmd_buffer, sizeof(g_po_cmd_buffer));
  status = g_po_cmd_buffer.cmd_id;

  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;
}
