// SPDX-License-Identifier: GPL-2.0-or-later AND LGPL-2.0-or-later AND LGPL-2.1-or-later

#include <string.h>
#include <stdlib.h>
#include <errno.h>

#include "mvb_heap.h"
#include "mvb_heap_impl.h"

#include "mvb_heap_debug.h"

int32_t mvb_log_level = LOG_OFF;

#ifdef USE_MVB_HEAP_ION_LEGACY
#include "mvb_heap_ion_legacy.h"
#endif
#ifdef USE_MVB_HEAP_ION_LATEST
#include "mvb_heap_ion_latest.h"
#endif

static struct mvb_heap_desc_t _descs[] = {
#ifdef USE_MVB_HEAP_ION_LEGACY
  {
    .mvb_heap_name = "ion_legacy",
    .mvb_heap_ops  = &mvb_heap_ops_ion_legacy,
  },
#endif
#ifdef USE_MVB_HEAP_ION_LATEST
  {
    .mvb_heap_name = "ion_latest",
    .mvb_heap_ops  = &mvb_heap_ops_ion_latest,
  },
#endif
  {
    .mvb_heap_name = NULL,
    .mvb_heap_ops  = NULL,
  },
};

static struct mvb_heap_ops_t*
_get_ops_by_name (const char* mvb_heap_name)
{
  MVB_LOGD ("try heap name: %s", mvb_heap_name);

  for (int i = 0; _descs[i].mvb_heap_name != NULL; i++)
  {
    if (strcmp (mvb_heap_name, _descs[i].mvb_heap_name) == 0)
    {
      return _descs[i].mvb_heap_ops;
    }
  }

  return NULL;
}

int
mvb_slot_get_size (struct mvb_slot_t* slot)
{
  return slot->size;
}

int
mvb_slot_get_fd (struct mvb_slot_t* slot)
{
  return slot->fd;
}

void*
mvb_slot_mmap (struct mvb_slot_t* slot)
{
  int ret;

  if (slot == NULL || slot->parent == NULL || slot->parent->ops == NULL || slot->parent->ops->slot_mmap == NULL)
    return NULL;

  ret = slot->parent->ops->slot_mmap (slot);
  if (ret != MVB_RET_OK) {
    MVB_LOGE ("fail to map");
    return NULL;
  }

  return slot->va;
}

void
mvb_slot_umap (struct mvb_slot_t* slot)
{
  int ret;

  if (slot == NULL || slot->parent == NULL || slot->parent->ops == NULL || slot->parent->ops->slot_mmap == NULL)
    return;

  ret = slot->parent->ops->slot_umap (slot);
  if (ret != MVB_RET_OK) {
    MVB_LOGE ("fail to umap");
  }
}

uint32_t
mvb_slot_get_flag (struct mvb_slot_t* slot)
{
  return slot->mvb_flag;
}

struct mvb_slot_t*
mvb_heap_alloc_slot (struct mvb_heap_t* p_mvb_heap, int size, uint32_t mvb_flag)
{
  struct mvb_slot_t* slot = NULL;

  MVB_LOGD ("begin, size: %d flag: %x", size, mvb_flag);

  if (p_mvb_heap == NULL)
    return NULL;

  if (p_mvb_heap->ops == NULL)
    return NULL;

  slot           = (struct mvb_slot_t*) malloc (sizeof (struct mvb_slot_t));
  slot->parent   = p_mvb_heap;

  p_mvb_heap->ops->slot_init (slot, size, mvb_flag);

  MVB_LOGD ("end, alloc slot %p", slot);
  return slot;
}

void
mvb_heap_free_slot (struct mvb_slot_t* slot)
{
  MVB_LOGD ("begin, %p", slot);

  if (slot == NULL) {
    MVB_LOGE ("slot == NULL");
    return;
  }

  if (slot->parent == NULL) {
    MVB_LOGE ("slot->parent == NULL");
    return;
  }

  slot->parent->ops->slot_deinit (slot);

  free (slot);

  MVB_LOGD ("end");
}

struct mvb_heap_t*
mvb_heap_create (const char* heap_name)
{
  struct mvb_heap_t* p_mvb_heap = (struct mvb_heap_t*) malloc (sizeof (struct mvb_heap_t));

  MVB_LOGD ("begin");

  if (p_mvb_heap == NULL) {
    MVB_LOGE ("fail malloc memory for mvb heap");
    return NULL;
  }

  p_mvb_heap->ops = _get_ops_by_name (heap_name);

  if (p_mvb_heap->ops == NULL) {
    MVB_LOGE ("fail malloc memory for mvb heap");
    return NULL;
  }


  p_mvb_heap->ops->heap_init (p_mvb_heap);

  MVB_LOGD ("end");

  return p_mvb_heap;
}

void
mvb_heap_destroy (struct mvb_heap_t* p_mvb_heap)
{
  MVB_LOGD ("begin");

  if (p_mvb_heap == NULL) {
    MVB_LOGE ("invalid mvb heap pointer");
    return;
  }

  if (p_mvb_heap->ops == NULL) {
    MVB_LOGE ("invalid ops");
    return;
  }

  p_mvb_heap->ops->heap_deinit (p_mvb_heap);

  free (p_mvb_heap);

  MVB_LOGD ("end");
}





