#include "at_sever.h"

osThreadId_t atParseThread = SR_NULL;

/**
 * @brief AT解析任务线程，接收待解析的字符，执行相应的命令。
 *
 * @return none.
 */
void SR_AtParseTask(void *arg)
{
    SR_AT_MNG_T *atServer = (SR_AT_MNG_T *)arg;

    int result = 0;
    char buf[128] = {0};
    uint32_t capacity = 0, msgSize = 0, count = 0, space = 0;

    while (1)
    {
        result = osMessageQueueGet((atServer->queue), &buf, 0, osWaitForever);

        // BSP_DEBUG_PRINTF("queue recv data = %s, recv data len = %d", buf, strlen(buf));
        SR_AtServerParse(atServer, buf, strlen(buf));
    }
}

/**
 * @brief 字符串拆分解析处理
 *
 * @return 检测归类的参数个数
 **/
int string_split(char *strp, uint32_t strsize, char ch, char *argv[], uint32_t argcM)
{
    int ch_index = 0;
    int argc_index = 0;
    uint8_t splitflag = 0;

    if ((!strsize) || (!argcM))
        return 0;

    argv[argc_index++] = &strp[ch_index];
    for (ch_index = 0; ch_index < strsize; ch_index++)
    {
        if (strp[ch_index] == ch)
        {
            strp[ch_index] = '\0';

            /* 处理连续出现ch情况 */
            if (1 == splitflag)
            {
                argv[argc_index++] = &strp[ch_index];
            }
            splitflag = 1;
        }
        else if (splitflag == 1)
        {
            splitflag = 0;
            argv[argc_index++] = &strp[ch_index];
            if (argc_index >= argcM)
                break;
        }
        else
        {
            splitflag = 0;
        }
    }

    return argc_index;
}

/**
 * @brief 解析AT指令。
 *
 * @param atServer AT服务端指针。
 * @param pData 指向包含AT指令数据的缓冲区指针。
 * @param datasize 数据缓冲区的大小 (Byte).
 *
 * @return 成功解析返回0，失败返回-1。
 */
int SR_AtServerParse(SR_AT_MNG_T *atServer, uint8_t *pData, uint16_t datasize)
{
    int ret = -1;
    char *ptr = NULL;
    int argc = ARGC_LIMIT;
    uint16_t offset = 0;
    int index = 0;
    char *argv[ARGC_LIMIT] = {(char *)0};

    /* 转为大写 */
    pData = strupr(pData);

    /* 匹配AT命令字 */
    if ((strstr((const char *)pData, "AT") == NULL) || (strstr((const char *)pData, "\r\n") == NULL))
        return 0;
    for (index = 0; index < atServer->tableNum; index++)
    {
        ptr = strstr((const char *)pData, atServer->table[index].cmd);
        // BSP_DEBUG_PRINTF("AT Parse data = %s\n", pData);
        if (ptr != NULL)
        {
            ptr += strlen(atServer->table[index].cmd);
            offset = ptr - (char *)pData;
            if (((ptr[0] == '?') && (ptr[1] == '\r') && (ptr[2] == '\n')) ||
                ((ptr[0] == '\r') && (ptr[1] == '\n')) ||
                (ptr[0] == '='))
                break;
        }
    }
    if (index >= atServer->tableNum)
        goto at_end;

    if ((ptr[0] == '?') && (ptr[1] == '\r') && (ptr[2] == '\n'))
    {
        /* 解析查询命令 */
        if (NULL != atServer->table[index].deal_func)
        {
            ret = atServer->table[index].deal_func(SR_AT_OPT_QUERY, argc, argv);
        }
    }
    else if ((ptr[0] == '\r') && (ptr[1] == '\n'))
    {
        /* 解析执行命令 */
        if (NULL != atServer->table[index].deal_func)
        {
            ret = atServer->table[index].deal_func(SR_AT_OPT_EXECUTE, argc, argv);
        }
    }
    else if (ptr[0] == '=')
    {
        /* 解析设置命令 */
        ptr += 1;
        argc = string_split((char *)ptr, datasize - offset, ',', argv, argc);
        if (NULL != atServer->table[index].deal_func)
        {
            ret = atServer->table[index].deal_func(SR_AT_OPT_SET, argc, argv);
        }
    }
    else
    {
        ret = -1;
    }

at_end:
    if (-1 == ret)
    {
        atServer->func("\r\nERROR\r\n", sizeof("\r\nERROR\r\n") - 1);
    }
    else
    {
        atServer->func("\r\nOK\r\n", sizeof("\r\nOK\r\n") - 1);
    }

    return ret;
}

/**
 * @brief 创建AT服务端。
 *
 * @return 成功返回AT服务端指针，失败返回空指针。
 */
SR_AT_MNG_T *SR_AtServerCreate(void)
{
    SR_AT_MNG_T *atServer = (SR_AT_MNG_T *)SR_OsMalloc(sizeof(SR_AT_MNG_T));
    memset(atServer, 0, sizeof(SR_AT_MNG_T));
    // BSP_DEBUG_PRINTF("at sever malloc size = %d", sizeof(SR_AT_MNG_T));

    /* 创建消息队列, 最多存放4条; 最多128字节. */
    atServer->queue = osMessageQueueNew(4, 128, SR_NULL);
    if (atServer->queue == SR_NULL)
    {
        SR_OsFree(atServer);
        return SR_NULL;
    }

    /* 创建线程1，并设置线程参数 */
    osThreadAttr_t threadAttr = {
        .name = "at_parse_thread",     // 线程名称
        .stack_size = 4 * 1024,        // 线程栈大小
        .priority = osPriorityNormal1, // 线程优先级
    };

    atParseThread = osThreadNew(SR_AtParseTask, atServer, &threadAttr);
    if (atParseThread == SR_NULL)
    {
        osMessageQueueDelete(atServer->queue);
        SR_OsFree(atServer);
        return SR_NULL;
    }

    return atServer;
}

/**
 * @brief AT命令发送接口
 *
 * @param atServer AT服务端指针。
 * @param pData 指向包含AT指令数据的缓冲区指针。
 * @param datasize 数据缓冲区的大小 (Byte).
 *
 * @return 成功返回0，失败返回-1。
 *
 * @note 内部通过消息队列将命令发给AT解析器，与物理接口无关
 */
int SR_AtSendToServer(SR_AT_MNG_T *atServer, uint8_t *pData, uint16_t datasize)
{
    int ret;

    if (atServer)
    {
        if (atServer->queue)
        {
            (void)datasize;
            ret = osMessageQueuePut((atServer->queue), pData, 0, 0);
            if (ret == SR_OK)
                return 0;
        }
    }
    return -1;
}

/**
 * @brief 注册AT指令表。
 *
 * @param atServer AT服务端指针。
 * @param table 指向SR_AT_CMD_T类型结构的指针，该结构定义了AT指令的表和对应的处理函数。
 * @param tableNum AT命令的个数。
 *
 * @return 成功注册返回0，失败返回-1。
 */
int SR_AtCmdTableRegister(SR_AT_MNG_T *atServer, SR_AT_CMD_T *table, int tableNum)
{
    if (atServer)
    {
        atServer->table = table;
        atServer->tableNum = tableNum;

        return 0;
    }
    return -1;
}

/**
 * @brief 注册AT响应函数
 *
 * @param atServer AT服务端指针。
 * @param func AT响应函数指针。
 *
 * @return 成功返回0，失败返回-1。
 */
int SR_AtServerSetResponseFun(SR_AT_MNG_T *atServer, AtServerResponse func)
{
    if (atServer)
    {
        atServer->func = func;

        return 0;
    }
    return -1;
}

/**
 * @brief 销毁AT服务端
 *
 * @param atServer AT服务端指针。
 *
 * @return 成功返回0，失败返回-1。
 */
int SR_AtServerDestroy(SR_AT_MNG_T *atServer)
{
    if (atServer)
    {
        osThreadTerminate(atParseThread);
        osMessageQueueDelete(atServer->queue);
        SR_OsFree(atServer);

        return 0;
    }
    return -1;
}
