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

#include "CLogSinkExample_open.h"
#include "ITALog_invoke.h"
#include "qsee_heap.h"
#include "qsee_log.h"
#include "object.h"
#include <stdio.h>

#define MAX_BUF_LEN   (64)

/* This file gives an example of a Log Sink implementation as defined by the
 * ILogSink interface.
 *
 * When a log sink is registered by the TA, all the logs of the TA, produced by
 * qsee_log(), are routed to the CLogSink_onLog() function implemented in this
 * file (in addition to the normal qsee_log() buffer).
 *
 * In this CLogSink_onLog() implementation, we copy the last message that passed
 * through this log sink. We also maintain a counter of the number of messages
 * that were processed by this sink.
 *
 * Upon release of the log sink object, we will print the following information:
 * last message received, its priority, its length and the number of messages
 * that were processed by the log sink.
 */

typedef struct {
  char buf[MAX_BUF_LEN];
  uint8_t pri;
  size_t msgLen;
  unsigned int nbMsgs;
  int refs;
} CLogSink;

static int32_t CLogSink_onLog(CLogSink *me, uint8_t pri, const char *msg,
                              size_t msgLen)
{
  /* The following qsee_log call will not be printed. This is expected as the
   * qsee_log mask is cleared when we call the _onLog() method.
   * The mask is cleared to avoid infinite recursion when dealing with logs.
   *
   * Manipulating the qsee_log mask within this function should be avoided.
   */
  qsee_log(QSEE_LOG_MSG_ERROR, "__This won't be printed___");

  /* As an implementation example, we store the last message handled by the log
   * sink. On release of the sink, all fields will be printed.
   */
  snprintf(me->buf, sizeof(me->buf), "%s", msg);
  me->pri = pri;
  me->msgLen = msgLen;
  me->nbMsgs++;

  return Object_OK;
}

static int32_t CLogSink_retain(CLogSink *me)
{
  ++me->refs;
  return Object_OK;
}

static int32_t CLogSink_release(CLogSink *me)
{
  if (--me->refs == 0) {
    /* Print info about the last message that was stored in this sink. */
    qsee_log(QSEE_LOG_MSG_ERROR, "Last LogSink buf: %s", me->buf);
    qsee_log(QSEE_LOG_MSG_ERROR, "Last LogSink pri: %hhu", me->pri);
    qsee_log(QSEE_LOG_MSG_ERROR, "Last LogSink msgLen: %zu", me->msgLen);
    qsee_log(QSEE_LOG_MSG_ERROR, "LogSink nbMsgs: %u", me->nbMsgs);

    qsee_free(me);
  }

  return Object_OK;
}

static ILogSink_DEFINE_INVOKE(CLogSink_invoke, CLogSink_, CLogSink *);

int32_t CLogSink_open(Object *objOut)
{
  CLogSink *me = QSEE_ZALLOC_TYPE(CLogSink);
  if (me == NULL) {
    qsee_log(QSEE_LOG_MSG_ERROR, "Memory allocation for CLogSink failed!");
    return Object_ERROR_MEM;
  }

  me->nbMsgs = 0;
  me->refs = 1;
  *objOut = (Object) { CLogSink_invoke, me };

  return Object_OK;
}
