#include <string.h>

/* WHD resource API */
#include "whd_resource_api.h"

/* Private resource storage identifiers */
#include "whd_port/resources/whd_resources.h"

#define RESOURCE_FIRMWARE_NAME cyw43362a2_firmware_image
#define RESOURCE_FIRMWARE_SIZE sizeof(RESOURCE_FIRMWARE_NAME)

/* CYW43362A2 does not have CLM */
#define RESOURCE_CLM_NAME
#define RESOURCE_CLM_SIZE    0

#define RESOURCE_NVRAM_NAME  cyw43362a2_nvram_image
#define RESOURCE_NVRAM_SIZE  sizeof(RESOURCE_NVRAM_NAME)

#define RESOURCE_BUFFER_SIZE 512

static uint8_t  s_resource_buf[RESOURCE_BUFFER_SIZE];

static uint32_t resource_block_size(whd_driver_t whd_drv, whd_resource_type_t type, uint32_t *size_out) {
    *size_out = RESOURCE_BUFFER_SIZE;

    return WHD_SUCCESS;
}

static uint32_t resource_size(whd_driver_t whd_drv, whd_resource_type_t resource, uint32_t *size_out) {
    switch (resource) {
        case WHD_RESOURCE_WLAN_FIRMWARE:
            *size_out = RESOURCE_FIRMWARE_SIZE;
            break;
        case WHD_RESOURCE_WLAN_NVRAM:
            *size_out = RESOURCE_NVRAM_SIZE;
            break;
        case WHD_RESOURCE_WLAN_CLM:
            *size_out = RESOURCE_CLM_SIZE;
            break;
        default:
            *size_out = 0;
            break;
    }
    return WHD_SUCCESS;
}

static uint32_t resource_no_of_blocks(whd_driver_t whd_drv, whd_resource_type_t type, uint32_t *block_count) {
    uint32_t res_sz = 0U;
    uint32_t blk_sz = 0U;

    resource_size(whd_drv, type, &res_sz);
    resource_block_size(whd_drv, type, &blk_sz);
    *block_count = res_sz / blk_sz;
    if (res_sz % blk_sz) *block_count += 1;

    return WHD_SUCCESS;
}

static uint32_t resource_block(whd_driver_t whd_drv, whd_resource_type_t type, uint32_t blockno, const uint8_t **data,
                               uint32_t *size_out) {
    uint32_t ret    = WHD_SUCCESS;
    uint32_t res_sz = 0U;
    uint32_t blk_sz = 0U;

    ret = resource_size(whd_drv, type, &res_sz);
    if (ret != WHD_SUCCESS) {
        return ret;
    }

    ret = resource_block_size(whd_drv, type, &blk_sz);
    if (ret != WHD_SUCCESS) {
        return ret;
    }

    switch (type) {
        case WHD_RESOURCE_WLAN_FIRMWARE: {
            uint32_t size_left = res_sz - blk_sz * blockno;
            uint32_t size_copy = blk_sz;
            if (size_left < blk_sz) {
                size_copy = size_left;
            }

            memcpy(s_resource_buf, (uint8_t *)(RESOURCE_FIRMWARE_NAME + blk_sz * blockno), size_copy);
            *data     = s_resource_buf;
            *size_out = size_copy;

            break;
        }

        default:
            break;
    }
    return WHD_SUCCESS;
}

whd_resource_source_t resource_ops = {
    .whd_resource_size             = resource_size,
    .whd_get_resource_block_size   = resource_block_size,
    .whd_get_resource_no_of_blocks = resource_no_of_blocks,
    .whd_get_resource_block        = resource_block,
};