#include "browser/browser.h"
#include "smartbox/smartbox.h"
#include "dev_manager.h"
#include "music_player.h"
#include "music/music.h"
#include "file_operate/file_bs_deal.h"
#include "smartbox/event.h"

#define FILE_BROWSE_BUF_LEN    			250//要小于RCSP MTU, 不要随意改大
#define FILE_BROWSE_NAME_MAX_LIMIT  	128//限制最大文件夹名称大小

#define FILE_BROWSE_TASK_NAME			"file_bs"
#if defined(CONFIG_FAT_MAX_DEEPTH) && (CONFIG_FAT_MAX_DEEPTH > 0)
#define MAX_DEEPTH 						CONFIG_FAT_MAX_DEEPTH
#else
#define MAX_DEEPTH 						9/* 0~9 deepth of system */
#endif



enum {
    BS_FLODER = 0,
    BS_FILE,
};

enum {
    BS_UNICODE = 0,
    BS_ANSI,
};

static const char *dev_logo[] = {
    [BS_UDISK] = "udisk0",
    [BS_SD0] = "sd0",
    [BS_SD1] = "sd1",
    [BS_FLASH] = "virfat_flash",
    [BS_FLASH_2] = "fat_nor",
#ifdef TCFG_NANDFLASH_FAT_ROOT
    [BS_NAND_FLASH] = TCFG_NANDFLASH_FAT_ROOT,
#else
    [BS_NAND_FLASH] = "NULL",
#endif
};

#pragma pack(1)
struct __browser {
    u8 path_type;///
    u8 read_file_num;
    u16 start_num;
    u32 dev_handle;
    u16 path_len;
    u32 path_clust[MAX_DEEPTH];
};

#if (defined TCFG_NANDFLASH_DEV_ENABLE && TCFG_NANDFLASH_DEV_ENABLE)
struct JL_FILE_DATA {
    u8 type : 1;
    u8 format : 1;
    u8 device : 5;
    u8 reserve : 1;

    u32 clust;
    u16 file_num;
    u8 name_len;
    u8 file_data[0];
};
#else
struct JL_FILE_DATA {
    u8 type : 1;
    u8 format : 1;
    u8 device : 3;
    u8 reserve : 3;

    u32 clust;
    u16 file_num;
    u8 name_len;
    u8 file_data[0];
};
#endif
#pragma pack()



static const char dec_file_ext[][3] = {
#if (WATCH_FILE_TO_FLASH)
    {"ALL"},
    {'\0'},
#else // WATCH_FILE_TO_FLASH
#if (TCFG_DEC_MP3_ENABLE)
    {"MP1"},
    {"MP2"},
    {"MP3"},
#endif

#if (TCFG_DEC_WMA_ENABLE)
    {"WMA"},
#endif

#if (TCFG_DEC_WAV_ENABLE || TCFG_DEC_DTS_ENABLE)
    {"WAV"},
#endif

#if (TCFG_DEC_FLAC_ENABLE)
    {"FLA"},
#endif

#if (TCFG_DEC_APE_ENABLE)
    {"APE"},
#endif

#if (TCFG_DEC_DECRYPT_ENABLE)
    {"SMP"},
#endif

#if (TCFG_DEC_AMR_ENABLE)
    {"AMR"},
#endif

#if (TCFG_DEC_M4A_ENABLE)
    {"M4A"},
    {"AAC"},
#endif
#if (TCFG_DEC_M4A_ENABLE || TCFG_DEC_ALAC_ENABLE)
    {"MP4"},
#endif
    {"TMP"},
    {'\0'},
#endif // WATCH_FILE_TO_FLASH
};

static struct __browser *browser = NULL;

char *smartbox_browser_file_ext(void)
{
    return (char *)dec_file_ext;
}

u16 smartbox_browser_file_ext_size(void)
{
    return strlen((const char *)dec_file_ext);
}

char *smartbox_browser_dev_remap(u32 index)
{
    if (index >= BS_DEV_MAX) {
        return NULL;
    }
    return (char *)dev_logo[index];
}

u16 file_name_cut(u8 *name, u16 len, u16 len_limit)
{
    u8 ex_type[8];
    u8 three_point_hex[] = {0x2E, 0x00, 0x2E, 0x00, 0x2E, 0x00}; //... 显示unicode码
    if (len > len_limit) {
        memcpy(name + len_limit - sizeof(three_point_hex), three_point_hex, sizeof(three_point_hex));
        return len_limit;
    }
    return len;
}

static bool browser_get_dir_info(FILE_BS_DEAL *fil_bs, u8 *path_buf, u16 len, u8 type, void *ptr)
{
    s16 ret = 0;
    u16 i, j = 0;
    u32 deep_clust = 0;
    FS_DIR_INFO dir_info;
    //open root
    ret = file_bs_entern_dir(fil_bs, NULL);
    if (ret == 0) {
        goto end;
    }

    if (len == 4 && type == BS_FLODER) {
        /* printf("root deep\n"); */
        if (ptr) {
            *((u32 *)ptr) = ret;
        }
        goto end;
    } else if (len == 4 && type == BS_FILE) {
        /* printf("play file path\n"); */
        memcpy((u8 *)&deep_clust, path_buf, 4);
        deep_clust = app_ntohl(deep_clust);
        if (ptr) {
            *((u32 *)ptr) = deep_clust;
        }
        goto end;
    }
    //deep check
    u8 deep = len / 4;
    if (deep >  MAX_DEEPTH) {
        printf("deep err : %d\n", deep);
        return false;
    }
    /* printf("get deep%d data\n", deep - 1); */
    for (i = 1; i < deep; i++) {
        memcpy((u8 *)&deep_clust, path_buf + 4 * i, 4);
        deep_clust = app_ntohl(deep_clust);
        /* printf("deep_clust:%x\n", deep_clust); */
        for (j = 1; j < ret + 1; j++) {
            /* file_browse_get_dir(obj, (void *)&dir_info, j, 1); */
            file_bs_get_dir_info(fil_bs, &dir_info, j, 1);
            if (dir_info.sclust == deep_clust) {
                break;
            }
        }
        if (i < deep - 1) {
            ret = file_bs_entern_dir(fil_bs, &dir_info);
            if (ret == 0) {
                goto end;
            }
        }
    }
    if (type == BS_FILE) {
        if (ptr) {
            *((u32 *)ptr) = dir_info.sclust;    //file return clust
        }
        goto end;
    } else {
        ret = file_bs_entern_dir(fil_bs, &dir_info);
        if (ret == 0) {
            goto end;
        }

        if (ptr) {
            *((u32 *)ptr) = ret;    //file return clust
        }
    }
end:
    return true;
}

static u32 browse_open_dir(FILE_BS_DEAL *fil_bs, u8 *path_buf, u16 len)
{
    u32 file_cnt = 0;
    browser_get_dir_info(fil_bs, path_buf, len, BS_FLODER, (void *)&file_cnt);
    return file_cnt;
}

static void file_printf_dir(FS_DIR_INFO *dir_inf, u8 cnt)
{
    u8 i;
    LONG_FILE_NAME *l_name_pt;

    for (i = 0; i < cnt; i++) {
        /* printf("file type %d nt:%d clust %x \n", dir_inf[i].dir_type, dir_inf[i].fn_type, dir_inf[i].sclust); */
        l_name_pt = &dir_inf[i].lfn_buf;
        if (dir_inf[i].fn_type == BS_FNAME_TYPE_SHORT) {
            file_comm_display_83name((void *)&l_name_pt->lfn[32], (void *)l_name_pt->lfn);
            strcpy(l_name_pt->lfn, &l_name_pt->lfn[32]);
            l_name_pt->lfn_cnt = strlen(l_name_pt->lfn);
            printf("%s\n", l_name_pt->lfn);
        } else {
            if (l_name_pt->lfn_cnt > 510) {
                l_name_pt->lfn_cnt = 510;
                puts("***get long name err!!!");
            }
            l_name_pt->lfn_cnt = file_comm_long_name_fix((void *)l_name_pt->lfn, l_name_pt->lfn_cnt);
            l_name_pt->lfn[l_name_pt->lfn_cnt] = 0;
            l_name_pt->lfn[l_name_pt->lfn_cnt + 1] = 0;

            /* printf("file name len : %d \n", l_name_pt->lfn_cnt); */
            /* put_buf((u8 *)l_name_pt->lfn, l_name_pt->lfn_cnt); */
        }
    }
}
static u16 add_one_iterm_to_sendbuf(u8 *dest, u16 max_buf_len, u16 offset, FS_DIR_INFO *p_dir_info, u16 file_cnt, u8 dev_type)
{
    struct JL_FILE_DATA file_data;
    memset((u8 *)&file_data, 0, sizeof(struct JL_FILE_DATA));


    file_data.type = p_dir_info->dir_type;

    if (p_dir_info->fn_type == BS_FNAME_TYPE_SHORT) {
        file_data.format = BS_ANSI;
    } else {
        file_data.format = BS_UNICODE;
    }

    ///限制文件名长度
    p_dir_info->lfn_buf.lfn_cnt = file_name_cut((u8 *)p_dir_info->lfn_buf.lfn, p_dir_info->lfn_buf.lfn_cnt, FILE_BROWSE_NAME_MAX_LIMIT);

    file_data.device = dev_type;
    file_data.clust = app_htonl(p_dir_info->sclust);
    file_data.file_num = app_htons(file_cnt);
    file_data.name_len = p_dir_info->lfn_buf.lfn_cnt;

    memcpy(dest + offset, (u8 *)&file_data, sizeof(struct JL_FILE_DATA));
    memcpy(dest + offset + sizeof(struct JL_FILE_DATA), (u8 *)p_dir_info->lfn_buf.lfn, p_dir_info->lfn_buf.lfn_cnt);

    /* printf("add send data:"); */
    /* put_buf(dest+offset,p_dir_info->lfn_buf.lfn_cnt + sizeof(struct JL_FILE_DATA)); */
    return (p_dir_info->lfn_buf.lfn_cnt + sizeof(struct JL_FILE_DATA));
}

static void smartbox_browser_task(void *p)
{
    u8 reason = 0;
    u32 play_file_clust = 0;
    FS_DIR_INFO dir_info;
    FILE_BS_DEAL fil_bs;
    u8 *path_data = NULL;

    memset((u8 *)&dir_info, 0, sizeof(FS_DIR_INFO));
    memset((u8 *)&fil_bs, 0, sizeof(FILE_BS_DEAL));

    fil_bs.dev = dev_manager_find_spec(smartbox_browser_dev_remap(browser->dev_handle), 0);
    if (fil_bs.dev == NULL) {
        reason = 1;
        printf("dev nofound!!!\n");
        goto _EXIT;
    }
    file_bs_open_handle(&fil_bs, (u8 *)smartbox_browser_file_ext());

    u32 dir_file_cnt = browse_open_dir(&fil_bs, (u8 *)browser->path_clust, browser->path_len);
    if (browser->start_num  + browser->read_file_num >= dir_file_cnt) {
        printf("file range err\n");
        reason = 1;
        browser->read_file_num =  dir_file_cnt - browser->start_num + 1;
        /* goto _EXIT; */
    }
    /* printf("start num:%d read file num:%d\n", browser->start_num, browser->read_file_num); */

    u16 offset = 0;
    u32 ret = 0;
    path_data = (u8 *)zalloc(FILE_BROWSE_BUF_LEN);
    if (path_data == NULL) {
        reason = 1;
        printf("no ram for path_data!! \n");
        goto _EXIT;
    }
    for (int i = browser->start_num ; i < (browser->start_num + browser->read_file_num); i++) {
        ret = file_bs_get_dir_info(&fil_bs, &dir_info, i, 1);
        if (!ret) {
            break;
        }

        file_printf_dir(&dir_info, 1);
        if (offset && ((offset + dir_info.lfn_buf.lfn_cnt + sizeof(struct JL_FILE_DATA)) > FILE_BROWSE_BUF_LEN)) {
            ///如果buf不够填充了， 先将数据发送了先，再重新填充
            ret = JL_DATA_send(JL_OPCODE_DATA, JL_OPCODE_FILE_BROWSE_REQUEST_START, path_data, offset, JL_NOT_NEED_RESPOND);
            if (ret) {
                printf("send data err: %d, %d\n", ret, offset);
                goto _EXIT;
            }
            //reset send buf
            offset = 0;
            memset(path_data, 0, FILE_BROWSE_BUF_LEN);
            offset += add_one_iterm_to_sendbuf(path_data, FILE_BROWSE_BUF_LEN, offset, &dir_info, i, browser->dev_handle);
        } else {
            offset += add_one_iterm_to_sendbuf(path_data, FILE_BROWSE_BUF_LEN, offset, &dir_info, i, browser->dev_handle);
        }
    }

    //send last package
    if (offset) {
        ret = JL_DATA_send(JL_OPCODE_DATA, JL_OPCODE_FILE_BROWSE_REQUEST_START, path_data, offset, JL_NOT_NEED_RESPOND);
        if (ret) {
            printf("send data err: %d\n", ret);
            goto _EXIT;
        }
    }

_EXIT:
    file_bs_close_handle(&fil_bs);
    if (path_data) {
        free(path_data);
    }
    smartbox_msg_post(
        USER_MSG_SMARTBOX_BS_END,
        4,
        (int)smartbox_handle_get(),
        (int)reason,
        (int)smartbox_browser_dev_remap(browser->dev_handle),
        (int)play_file_clust);

    while (1) {
        os_time_dly(10);
    }
}

void smartbox_browser_start(u8 *data, u16 len)
{
    ///检查数据是否有效
    printf("%s\n", __func__);
    if (len > sizeof(struct __browser)) {
        return ;
    }
    ///创建数据解析句柄
    browser = (struct __browser *)zalloc(sizeof(struct __browser));
    if (browser == NULL) {
        return ;
    }
    ///解析数据
    memcpy((u8 *)browser, data, sizeof(struct __browser));
    browser->start_num = app_ntohs(browser->start_num);
    browser->dev_handle = app_ntohl(browser->dev_handle);
    browser->path_len = app_ntohs(browser->path_len);
    ///检查设备范围
    if (browser->dev_handle >= BS_DEV_MAX) {
        printf("bs dev hdl err !!\n");
        free(browser);
        browser = NULL;
        return ;
    }
    ///检查是否是已经选定好文件播放
    if (browser->path_type) {
        u8 reason = 2;
        u32 play_file_clust = app_ntohl(browser->path_clust[0]);
        smartbox_msg_post(
            USER_MSG_SMARTBOX_BS_END,
            4,
            (int)smartbox_handle_get(),
            (int)reason,
            (int)smartbox_browser_dev_remap(browser->dev_handle),
            (int)play_file_clust);
        return ;
    }
    ///目录浏览线程创建
    if (task_create(smartbox_browser_task, (void *)NULL, FILE_BROWSE_TASK_NAME)) {
        free(browser);
        browser = NULL;
        printf("smartbox_browser_task creat fail\n");
    }
}

bool smartbox_browser_busy(void)
{
    if (browser) {
        return false;
    } else {
        return true;
    }
}


void smartbox_browser_stop(void)
{
    ///删除线程，释放资源
    task_kill(FILE_BROWSE_TASK_NAME);
    if (browser) {
#if 0
        struct __dev *dev;
        dev = dev_manager_find_spec(smartbox_browser_dev_remap(browser->dev_handle), 0);
        if (dev != NULL) {
            if ((strcmp(dev_manager_get_logo(dev), "sd0") == 0) || (strcmp(dev_manager_get_logo(dev), "sd1") == 0)) {
                struct imount *mount_hdl = dev_manager_get_mount_hdl(dev);
                dev_ioctl(mount_hdl->dev.fd, IOCTL_SET_ACTIVE_STATUS, 0);
            }
        }
#endif
        free(browser);
        browser = NULL;
    }
}



