#include "unittest.h"

#include <string.h>

#include <AmbaShell.h>

#include "ins_pal_error_code.h"
#include "ins_pal_system.h"
#include "ins_comm_log.h"
#include "ins_pal_fs.h"
#include <unittest/mmc/ins_ut_mmc.h>
#include <unittest/ambalink/ins_ut_ambalink.h>
#include <unittest/alg/ut_alg.h>
#include "ins_ut_media.h"
#include <unittest/config/ins_ut_config.h>
#include <unittest/dcf/ins_ut_dcf.h>
#include <unittest/command/ins_ut_cmd.h>
#include <unittest/device/ins_ut_device.h>
#include <unittest/fw_update/ins_ut_fwupdate.h>


/* ***** Shell Cmd Table ***** */
static void InsUT_Unittest_AIPCmd(uint32_t argc, char * const *argv, AMBA_SHELL_PRINT_f PrintFunc);

#define INSUT_SHELLCMD_CNT      (1)
AMBA_SHELL_COMMAND_s g_ut_shell_cmd[INSUT_SHELLCMD_CNT] =
{
    {"aip", (AMBA_SHELL_PROC_f)InsUT_Unittest_AIPCmd,   NULL},
};

/* ***** Unittest Cmd Table ***** */
static InsUT_Unittest_CmdInfo_t g_ut_cmd_aip[] =
{
    {NULL,  INSUT_CMDCNT_MMC,       g_ut_cmd_mmc,       "mmc",              "Mmc"},
    {NULL,  INSUT_CMDCNT_MEDIA,     g_ut_cmd_media,     "media",            "Media"},
    {NULL,  INSUT_CMDCNT_ALG,       g_ut_cmd_alg,       "alg",              "Alg"},
    {NULL,  INSUT_CMDCNT_CONFIG,    g_ut_cmd_config,    "config",           "Config"},
    {NULL,  INSUT_CMDCNT_CMD,       g_ut_cmd_cmd,       "command",          "Command"},
    {NULL,  INSUT_CMDCNT_DEVICE,    g_ut_cmd_device,    "device",          	"Device"},
    {NULL,  INSUT_CMDCNT_AMBALINK,  g_ut_cmd_ambalink,  "ambalink",         "Ambalink"},
    {NULL,  INSUT_CMDCNT_DCF,       g_ut_cmd_dcf,       "dcf",              "Dcf"},
    {NULL,  INSUT_CMDCNT_FW_UPDATE, g_ut_cmd_fwupdate,  "fw_update",        "FwUpdate"},
};
static const unsigned int INSUT_CMDCNT_AIP = sizeof(g_ut_cmd_aip) / sizeof(InsUT_Unittest_CmdInfo_t);


int32_t InsUT_Unittest_Init(void)
{
    uint8_t i = 0;

    INSLOG_I("[Unittest] Unittest Init");

    for(i=0; i<INSUT_SHELLCMD_CNT; i++)
    {
        if(0 == AmbaShell_CommandRegister(&g_ut_shell_cmd[i]))
        {
            INSLOG_I("[Unittest] Add shell cmd : %s", g_ut_shell_cmd[i].pName);
        }
        else
        {
            INSLOG_C("[Unittest] Add shell cmd : %s fail", g_ut_shell_cmd[i].pName);
        }
    }

    return INSERR_OK;
}

static int32_t InsUT_Unittest_ShowUsage(InsUT_Unittest_CmdInfo_t *cmd_info, uint8_t cmd_cnt)
{
    uint8_t i = 0;

    if(cmd_info == NULL)
    {
        return EINVAL;
    }

    INSLOG_I("Insta360 AIP Command List:");
    for(i=0; i<cmd_cnt; i++)
    {
        INSLOG_I("  %s - %s", cmd_info[i].cmd, cmd_info[i].usage);
    }
    INSLOG_FLUSH();

    return INSERR_OK;
}

static int32_t InsUT_Unittest_RunCmd(InsUT_Unittest_CmdInfo_t *cmd_info, uint8_t cmd_cnt, int32_t argc, char **argv)
{
    uint8_t i = 0;
    int32_t rval = INSERR_OK;

    if(argc > 0 && argv != NULL)
    {
        for(i=0; i<cmd_cnt; i++)
        {
            if(strcmp(argv[0], cmd_info[i].cmd) == 0)
            {
                if(cmd_info[i].exec_func != NULL)
                {
                    rval = cmd_info[i].exec_func(argc-1, &argv[1]);
                    if(rval == INSUT_UNITTEST_USAGE)
                    {
                        InsUT_Unittest_ShowUsage(cmd_info, cmd_cnt);
                    }
                    else if(rval != INSERR_OK)
                    {
                        INSLOG_E("Rum cmd fail [ %s ] (0x%x)", argv[0], rval);
                    }
                    InsComm_Log_Flush();
                    return rval;
                }
                else if(cmd_info[i].exec_func == NULL && cmd_info[i].next_cmd_info != NULL)
                {
                    return InsUT_Unittest_RunCmd(cmd_info[i].next_cmd_info, cmd_info[i].next_cmd_cnt, argc-1, &argv[1]);
                }
            }
        }
    }

    InsUT_Unittest_ShowUsage(cmd_info, cmd_cnt);
    return INSUT_UNITTEST_USAGE;
}

int32_t InsUT_Unittest_RunCmdString(char *ut_cmd)
{
    if(ut_cmd == NULL)
    {
        return EINVAL;
    }

    INSLOG_I("[Unittest] Run Cmd String : %s", ut_cmd);
    return AmbaShell_ExecCommand(ut_cmd);
}

static int32_t InsUT_Unittest_ExecScriptFile(const char *p_file_name)
{
    int32_t rval = INSERR_OK;
    char temp_cmd_buf[AMBA_SHELL_MAX_CMD_LINE_SIZE];
    InsPal_FS_File_t *p_file = NULL;
    char one_char;
    uint32_t read_size;
    uint32_t idx = 0U;
    uint32_t end_of_file = 0U;

    rval = InsPal_FS_Open(p_file_name, "r", &p_file);
    if(rval != INSERR_OK)
    {
        return rval;
    }

    memset(temp_cmd_buf, 0, AMBA_SHELL_MAX_CMD_LINE_SIZE);
    while(INSERR_OK == rval)
    {
        uint32_t shell_exec = 0U;

        read_size = InsPal_FS_Read(&one_char, 1U, 1U, p_file);
        if(read_size > 0U)
        {
            switch(one_char)
            {
                case '\0':
                case '\r':
                case '\n':
                    temp_cmd_buf[idx] = '\0';
                    idx = idx + 1U;
                    shell_exec = 1U;
                    break;
                default:
                    temp_cmd_buf[idx] = one_char;
                    idx = idx + 1U;
                    break;
            }
        }
        else
        {
            rval = ERRCOM_FILE_READFAIL;
            INSLOG_E("[Unittest] ExecScriptFile read fail");
        }

        end_of_file = InsPal_FS_FileEof(p_file);
        if(1U == end_of_file)
        {
            temp_cmd_buf[idx] = '\0';
            idx = idx + 1U;
            shell_exec = 1U;
        }

        if(shell_exec == 1U)
        {
            INSLOG_I("[Unittest] Run File Cmd String : %s", temp_cmd_buf);
            AmbaShell_ExecCommand(temp_cmd_buf);
            memset(temp_cmd_buf, 0, AMBA_SHELL_MAX_CMD_LINE_SIZE);
            idx = 0U;
        }

        if(idx >= AMBA_SHELL_MAX_CMD_LINE_SIZE)
        {
            rval = ERRCOM_BUF_FULL;
            INSLOG_E("[Unittest] Command length over");
        }
        if(1U == end_of_file)
        {
            break;
        }
    }

    InsPal_FS_Close(p_file);
    return rval;
}

int32_t InsUT_Unittest_RunCmdFile(uint8_t file_cnt, char *file_list[])
{
    uint8_t i = 0;

    if(file_cnt <= 0 || file_list == NULL)
    {
        return EINVAL;
    }

    for(i=0; i<file_cnt; i++)
    {
        INSLOG_I("[Unittest] Run Cmd File : %s", file_list[i]);
        InsUT_Unittest_ExecScriptFile(file_list[i]);
    }
    return INSERR_OK;
}

static void InsUT_Unittest_AIPCmd(uint32_t argc, char * const *argv, AMBA_SHELL_PRINT_f PrintFunc)
{
    INSPAL_UNUSED(&PrintFunc);
    if(argc >= 2 && argv != NULL)
    {
        InsUT_Unittest_RunCmd(g_ut_cmd_aip, INSUT_CMDCNT_AIP, argc-1, (char **)&argv[1]);
        return;
    }
    InsUT_Unittest_ShowUsage(g_ut_cmd_aip, INSUT_CMDCNT_AIP);
    return;
}

