/*
 * Copyright (c) 2019, 2023 Qualcomm Technologies, Inc.
 * All Rights Reserved.
 * Confidential and Proprietary - Qualcomm Technologies, Inc.
 */

#include <stdint.h>
#include <string.h>

#include "listener_handler.h"
#include "qsee_log.h"
#include "qsee_hash.h"
#include "qsee_heap.h"
#include "qsee_services.h"

void listener_handle_cmd(const struct listener_sendcmd_req *req,
                         struct listener_sendcmd_rsp *rsp)
{
  int error;
  int cleanup_error;

  struct listener_req listener_req;

  listener_req.cmd_id = LISTENER_CMD_1;
  listener_req.arg1 = 1;
  listener_req.arg2 = 2;
  
  struct listener_rsp listener_rsp = {0, 0, 0, 0};

  error = qsee_request_service(req->listener_id,
                               &listener_req,
                               sizeof(listener_req),
                               &listener_rsp,
                               sizeof(listener_rsp));

  if (error) {
    qsee_log(QSEE_LOG_MSG_ERROR, "qsee_request_service failed - error: %d", error);
    goto out;
  }

  qsee_log(QSEE_LOG_MSG_DEBUG, "Result from first listener call:");
  qsee_log(QSEE_LOG_MSG_DEBUG, "Result 1: %d", listener_rsp.result1);
  qsee_log(QSEE_LOG_MSG_DEBUG, "Result 2: %d", listener_rsp.result2);

  listener_req.cmd_id = LISTENER_CMD_2;
  listener_req.arg1 = 3;
  listener_req.arg2 = 4;

  error = qsee_request_service(req->listener_id,
                               &listener_req,
                               sizeof(listener_req),
                               &listener_rsp,
                               sizeof(listener_rsp));

  if (!error) {
    qsee_log(QSEE_LOG_MSG_DEBUG, "Result from second listener call:");
    qsee_log(QSEE_LOG_MSG_DEBUG, "Result 1: %d", listener_rsp.result1);
    qsee_log(QSEE_LOG_MSG_DEBUG, "Result 2: %d", listener_rsp.result2);
  } else {
    qsee_log(QSEE_LOG_MSG_ERROR, "qsee_request_service failed - error: %d", error);
    goto out;
  }

  listener_req.cmd_id = LISTENER_CMD_3_MODIFIED_RSP;

  /* Unused for this command. */
  listener_req.arg1 = 0;
  listener_req.arg2 = 0;

  error = qsee_request_service(req->listener_id,
                               &listener_req,
                               sizeof(listener_req),
                               &listener_rsp,
                               sizeof(listener_rsp));

  if (error) {
    qsee_log(QSEE_LOG_MSG_ERROR, "qsee_request_service failed - error: %d", error);
    goto out;
  }

  /*
   * As an example, we will hash a message and store the result in the shared buffer we received
   * in the modified response.
   */
  const char *message = "message";

  qsee_log(QSEE_LOG_MSG_DEBUG, "Hashing message '%s', storing result in buffer at addr %p.",
           message, listener_rsp.shared_buffer);

  error = qsee_register_shared_buffer(listener_rsp.shared_buffer, listener_rsp.shared_buffer_size);
  if (error) {
    qsee_log(QSEE_LOG_MSG_ERROR, "qsee_register_shared_buffer failed with error: %d", error);
    goto out;
  }

  error = qsee_prepare_shared_buf_for_secure_read(listener_rsp.shared_buffer,
                                                  listener_rsp.shared_buffer_size);
  if (error) {
    qsee_log(QSEE_LOG_MSG_ERROR,
             "qsee_prepare_shared_buf_for_secure_read failed with error: %d",
             error);

    (void)qsee_deregister_shared_buffer(listener_rsp.shared_buffer);
    goto out;
  }

  error = qsee_hash(QSEE_HASH_SHA256,
                    (const uint8_t *)message,
                    strlen(message),
                    listener_rsp.shared_buffer,
                    listener_rsp.shared_buffer_size);
  if (error) {
    qsee_log(QSEE_LOG_MSG_ERROR, "qsee_hash failed with error: %d", error);
  }

  cleanup_error = qsee_prepare_shared_buf_for_nosecure_read(listener_rsp.shared_buffer,
                                                    listener_rsp.shared_buffer_size);
  if (cleanup_error) {
    qsee_log(QSEE_LOG_MSG_ERROR,
             "qsee_prepare_shared_buf_for_nosecure_read failed with error: %d",
             cleanup_error);
    error = cleanup_error;
    goto out;
  }

  cleanup_error = qsee_deregister_shared_buffer(listener_rsp.shared_buffer);
  if (cleanup_error) {
    qsee_log(QSEE_LOG_MSG_ERROR, "qsee_deregister_shared_buffer failed with error: %d", error);
    error = cleanup_error;
  }
  
out:
  rsp->status = error ? LISTENER_FAILURE : LISTENER_SUCCESS;
}
