#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <poll.h>

#include "cm_common.h"

extern const char *version_name[];

int svr_restart(const struct svr_restart_ops * res_ops)
{
	int ret;
	char inits[256];
	const char * initp;

	if (res_ops == NULL)
		return -1;

	inits[0] = '\0';
	inits[sizeof(inits) - 0x1] = '\0';
	initp = res_ops->init_path;
	if (initp == NULL) {
		/* silently drop the restart operaton */
		return 0;
	}

	if (access(initp, X_OK) == -1) {
		const char * name;
		name = strrchr(initp, '/');
		if (name) name++;
		if (name == NULL || name[0] == '\0')
			return 0;

		/* check whether the restart script exits */
		snprintf(inits, sizeof(inits) - 0x1, "/lib/dyiot/init.d/%s", name);
		if (access(inits, X_OK) == -1)
			return 0;

		snprintf(inits, sizeof(inits) - 0x1, "/lib/dyiot/init.d/%s %s",
			name, res_ops->is_reload ? "reload" : "restart");
	} else {
		snprintf(inits, sizeof(inits) - 0x1, "%s %s", initp,
			res_ops->is_reload ? "reload" : "restart");
	}

	if (res_ops->pre_delay > 0)
		lnxall_msleep(res_ops->pre_delay * 1000, 1);
	ret = system(inits);
	if (res_ops->post_delay > 0)
		lnxall_msleep(res_ops->post_delay * 1000, 1);
	return ret == 0 ? 1 : -1;
}

static int simple_restart(const char * initd,
	int delay0, int delay1, int reload)
{
	struct svr_restart_ops svrops;
	svrops.pre_delay = delay0;
	svrops.post_delay = delay1;
	svrops.init_path = initd;
	svrops.is_reload = reload;
	return svr_restart(&svrops);
}

static int cm_config_load_poll(cm_var_t *var)
{
    TIMER_CONFIRM(var->config_load_timer);

    pthread_mutex_lock(&var->restart_flag_lock);
    bits restart_flag = bit_clone(var->restart_flag);
    bit_clean(var->restart_flag);
    pthread_mutex_unlock(&var->restart_flag_lock);

    if (restart_flag)
    {
        if (bit_get(restart_flag, BIT_PP_RESTART))
        {
            simple_restart(PP_RESTART_CMD,                0, 5, 1);
			simple_restart(IP_CAMERA_RELOAD_CMD,          0, 0, 1);
            simple_restart(IP_CAMERA_RESTART_CMD,         0, 0, 1);
			simple_restart(IP_SOUNDBOX_RESTART_CMD,       0, 0, 1);
			simple_restart(IP_SOUNDBOX_RESTART_CMD1,      0, 0, 1);
			simple_restart(AZURE_RESTART_CMD,             0, 0, 1);
			simple_restart(IP_ALARM_RESTART_CMD,          0, 0, 1);
			simple_restart(IP_ALARM_CLIENT_RESTART_CMD,   0, 0, 1);
			simple_restart(AZURE_ROCHE_RESTART_CMD,       0, 0, 1);
			simple_restart(SUPEC5100_RELOAD_CMD,          0, 0, 1);
			simple_restart(CLOUD_NANDU_RESTART_CMD,       0, 0, 1);
			simple_restart(OPC_UA_RESTART_CMD,            0, 0, 1);
			simple_restart(OPC_DA_RESTART_CMD,            0, 0, 1);
			simple_restart(OPCUA_SERVER_RESTART_CMD,      0, 0, 1);
			simple_restart(MHMP_TCP_CLIENT_RESTART_CMD,   0, 0, 1);
			simple_restart(MQTT_FORWARD_RESTART_CMD,      0, 0, 1);
			simple_restart(IEC104_SERVER_RESTART_CMD,     0, 0, 1);
			simple_restart(DOCKER_CONTROL_RESTART_CMD,    0, 0, 0);
			simple_restart(YOUCAN_RESTART_CMD,            0, 0, 0);
        }
        if (bit_get(restart_flag, BIT_RS485_RESTART))
        {
            simple_restart(RS485_RESTART_CMD,             0, 0, 1);
			simple_restart(MODBUS_TCP_RESTART_CMD,        0, 0, 1);
        }
        if (bit_get(restart_flag, BIT_RS485_SLAVE_RESTART))
        {
			simple_restart(RS485_SLAVE_RESTART_CMD,       0, 0, 1);
        }
        if (bit_get(restart_flag, BIT_ENTRANCE_GUARD_RESTART))
        {
            simple_restart(ENTRANCE_GUARD_RESTART_CMD,    0, 0, 1);
        }
        if (bit_get(restart_flag, BIT_COMMON_SOCKET_RESTART))
        {
            simple_restart(COMMON_SOCKET_RESTART_CMD,     0, 0, 1);
        }
        if (bit_get(restart_flag, BIT_HUAYUN_RESTART))
        {
			simple_restart(HUAYUN_RESTART_CMD,            0, 0, 1);
        }
        if (bit_get(restart_flag, BIT_LINKKIT_GATEWAY_RESTART))
        {
            simple_restart(LINKKIT_GATEWAY_RESTART_CMD,   0, 0, 1);
			simple_restart(ALINK_RESTART_CMD,             0, 0, 1);
        }
        if (bit_get(restart_flag, BIT_VINT_RESTART))
        {
            simple_restart(VINT_RESTART_CMD,              0, 0, 1);
        }
        if (bit_get(restart_flag, BIT_DR_RESTART))
        {
            simple_restart(DATA_RPT_RESTART_CMD,          0, 0, 1);
        }
        if (bit_get(restart_flag, BIT_RULE_RESTART))
        {
            simple_restart(RULE_ENG_RESTART_CMD,          0, 0, 1);
            simple_restart(WHSNBG_RESTART_CMD,            0, 0, 0);
        }
        if (bit_get(restart_flag, BIT_LORAWAN_RESTART) || bit_get(restart_flag, BIT_LORA_RESTART))
        {
            simple_restart(LORA_RESTART_CMD,              0, 1, 1);
            simple_restart(LORAWAN_RESTART_CMD,           0, 0, 1);
        }
        if (bit_get(restart_flag, BIT_VDEV_RESTART))
        {
            simple_restart(VDEV_RESTART_CMD,              0, 0, 1);
        }
        if (bit_get(restart_flag, BIT_CAN_RESTART))
        {
            simple_restart(CAN2MODBUS_RESTART_CMD,        0, 0, 1);
            simple_restart(XIENENG_CAR_BMS_RESTART_CMD,   0, 0, 1);
            simple_restart(CAN_MQTT_PROXY_RESTART_CMD,    0, 0, 1);
        }
        if (bit_get(restart_flag, BIT_UPGRADE_RESTART))
        {
            simple_restart(UPGRADE_NODE_RESTART_CMD,      0, 0, 1);
        }
        if (bit_get(restart_flag, BIT_NETWORK_RESTART))
        {
            // 网络重启flag，延迟网络重启的时间，防止下配置过程中出现网络重启导致配置下载失败
#if 1
            system("lua /app/network_restart.lua </dev/null >/dev/null 2>/dev/null &");
#else
            system(NETWORK_RESTART_CMD);
#endif
        }
        if (bit_get(restart_flag, BIT_IOT_CLD_RESTART))
        {
            simple_restart(IOT_CLOUD_RESTART_CMD,         0, 0, 1);
			simple_restart(IEC104_CLOUD_RESTART_CMD,      0, 0, 1);
			simple_restart(DASLINK_CLOUD_RESTART_CMD,     0, 0, 1);
        }
        if (bit_get(restart_flag, BIT_CLOUD_MQTT_RESTART))
        {
            simple_restart(CLOUD_MQTT_RESTART_CMD,        0, 0, 1);
        }
        if (bit_get(restart_flag, BIT_SHANGHAI_S5_RESTART))
        {
            simple_restart(SHANGHAI_S5_RESTART_CMD,       0, 0, 1);
        }
        if (bit_get(restart_flag, BIT_LANZHUO_RESTART))
        {
            simple_restart(LANZHUO_RESTART_CMD,           0, 0, 1);
        }
        if (bit_get(restart_flag, BIT_S7_PLC_RESTART))
        {
            simple_restart(S7_PLC_RESTART_CMD,            0, 0, 1);
        }
		if (bit_get(restart_flag, BIT_IPDEV_MANAGER_RESTART))
        {
            simple_restart(IPDEV_MANAGER_RESTART_CMD,     0, 0, 1);
        }
        if (bit_get(restart_flag, BIT_BLE_RESTART))
        {
            simple_restart("/etc/init.d/mpcie_detect",    0, 0, 0);
        }
        if (bit_get(restart_flag, BIT_SCADA_IEC104_RESTART))
        {
            simple_restart("/etc/init.d/scada_iec104",    0, 0, 1);
        }
        if (bit_get(restart_flag, BIT_NETSNIFFER_RESTART))
        {
            simple_restart("/etc/init.d/net_sniffer",     0, 0, 0);
        }
    }
    bit_destroy(restart_flag);

    reply_msg_t *node = NULL;
    reply_msg_t *tmp = NULL;

    list_for_each_entry_safe(node, tmp, &var->reply_list, list)
    {
        gw_common_result(var->session, node->mi, node->ret, node->topic);
        list_del(&node->list);
        free(node);
    }
    return 0;
}

static void cm_loop(cm_var_t *var)
{
    int ret = -1;
    struct pollfd pfd;

    while (1)
    {
        pfd.fd = var->config_load_timer;
        pfd.events = POLLIN;
        pfd.revents = 0;

        ret = poll(&pfd, 0x1, 10 * 1000);
        if (ret < 0)
        {
            int error = errno;
            printf("errno %d\n", error);
            if (error == EINTR)
            {
                continue;
            }
            else
            {
                break;
            }
        }
        else if (ret > 0)
        {
            if (var->config_load_timer > 0 && pfd.revents)
            {
                cm_config_load_poll(var);
            }
        }
    }
}

static void cm_subscribe_all(cm_var_t *var)
{
    ipc_session_t *ipc_session = var->session;
    char topic[TOPIC_MAX_LEN] = {0};

    sprintf(topic, "M/+/%s/device/%s/service/#", TOPIC_GATEWAY_CONFIG, var->sn_str);
    ipc_session_subscribe(ipc_session, topic);
    
    sprintf(topic, "M/%s", TOPIC_GET_GWINFO);
    ipc_session_subscribe(ipc_session, topic);
}

static int cm_mqtt_handle_recv_msg(void *obj, ipc_msg_t *mqtt_msg)
{
    cm_var_t *var = (cm_var_t *)obj;
    dy_syslog(LOG_DEBUG, "Config Manager MQTT client received MQTT topic:%s payload length:%d",
              mqtt_msg->topic, mqtt_msg->payloadLen);
    cm_handle_mqtt_data(var, mqtt_msg);
    return 0;
}

// 建立与内部broker之间的MQTT连接
static int cm_mqtt_client_init(cm_var_t *var)
{
    char clientId[128];

    memset(clientId, 0, sizeof(clientId));
    snprintf(clientId, sizeof(clientId), "INT_cm_%s", var->sn_str);
    var->session = ipc_session_new(clientId, (void*)var, IPC_DEFAULT);
    if (var->session == NULL) return -1;

    ipc_session_set_callbacks(var->session, cm_mqtt_handle_recv_msg, NULL);
    cm_subscribe_all(var);
    ipc_session_start(var->session);
    return 0;
}

static int cm_init(cm_var_t *var)
{
    check_make_dir(NODES_CACHE);
    check_make_dir(NODES_CFG);
    get_board_sn(var->sn_str);
    get_process_name(var->proc_name);
    var->restart_flag = bit_new(128);

    pthread_mutex_init(&var->restart_flag_lock, NULL);

    INIT_LIST_HEAD(&var->reply_list);

    cm_mqtt_client_init(var);

    var->config_load_timer = my_timer_create();
    if (var->config_load_timer > 0)
    {
        my_timer_set(var->config_load_timer, 1, 5000);
    }
    dy_syslog(LOG_INFO, "init done, board SN:%s", var->sn_str);

    return 0;
}

int main(int argc, char *argv[])
{
    cm_var_t var = {0};

    openlog("config-manager", LOG_PID, LOG_DAEMON);
    memset(&var, 0, sizeof(var));

    cm_init(&var);
    cm_loop(&var);

    return 0;
}
