#include "rgb_strip_mgr.h"

#include <rtthread.h>
#include <string.h>

#include "rgb_effect.h"

#include "rgb_strip_array.h"
#include "drv_rgb.h"

#include "drv_flash.h"
#include "mem_section.h"


static struct rgb_strip_mgr_t g_rgb_strip_mgr;

/**
 * @brief 初始化RGB灯条的灯效管理器
 * 
 * @return rt_err_t 初始化结果
 */ 
rt_err_t rgb_strip_mgr_init(void)
{
    struct rgb_strip_mgr_t *mgr = &g_rgb_strip_mgr;

    if (mgr->player.is_inited) {
        rt_kprintf("func: %s, player is inited.\r\n", __func__);
        return -RT_ERROR;
    }

    if (rgb_strip_mgr_get_effects() != RT_EOK) {
        rt_kprintf("func: %s, get effects failed.\r\n", __func__);
        return -RT_ERROR;
    }

    rgb_player_cfg_t cfg;
    memset(&cfg, 0, sizeof(cfg));
    cfg.effects = mgr->effects;
    cfg.effect_count = mgr->effect_count;
    cfg.fore_effect = &mgr->effects[0];
    cfg.back_effect = (mgr->effect_count > 1) ? &mgr->effects[1] : &mgr->effects[0];
    cfg.frame_cache = mgr->frame_cache;
    cfg.frame_cache_size = (uint16_t)RGB_STRIP_MGR_RGB_NUM;
    cfg.output_cb = rgb_strip_mgr_output_effect;
    cfg.output_lock = RT_NULL;
    cfg.sem_name = RGB_STRIP_MGR_SEM_NAME;
    cfg.mq_name = RGB_STRIP_MGR_MQ_NAME;
    cfg.mq_pool = mgr->mq_pool;
    cfg.mq_pool_size = RGB_STRIP_MGR_MQ_DEPTH * sizeof(rgb_player_msg_t);
    cfg.thread_name = RGB_STRIP_MGR_THREAD_NAME;
    cfg.stack = g_rgb_strip_mgr_thread_stack;
    cfg.stack_size = RGB_STRIP_MGR_THREAD_STACK_SIZE;
    cfg.priority = RGB_STRIP_MGR_THREAD_PRIORITY;
    cfg.timeslice = RGB_STRIP_MGR_THREAD_TIMESLICE;

    return rgb_player_open(&mgr->player, &cfg);
}

/**
 * @brief 关闭RGB灯条的灯效管理器
 * 
 * @return rt_err_t 关闭结果
 */ 
rt_err_t rgb_strip_mgr_deinit(void)
{
    struct rgb_strip_mgr_t *mgr = &g_rgb_strip_mgr;

    if (mgr->player.is_inited) {
        (void)rgb_player_close(&mgr->player);
    }

    memset(&mgr->player, 0, sizeof(mgr->player));
    memset(mgr->effects, 0, sizeof(mgr->effects));
    mgr->effect_count = 0;

    return RT_EOK;
}

/**
 * @brief 从RGB灯效列表中获取参数
 * 
 * @return rt_err_t 获取结果
 */ 
static rt_err_t rgb_strip_mgr_get_effects(void)
{
    struct rgb_strip_mgr_t *mgr = &g_rgb_strip_mgr;
    uint16_t count = 0;

    memset(mgr->effects, 0, sizeof(mgr->effects));

    for (uint16_t i = 0; i < rgb_strip_effects_count; i++) {
        const rgb_effect_t *eff = &rgb_strip_effects[i];
        if (eff->led_count != RGB_STRIP_MGR_RGB_NUM) {
            rt_kprintf("func: %s, led_count not match, %s, %d.\r\n", eff->name, eff->led_count);
            continue;
        }
        if (count >= (uint16_t)(sizeof(mgr->effects) / sizeof(mgr->effects[0]))) {
            rt_kprintf("func: %s, effects count overflow, %d.\r\n", __func__, count);
            return -RT_ERROR;
        }
        mgr->effects[count++] = *eff;
    }
    mgr->effect_count = count;

    return (count > 0) ? RT_EOK : -RT_ERROR;
}

/**
 * @brief 输出RGB灯条的灯效颜色
 * 
 * @param buff 颜色缓存
 * @param count 颜色数量
 * @return rt_err_t 输出结果    
 */
static rt_err_t rgb_strip_mgr_output_effect(uint32_t *buff, uint32_t count)
{
    return rgb_strip_set_color(buff, count);
}

/**
 * @brief 启动RGB灯条的灯效播放开始
 * 
 * @return rt_err_t 启动结果
 */
rt_err_t rgb_strip_mgr_play_start(void)
{
    struct rgb_strip_mgr_t *mgr = &g_rgb_strip_mgr;

    rgb_player_msg_t msg;
    memset(&msg, 0, sizeof(msg));
    msg.event = RGB_PLAYER_EVENT_PLAY;
    msg.effect_name = RT_NULL;
    msg.frame_index = 0;
    msg.is_loop = true;

    return rgb_player_send(&mgr->player, &msg);
}

/**
 * @brief 停止RGB灯条的灯效播放停止
 * 
 * @return rt_err_t 停止结果
 */
rt_err_t rgb_strip_mgr_play_stop(void)
{
    struct rgb_strip_mgr_t *mgr = &g_rgb_strip_mgr;

    rgb_player_msg_t msg;
    memset(&msg, 0, sizeof(msg));
    msg.event = RGB_PLAYER_EVENT_STOP;
    msg.effect_name = RT_NULL;
    msg.frame_index = 0;
    msg.is_loop = true;

    return rgb_player_send(&mgr->player, &msg);
}

/**
 * @brief 切换到RGB灯条的下一个灯效播放
 * 
 * @return rt_err_t 切换结果
 */ 
rt_err_t rgb_strip_mgr_play_next(void)
{
    struct rgb_strip_mgr_t *mgr = &g_rgb_strip_mgr;

    rgb_player_msg_t msg;
    memset(&msg, 0, sizeof(msg));
    msg.event = RGB_PLAYER_EVENT_NEXT_EFFECT;
    msg.effect_name = RT_NULL;
    msg.frame_index = 0;
    msg.is_loop = true;

    return rgb_player_send(&mgr->player, &msg);
}

/**
 * @brief 切换到RGB灯条的上一个灯效播放
 * 
 * @return rt_err_t 切换结果
 */ 
rt_err_t rgb_strip_mgr_play_prev(void)
{
    struct rgb_strip_mgr_t *mgr = &g_rgb_strip_mgr;

    rgb_player_msg_t msg;
    memset(&msg, 0, sizeof(msg));
    msg.event = RGB_PLAYER_EVENT_PREV_EFFECT;
    msg.effect_name = RT_NULL;
    msg.frame_index = 0;
    msg.is_loop = true;

    return rgb_player_send(&mgr->player, &msg);
}


