/******************************************************************************
 * file    include/cmd.h 
 * author  YuLiang
 * version 1.0.0
 * date    09-Oct-2021
 * brief   This file provides all the headers of the command functions.
 
 ******************************************************************************
 * Attention
 *
 * <h2><center>&copy; COPYRIGHT(c) 2021 LandPower</center></h2>
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *   3. Neither the name of LandPower nor the names of its contributors may be used to 
 *      endorse or promote products derived from this software without specific
 *      prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************/

#ifndef _CMD_H_
#define _CMD_H_

/* Includes ------------------------------------------------------------------*/
#include "array.h"
#include "vty.h"

/* Define --------------------------------------------------------------------*/
/* 命令行最大参数个数. */
#define CMD_ARGC_MAX   16

/* rang检查数字最大位数. */
#define DECIMAL_STRLEN_MAX 10
#define INIT_MATCHARR_SIZE 10
#define COMPLETE_BUF_SIZE 256

#define CA_MQTT_CLINET_ID_LEN 64
#define CA_MQTT_USERNAME_LEN 64
#define CA_MQTT_PASSWD_LEN 64
#define CA_MQTT_DEV_ID_LEN 64

#define IPV6_ADDR_STR       "0123456789abcdefABCDEF:.%"
#define IPV6_PREFIX_STR     "0123456789abcdefABCDEF:.%/"
#define STATE_START         1
#define STATE_COLON         2
#define STATE_DOUBLE        3
#define STATE_ADDR          4
#define STATE_DOT           5
#define STATE_SLASH         6
#define STATE_MASK          7

/* 命令行返回值. */
#define CMD_SUCCESS              0
#define CMD_WARNING              1
#define CMD_ERR_NO_MATCH         2
#define CMD_ERR_AMBIGUOUS        3
#define CMD_ERR_INCOMPLETE       4
#define CMD_ERR_EXEED_ARGC_MAX   5
#define CMD_ERR_NOTHING_TODO     6
#define CMD_COMPLETE_FULL_MATCH  7
#define CMD_COMPLETE_MATCH       8
#define CMD_COMPLETE_LIST_MATCH  9
#define CMD_SUCCESS_DAEMON      10

#define CONF_BACKUP_EXT ".sav"

#define CL_COPYRIGHT "Copyright 2023-2024 LandPower."

/* Common descriptions. */
#define SHOW_STR "Show running system information\n"
#define IP_STR "IP information\n"
#define IPV6_STR "IPv6 information\n"
#define NO_STR "Negate a command or set its defaults\n"
#define REDIST_STR "Redistribute information from another routing protocol\n"
#define CLEAR_STR "Reset functions\n"
#define RIP_STR "RIP information\n"
#define BGP_STR "BGP information\n"
#define OSPF_STR "OSPF information\n"
#define NEIGHBOR_STR "Specify neighbor router\n"
#define DEBUG_STR "Debugging functions (see also 'undebug')\n"
#define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n"
#define ROUTER_STR "Enable a routing process\n"
#define AS_STR "AS number\n"
#define MBGP_STR "MBGP information\n"
#define MATCH_STR "Match values from routing table\n"
#define SET_STR "Set values in destination routing protocol\n"
#define OUT_STR "Filter outgoing routing updates\n"
#define IN_STR  "Filter incoming routing updates\n"
#define V4NOTATION_STR "specify by IPv4 address notation(e.g. 0.0.0.0)\n"
#define OSPF6_NUMBER_STR "Specify by number\n"
#define INTERFACE_STR "Interface infomation\n"
#define IFNAME_STR "Interface name(e.g. ep0)\n"
#define IP6_STR "IPv6 Information\n"
#define OSPF6_STR "Open Shortest Path First (OSPF) for IPv6\n"
#define OSPF6_ROUTER_STR "Enable a routing process\n"
#define OSPF6_INSTANCE_STR "<1-65535> Instance ID\n"
#define SECONDS_STR "<1-65535> Seconds\n"
#define ROUTE_STR "Routing Table\n"
#define PREFIX_LIST_STR "Build a prefix list\n"

/* Some macroes */
#define CMD_OPTION(S)       ('[' == (S[0]))
#define CMD_VARIABLE(S)     (((S[0]) >= 'A' && (S[0]) <= 'Z') || ('<' == (S[0])))
#define CMD_VARARG(S)       ('.' ==(S[0]))
#define CMD_RANGE(S)        ('<' == (S[0]))
#define CMD_IPV4(S)         (0 == strcmp((S), "A.B.C.D"))
#define CMD_IPV4_PREFIX(S)  (0 == strcmp((S), "A.B.C.D/M"))
#define CMD_IPV6(S)         (0 == strcmp((S), "X:X::X:X"))
#define CMD_IPV6_PREFIX(S)  (0 == strcmp((S), "X:X::X:X/M"))

#define DEV_INFO_DEFAULT_IP "192.168.1.110"
#define DEV_INFO_DEFAULT_MASK "255.255.255.0"
#define DEV_INFO_DEFAULT_GW "192.168.1.1"

#define DEVICE_RUN_PATH     "/home/Cable"
#define SAVE_STA_CFG_BAK_FILE       1
#define SAVE_DEV_CFG_BAK_FILE       2

/* Exported types ------------------------------------------------------------*/
enum
{
    CMD_ATTR_DEPRECATED = 1,
    CMD_ATTR_HIDDEN,
};

/* 匹配结果类型. */
typedef enum
{
    no_match,
    extend_match,
    ipv4_prefix_match,
    ipv4_match,
    ipv6_prefix_match,
    ipv6_match,
    range_match,
    vararg_match,
    partly_match,
    exact_match 
}  MATCH_TYPE_E;

/* 用于定义命令的宏. */
#define CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \
    cmd_element_t cmdname = \
    { \
        .string = cmdstr, \
        .func = funcname, \
        .doc = helpstr, \
        .attr = attrs, \
        .daemon = dnum, \
    };

#define CMD_FUNC_DECL(funcname) \
    static int funcname(cmd_element_t *, vty_t *, int, const char *[]);

#define CMD_FUNC_TEXT(funcname) \
    static int funcname \
        (cmd_element_t *self __attribute__ ((unused)), \
        vty_t *vty __attribute__ ((unused)), \
        int argc __attribute__ ((unused)), \
        const char *argv[] __attribute__ ((unused)))

/* CMD for vty command interafce. Little bit hacky ;-). */
#define CMD(funcname, cmdname, cmdstr, helpstr) \
    CMD_FUNC_DECL(funcname) \
    CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \
    CMD_FUNC_TEXT(funcname)

#define CMD_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \
    CMD_FUNC_DECL(funcname) \
    CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \
    CMD_FUNC_TEXT(funcname)

#define CMD_HIDDEN(funcname, cmdname, cmdstr, helpstr) \
    CMD_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN)

#define CMD_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \
    CMD_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED) \

/* ALIAS macro which define existing command's alias. */
#define ALIAS(funcname, cmdname, cmdstr, helpstr) \
    CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0)

#define ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \
    CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0)

#define ALIAS_HIDDEN(funcname, cmdname, cmdstr, helpstr) \
    CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, 0)

#define ALIAS_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \
    CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED, 0)

/* 命令行模式节点宏 */
typedef enum
{
    USERNAME_NODE,      /* Username node. Default mode of vty interface. */
    PASSWORD_NODE,      /* Password node. */
    ENABLE_NODE,        /* Enable node. */
    CONFIG_NODE,        /* Config node. Default mode of config file. */
    COLL_RS485_NODE,    /* RS485 node. */
    COMMON_NODE,        /* Common node. Cmd is common to other node. */
    NODES_COUNT
} NODE_TYPE_E;

/* config节点配置优先级 */
typedef enum
{
    CONFIG_PRI_CA_COLL,
    CONFIG_PRI_CA_MQTT,
    CONFIG_PRI_COUNT
} CONFIG_PRI_E;

/* MQTT 基本配置结构体 */
typedef struct
{
    char server_ip[INET_ADDRSTRLEN];            // 服务器 ip
    uint16_t server_port;                       // 服务器 端口
    uint16_t alive_time;                        // 保活时间
    char dev_id[CA_MQTT_DEV_ID_LEN];            // 设备 id
    char client_id[CA_MQTT_CLINET_ID_LEN];      // 客户端 id
    char username[CA_MQTT_USERNAME_LEN];        // 用户名
    char passwd[CA_MQTT_PASSWD_LEN];            // 密码
} ca_mqtt_dev_info_t;

/* Host configuration variable */
typedef struct
{
    uint32_t id_minor;              /* 设备次设备号 */
    uint16_t id_major;              /* 设备主设备号 */
    uint32_t dev_id;                /* 设备 ID */
    uint8_t mac[MAC_ADDR_LEN];      /* System mac. */
    char host_ip[INET_ADDRSTRLEN];  /* host ip string. */
    char host_mask[INET_ADDRSTRLEN];/* host mask string. */
    char host_gw[INET_ADDRSTRLEN];  /* host gw string. */
    uint32_t factory_date;          /* 出厂日期. */
    uint32_t deployment_date;       /* 部署日期. */
    char dev_type[FILE_NAME_LEN];   /* 设备型号字符串. */
    ca_mqtt_dev_info_t mqtt;        /* MQTT 信息 */
} device_info_t;

/* Host configuration variable */
typedef struct
{
    char name[FILE_NAME_LEN];       /* Host name of this router. */
    int lines;                      /* System wide terminal lines. */
    char *version;                  /* 版本号. */
    char *compile;                  /* 编译时间. */
    char configfile[FILE_NAME_LEN]; /* config file name of this host */
    char bannerfile[FILE_NAME_LEN]; /* Banner configuration file name. */
} host_t;

/* Structure of command element. */
typedef struct _cmd_element 
{
    const char *string;         /* Command specification by string */
    const char *doc;            /* Documentation of this command */
    array_t *strs;              /* Pointing out each description array */
    unsigned int str_size;      /* Command index count */
    int (*func)(struct _cmd_element*, vty_t*, int, const char *[]);
    int daemon;                 /* Daemon to which this command belong */
    char *config;               /* Configuration string */
    array_t *sub_cfg;           /* Sub configuration string */
    unsigned char attr;         /* Command attributes */
} cmd_element_t;

/* Command description structure. */
typedef struct
{
    char *cmd;                    /* Command string. */
    char *str;                    /* Command's description. */
} desc_t;

/* 用于命令行模式节点注册配置保存函数 */
typedef int cmd_save_config_f(vty_t*);

/* 命令行模式节点结构体 */
typedef struct
{
    uint32_t node;              /* Node index. */
    uint32_t up_node;           /* Upper level node index. */
    uint8_t param_num;          /* Prompt param num. */
    char *prompt;               /* Prompt character at vty interface. */
    cmd_save_config_f *func;    /* Node's configuration write function */
    array_t *cmds;              /* Array of this node's command list. */
    array_t *configs;           /* 配置函数数组. */
} cmd_node_t;

/* Exported macro ------------------------------------------------------------*/

/* Extern global variables ---------------------------------------------------*/
extern host_t host;
extern device_info_t device_info;
extern array_t *cmd_nodes;
extern int8_t is_system_init;
extern int8_t is_system_reboot;

/* Extern functions ----------------------------------------------------------*/
static inline cmd_node_t *cmd_node_get(NODE_TYPE_E ntype)
{    
    return (cmd_node_t *)array_lookup(cmd_nodes, ntype);
}

extern void cmd_init(void);
extern int32_t cmd_execute(vty_t *vty);
extern const char *cmd_prompt(NODE_TYPE_E ntype);
extern array_t *cmd_strs_create(const char *string);
extern void cmd_strs_free(array_t *a);
extern void cmd_sort_node(void);
extern void cmd_install_node(cmd_node_t *node, cmd_save_config_f *func);
extern array_t *cmd_describe_command (array_t *cmd_line, vty_t *vty, int32_t *status);
extern char **cmd_complete_command(array_t *vline, vty_t *vty, int32_t *status);
extern void cmd_install_element(NODE_TYPE_E ntype, cmd_element_t *cmd);
extern int32_t cmd_config_node_config_register(int32_t pri, cmd_save_config_f *func);
extern void vtysh_init(void);
extern char *vtysh_prompt (void);
extern int vtysh_rl_question(void);
extern int vtysh_rl_completion(void);
extern char *vtysh_completion_entry_function(const char *ignore, int invoking_key);
extern void vtysh_config_recovery(void);
extern void vtysh_device_save(void);
extern void vtysh_eth0_save(void);
extern int32_t vtysh_config_save(void);
extern int32_t vtysh_host_addr_set(char *addr, char *mask);
extern int32_t vtysh_gateway_set(char *gateway);
extern void vtysh_shell_init(void);
extern void vtycmd_init(void);
extern void vtycmd_cmd_init(void);
extern bool vtycmd_connect(void);
extern void vtycmd_print(const char *format, va_list va);
#endif
/************************ (C) COPYRIGHT LandPower ***** END OF FILE ****************/
