#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include "main.h"
#include "signal.h"
#include <poll.h>
#include "lnxall_list.h"
#include "../common.h"

#include "collector-api.h"
#include "deviceLayer.h"
#include "../proto_forward.h"
#include "../adapter/pe_adapter.h"
#include "dy_utils/led.h"
#include "cloud_mqtt.h"
#include "../iec104_server/iec104_server.h"
#include "../mqtt_emms2/mqtt_emms2.h"
#include "../cmdclient.h"
#include "../log_module/log_module.h"
#include "../snapshoot/snapshoot.h"
#include "pub_fun.h"
#include "lc_system.h"
#include "lc_discovery.h"
#include "power_manage.h"
#include "../multilanguage.h"
static pcs_ctrl_var_t ctrl_var = {0};

pcs_ctrl_var_t *get_pcs_ctrl_var(void)
{
    return &ctrl_var;
}

static void sig_handler(int sig)
{
    ems_syslog(LOG_NOTICE, "=========================================================");
    ems_syslog(LOG_USER | LOG_NOTICE, "%s:%d receive signal:%d", __FILE__, __LINE__, sig);
    // proto_forward_schedule_stop();
    ems_syslog(LOG_NOTICE, "=========================================================");
    exit(0);
}

void sig_init(void)
{
    struct sigaction sig_action = {0};
    sig_action.sa_handler = sig_handler;
    sig_action.sa_flags = SA_RESTART;
    sigemptyset(&sig_action.sa_mask);
    sigaction(SIGINT, &sig_action, NULL);
    sigaction(SIGTERM, &sig_action, NULL);
    sigaction(SIGABRT, &sig_action, NULL);
    //
    memset(&sig_action, 0, sizeof(sig_action));
}
static int db_update_interval = -1;
static proto_forward_t *pr_init(void)
{
    proto_forward_param_t proto_par = {.enable_modbus_server = 0};
    proto_par.enable_open_ua = true;
    proto_par.ua_base_data.data_persistence = false;
    proto_par.ua_base_data.open_history = false;
    proto_par.ua_base_data.en_encryption = true;
    proto_par.ua_base_data.history_num = 10000;
    proto_par.ua_base_data.someExInfo[0] = strdup("TODO");
    proto_par.ua_base_data.someExInfo[3] = strdup("eth0");
    if (db_update_interval <= 0)
    {
        proto_par.db_update_interval = 60;
    }
    else
    {
        proto_par.db_update_interval = db_update_interval;
    }
    //
    ctrl_var.history_data_rolling = 2; // 默认2小时
    get_board_sn(ctrl_var.sn_str);
    get_process_name(ctrl_var.proc_name);
    ctrl_var.sample_rate = 10;
    if (ctrl_var.net_node == NULL)
    {
        ctrl_var.net_node = strdup("eth0");
    } //
#if (SUPPORT_LED == 1)
    led_init();
    net_led_check();
    post_run_led(LED_TWINKLE);
#endif
    //
    set_default_sample_rare(ctrl_var.sample_rate);
    ctrl_var.device_layer_ptr = proto_forward_creat(&proto_par);
    if (proto_par.ua_base_data.open_history)                                                                                                                                                            // 如果开启历史数据定时监测历史数据
    {
        pthread_t tid;
        if (0 == pthread_create(&tid,NULL, HistoryCycleTask, ((proto_forward_t *)ctrl_var.device_layer_ptr)->ua_server_param))
        {
            pthread_setname_np(tid, "HistoryCycle");
        }
        else
        {
            ems_syslog(LOG_ERR, "HistoryCycleTask create error");
            exit(0);
        }
    }  
    return ctrl_var.device_layer_ptr;
}

static void print_help(void)
{
    printf("\n--------------------------------------------------------------------------------\n");
    printf("Usage: emu_lc [OPTIONS]\n");
    printf("\n");
    printf("-v, --version         show this app version\n");
    printf("-c, --console         default run with deamon witch not log print;if set print to the termal\n");
    printf("-t, --time         shm update time\n");
    printf("-L, --prolevel [level]    emu_lc log level default:4\n");
    printf("-l, --emslevel [level]    ems log level default:4\n");
    printf("                                0:LOG_EMERG      system is unusable                 \n");
    printf("                                1:LOG_ALERT      action must be taken immediately   \n");
    printf("                                2:LOG_CRIT       critical conditions                \n");
    printf("                                3:LOG_ERR        error conditions                   \n");
    printf("                                4:LOG_WARNING    warning conditions                 \n");
    printf("                                5:LOG_NOTICE     normal, but significant, condition \n");
    printf("                                6:LOG_INFO       informational message              \n");
    printf("                                7:LOG_DEBUG      debug-level message                \n");
    printf("-h, --help            show this help\n");
    printf("\n--------------------------------------------------------------------------------\n");
}

static int extract_start_par(int argc, char *argv[])
{
    bool getversion = false;
    bool set_console = false;
    int proto_log_level = -1;
    int lc_log_level = -1;
    int c = '\0';
    while ((c = getopt(argc, argv, "n:vhcl:L:t:")) != -1)
    {
        switch (c)
        {
        case 'v':
            getversion = true;
            break;

        case 'c':
            set_console = true;
            break;

        case 'L':
            proto_log_level = atoi(optarg);
            break;

        case 'l':
            lc_log_level = atoi(optarg);
            break;

        case 'n':
            ctrl_var.net_node = strdup(optarg);
            break;

        case 't':
            db_update_interval = atoi(optarg);
            break;

        case 'h':
        case '?':
        default:
            print_help();
            exit(0);
        }
    }

    if (set_console)
    {
        openlog(argv[0], LOG_PERROR | LOG_PID, 0);
    }
    else
    {
        openlog(argv[0], LOG_PID, LOG_DAEMON);
    }

    if (proto_log_level > LOG_DEBUG || proto_log_level < LOG_EMERG)
    {
        proto_log_level = LOG_WARNING;
    }
    proto_syslog(LOG_NOTICE, "set proto_log level:%d", proto_log_level);
    proto_set_log_level(proto_log_level);
    if (lc_log_level > LOG_DEBUG || lc_log_level < LOG_EMERG)
    {
        lc_log_level = LOG_WARNING;
    }
    ems_set_log_level(lc_log_level);
    proto_syslog(LOG_NOTICE, "set lc_log level:%d", lc_log_level);

    if (getversion)
    {
        if (set_console)
        {
            proto_syslog(LOG_NOTICE, "project:lc - %s\nmajor version: %s, build at %s %s", DISPLAY_VERSION, SW_VERSION, __DATE__, __TIME__);
        }
        else
        {
            printf("ver: %s\n", DISPLAY_VERSION);
            printf("major version: %s, build at %s %s\r\n", SW_VERSION, __DATE__, __TIME__);
        }
        exit(0);
    }
    return 0;
}

int update_cabinet_cnt(pcs_ctrl_var_t *var)
{
    int cnt = get_same_type_devs_cnt(DEV_NO_PCS);
    if (cnt <= 0)
    {
        var->cabinet_cnt = 1; // 缺省1组
        ems_syslog(LOG_ERR, "System must be included PCS device");
    }
    else
    {
        var->cabinet_cnt = cnt;
        ems_syslog(LOG_NOTICE, "Find %d PCS in device list", var->cabinet_cnt);
    }
    return 0;
}

int creat_power_manager_thread(void)
{
    pthread_t thread = PTHREAD_NULL;
    if (pthread_create(&thread, NULL, lc_power_manage, NULL) != 0)
    {
        perror("creat power manager thread error");
        return -1;
    }
    else
    {
        pthread_setname_np(thread, "power_manage");
        return 0;
    }
}

static int sys_reboot(int reboot_flag)
{
    sleep(3);
    while (1)
    {
        ems_syslog(LOG_EMERG, "systemctl reboot ... reboot_flag=%d", reboot_flag);
        cmd_call("reboot -d 20 &",1,NULL,0);
        sleep(10);
    }
    return 0;
}

int main(int argc, char *argv[])
{
    proto_forward_t *proto = NULL;
    init_multilanguage();
    sig_init();
    log_module_server_init();
    extract_start_par(argc, argv);
    cmd_client_init("cmdclient_lc");
    proto = pr_init();
    if (proto == NULL)
    {
        ems_syslog(LOG_ERR, "pre init err");
        return -1;
    }
    data_presistence_start(proto->gv, "DataPersist");
    load_device_cfg(proto, CONFIG_PATH "/lc/" COLLECTOR_DEVICE, 1);
    update_cabinet_cnt(&ctrl_var);
    load_lc_device_cfg(proto);
    proto_forward_later_handle();
    if (proto->gv != NULL)
    {
        data_presistence_start(proto->gv, "DataPersist");
    }
    add_lc_system_info(proto->ua_server_param);
    pe_adapter_probe();

    lc_discover_init(ctrl_var.sn_str, DISCOVERY_TYPE_LC);

    proto_forward_schedule(proto);
    creat_power_manager_thread();
    heat_management_main(0);
    while (1)
    {
        if (ctrl_var.reboot_flag != 0)
        {
            sys_reboot(ctrl_var.reboot_flag);
        }
        sleep(1);
    }

    return 0;
}
