#include <string.h>
#include <stdlib.h>
#include "sr_log.h"
#include "sr_osal.h"
#include "fal.h"
#include "fal_part.h"
#include "fal_def.h"

#define DBG_TAG "drv.fal_part"

static const fal_part_info_t fal_part_info[] = SR_FAL_PART_DEF;

static fal_part_t *fal_part_table = SR_NULL;
static const int fal_part_table_size = sizeof(fal_part_info) / sizeof(fal_part_info[0]);

void fal_show_part_table(void)
{
    char *item1 = "name", *item2 = "flash_dev";
    size_t i, part_name_max = strlen(item1), flash_dev_name_max = strlen(item2);
    struct fal_part *part;

    part = &fal_part_table[0];
    for (i = 0; i < fal_part_table_size; i++, part++)
    {
        if (strlen(part->info->name) > part_name_max)
        {
            part_name_max = strlen(part->info->name);
        }
        if (strlen(part->info->flash_name) > flash_dev_name_max)
        {
            flash_dev_name_max = strlen(part->info->flash_name);
        }
    }

    SR_Printf("==================== FAL partition table ====================\r\n");
    SR_Printf("| %-*.*s | %-*.*s |   offset   |    length  |\r\n",
              part_name_max,
              FAL_DEV_NAME_MAX,
              item1,
              flash_dev_name_max,
              FAL_DEV_NAME_MAX,
              item2);
    SR_Printf("-------------------------------------------------------------\r\n");

    part = &fal_part_table[0];
    for (i = 0; i < fal_part_table_size; i++, part++)
    {
        SR_Printf("| %-*.*s | %-*.*s | 0x%08lx | 0x%08x |\r\n",
                  part_name_max,
                  FAL_DEV_NAME_MAX,
                  part->info->name,
                  flash_dev_name_max,
                  FAL_DEV_NAME_MAX,
                  part->info->flash_name,
                  part->info->offset,
                  part->info->size);
    }
    SR_Printf("=============================================================\r\n");
}

int fal_part_init(void)
{
    int i;
    fal_flash_t *flash_dev = NULL;

    fal_part_table = SR_OsCalloc(fal_part_table_size, sizeof(fal_part_t));
    SR_ASSERT(fal_part_table);

    for (i = 0; i < fal_part_table_size; i++)
    {
        flash_dev = fal_flash_find(fal_part_info[i].flash_name);
        if (flash_dev == NULL)
        {
            SR_LOG(ERR, "Initialize failed! Didn't find the flash device(%s).\r\n", fal_part_info[i].flash_name);
            SR_OsFree(fal_part_table);
            fal_part_table = SR_NULL;
            return -1;
        }

        if (fal_part_info[i].offset >= flash_dev->len)
        {
            SR_LOG(ERR,
                   "Initialize failed! Partition(%s) offset address(%ld) out of flash bound(<%d).\r\n",
                   fal_part_info[i].name,
                   fal_part_info[i].offset,
                   flash_dev->len);
            SR_OsFree(fal_part_table);
            fal_part_table = SR_NULL;
            return -1;
        }

        fal_part_table[i].info = (fal_part_info_t *)&fal_part_info[i];
        fal_part_table[i].flash = flash_dev;
        // fal_part_table[i].flags = fal_part_info[i].flags;
    }

    // fal_show_part_table();

    return 0;
}
SR_INIT_COMPONENT_EXPORT(fal_part_init, SR_PRIORITY_1);

// OS_INIT_CALL(fal_part_init, OS_INIT_LEVEL_DEVICE, OS_INIT_SUBLEVEL_LOW);

fal_part_t *fal_part_find(const char *name)
{
    int i;

    // SR_ASSERT(fal_part_table != SR_NULL);
    if (fal_part_table == SR_NULL)
        return SR_NULL;

    for (i = 0; i < fal_part_table_size; i++)
    {
        if (!strcmp(name, fal_part_table[i].info->name))
        {
            return &fal_part_table[i];
        }
    }

    return SR_NULL;
}

int fal_part_read(fal_part_t *part, uint32_t offset, uint8_t *buf, size_t size)
{
    int ret = 0;

    fal_flash_t *flash_dev = SR_NULL;

    if (!part || !part->flash || !buf)
        return SR_INVALID;

    if (offset + size > part->info->size)
    {
        SR_LOG(ERR, "Part Read Err, addr out of bound.");
        return SR_EBOUND;
    }

    flash_dev = part->flash;

    ret = flash_dev->ops.read(flash_dev, part->info->offset + offset, buf, size);

    return ret;
}

int fal_part_write(fal_part_t *part, uint32_t offset, uint8_t *buf, size_t size)
{
    int ret = 0;

    fal_flash_t *flash_dev = SR_NULL;

    if (!part || !part->flash || !buf)
        return SR_INVALID;

    if (offset + size > part->info->size)
    {
        SR_LOG(ERR, "Part write Err, addr out of bound.");
        return SR_EBOUND;
    }

    flash_dev = part->flash;

    ret = flash_dev->ops.write(flash_dev, part->info->offset + offset, buf, size);

    return ret;
}

int fal_part_erase(fal_part_t *part, uint32_t blkId, size_t blkNum)
{
    int ret = 0;
    fal_flash_t *flash_dev = SR_NULL;

    if (!part || !part->flash)
        return SR_INVALID;

    flash_dev = part->flash;

    if (((blkId + blkNum) * flash_dev->blk_size) > part->info->size)
    {
        SR_LOG(ERR, "Part erase Err, addr out of bound.");
        return SR_EBOUND;
    }

    ret = flash_dev->ops.erase_block(flash_dev, part->info->offset + blkId * flash_dev->blk_size, blkNum);

    return ret;
}

int fal_part_erase_all(fal_part_t *part)
{
    fal_flash_t *flash_dev = SR_NULL;

    if (!part || !part->flash)
        return SR_INVALID;

    flash_dev = part->flash;

    return fal_part_erase(part, 0, part->info->size / flash_dev->blk_size);
}


//获取分区起始的实际物理地址
uint32_t fal_part_get_phyaddr(fal_part_t *part)
{
    int ret = 0;
    fal_flash_t *flash_dev = SR_NULL;

    if (!part || !part->flash)
        return SR_INVALID;

    flash_dev = part->flash;

    //分区起始的实际物理地址 = flash物理基地址+分区偏移
    return flash_dev->addr + part->info->offset;

}

