#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <sys/queue.h>
#include <getopt.h>
#include "channel_manager.h"
#include "channel_monitor.h"
#include "power_manager.h"
#include "vm_power_cli.h"
#include "oob_monitor.h"
#include "parse.h"
#ifdef RTE_LIBRTE_IXGBE_PMD
#endif
#ifdef RTE_LIBRTE_I40E_PMD
#endif
#ifdef RTE_LIBRTE_BNXT_PMD
#include <rte_pmd_bnxt.h>
#endif
#define RX_RING_SIZE 1024
#define TX_RING_SIZE 1024
#define NUM_MBUFS 8191
#define MBUF_CACHE_SIZE 250
#define BURST_SIZE 32
static uint32_t enabled_port_mask;
static volatile bool force_quit;
    },
};
static inline int
{
    const uint16_t rx_rings = 1, tx_rings = 1;
    int retval;
    uint16_t q;
        return -1;
    
    if (retval != 0)
        return retval;
    
    for (q = 0; q < rx_rings; q++) {
        if (retval < 0)
            return retval;
    }
    txq_conf = dev_info.default_txconf;
    
    for (q = 0; q < tx_rings; q++) {
        if (retval < 0)
            return retval;
    }
    
    if (retval < 0)
        return retval;
    
    printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8
               " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n",
            (unsigned int)port,
            addr.addr_bytes[0], addr.addr_bytes[1],
            addr.addr_bytes[2], addr.addr_bytes[3],
            addr.addr_bytes[4], addr.addr_bytes[5]);
    
    return 0;
}
static int
parse_portmask(const char *portmask)
{
    char *end = NULL;
    unsigned long pm;
    
    pm = strtoul(portmask, &end, 16);
    if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
        return -1;
    if (pm == 0)
        return -1;
    return pm;
}
static int
parse_args(int argc, char **argv)
{
    int opt, ret, cnt, i;
    char **argvopt;
    uint16_t *oob_enable;
    int option_index;
    char *prgname = argv[0];
    struct core_info *ci;
    float branch_ratio;
    static struct option lgopts[] = {
        { "mac-updating", no_argument, 0, 1},
        { "no-mac-updating", no_argument, 0, 0},
        { "core-list", optional_argument, 0, 'l'},
        { "port-list", optional_argument, 0, 'p'},
        { "branch-ratio", optional_argument, 0, 'b'},
        {NULL, 0, 0, 0}
    };
    argvopt = argv;
    ci = get_core_info();
    while ((opt = getopt_long(argc, argvopt, "l:p:q:T:b:",
                  lgopts, &option_index)) != EOF) {
        switch (opt) {
        
        case 'p':
            enabled_port_mask = parse_portmask(optarg);
            if (enabled_port_mask == 0) {
                printf("invalid portmask\n");
                return -1;
            }
            break;
        case 'l':
            oob_enable = malloc(ci->core_count * sizeof(uint16_t));
            if (oob_enable == NULL) {
                printf("Error - Unable to allocate memory\n");
                return -1;
            }
            cnt = parse_set(optarg, oob_enable, ci->core_count);
            if (cnt < 0) {
                printf("Invalid core-list - [%s]\n",
                        optarg);
                free(oob_enable);
                break;
            }
            for (i = 0; i < ci->core_count; i++) {
                if (oob_enable[i]) {
                    printf("***Using core %d\n", i);
                    ci->cd[i].oob_enabled = 1;
                    ci->cd[i].global_enabled_cpus = 1;
                }
            }
            free(oob_enable);
            break;
        case 'b':
            branch_ratio = 0.0;
            if (strlen(optarg))
                branch_ratio = atof(optarg);
            if (branch_ratio <= 0.0) {
                printf("invalid branch ratio specified\n");
                return -1;
            }
            ci->branch_ratio_threshold = branch_ratio;
            printf("***Setting branch ratio to %f\n",
                    branch_ratio);
            break;
        
        case 0:
            break;
        default:
            return -1;
        }
    }
    if (optind >= 0)
        argv[optind-1] = prgname;
    ret = optind-1;
    optind = 0; 
    return ret;
}
static void
check_all_ports_link_status(uint32_t port_mask)
{
#define CHECK_INTERVAL 100 
#define MAX_CHECK_TIME 90 
    uint16_t portid, count, all_ports_up, print_flag = 0;
    printf("\nChecking link status");
    fflush(stdout);
    for (count = 0; count <= MAX_CHECK_TIME; count++) {
        if (force_quit)
            return;
        all_ports_up = 1;
            if (force_quit)
                return;
            if ((port_mask & (1 << portid)) == 0)
                continue;
            memset(&link, 0, sizeof(link));
            
            if (print_flag == 1) {
                if (link.link_status)
                    printf("Port %d Link Up - speed %u "
                        "Mbps - %s\n", (uint16_t)portid,
                        (unsigned int)link.link_speed,
                    ("full-duplex") : ("half-duplex"));
                else
                    printf("Port %d Link Down\n",
                        (uint16_t)portid);
                continue;
            }
               
                all_ports_up = 0;
                break;
            }
        }
        
        if (print_flag == 1)
            break;
        if (all_ports_up == 0) {
            printf(".");
            fflush(stdout);
        }
        
        if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
            print_flag = 1;
            printf("done\n");
        }
    }
}
static int
run_monitor(__attribute__((unused)) void *arg)
{
    if (channel_monitor_init() < 0) {
        printf("Unable to initialize channel monitor\n");
        return -1;
    }
    run_channel_monitor();
    return 0;
}
static int
run_core_monitor(__attribute__((unused)) void *arg)
{
    if (branch_monitor_init() < 0) {
        printf("Unable to initialize core monitor\n");
        return -1;
    }
    run_branch_monitor();
    return 0;
}
static void
sig_handler(int signo)
{
    printf("Received signal %d, exiting...\n", signo);
    channel_monitor_exit();
    channel_manager_exit();
    power_manager_exit();
}
int
main(int argc, char **argv)
{
    int ret;
    unsigned lcore_id;
    unsigned int nb_ports;
    uint16_t portid;
    struct core_info *ci;
    ret = core_info_init();
    if (ret < 0)
    ci = get_core_info();
    if (ret < 0)
    signal(SIGINT, sig_handler);
    signal(SIGTERM, sig_handler);
    argc -= ret;
    argv += ret;
    
    ret = parse_args(argc, argv);
    if (ret < 0)
        rte_exit(EXIT_FAILURE, 
"Invalid arguments\n");
 
    if (nb_ports > 0) {
                NUM_MBUFS * nb_ports, MBUF_CACHE_SIZE, 0,
        if (mbuf_pool == NULL)
            rte_exit(EXIT_FAILURE, 
"Cannot create mbuf pool\n");
 
        
            int w, j;
            int ret;
            if ((enabled_port_mask & (1 << portid)) == 0)
                continue;
            eth.addr_bytes[1] = 0xe0;
            eth.addr_bytes[2] = 0xe0;
            eth.addr_bytes[3] = 0xe0;
            eth.addr_bytes[4] = portid + 0xf0;
            if (port_init(portid, mbuf_pool) != 0)
                    "Cannot init port %"PRIu8 "\n",
                    portid);
            for (w = 0; w < MAX_VFS; w++) {
                eth.addr_bytes[5] = w + 0xf0;
                ret = -ENOTSUP;
#ifdef RTE_LIBRTE_IXGBE_PMD
                            w, ð);
#endif
#ifdef RTE_LIBRTE_I40E_PMD
                if (ret == -ENOTSUP)
                            portid, w, ð);
#endif
#ifdef RTE_LIBRTE_BNXT_PMD
                if (ret == -ENOTSUP)
                    ret = rte_pmd_bnxt_set_vf_mac_addr(
                            portid, w, ð);
#endif
                switch (ret) {
                case 0:
                    printf("Port %d VF %d MAC: ",
                            portid, w);
                    for (j = 0; j < 5; j++) {
                        printf("%02x:",
                            eth.addr_bytes[j]);
                    }
                    printf("%02x\n", eth.addr_bytes[5]);
                    break;
                }
                printf("\n");
            }
        }
    }
    check_all_ports_link_status(enabled_port_mask);
    if (lcore_id == RTE_MAX_LCORE) {
        RTE_LOG(ERR, EAL, 
"A minimum of three cores are required to run " 
                "application\n");
        return 0;
    }
    printf("Running channel monitor on lcore id %d\n", lcore_id);
    if (lcore_id == RTE_MAX_LCORE) {
        RTE_LOG(ERR, EAL, 
"A minimum of three cores are required to run " 
                "application\n");
        return 0;
    }
    if (power_manager_init() < 0) {
        printf("Unable to initialize power manager\n");
        return -1;
    }
    if (channel_manager_init(CHANNEL_MGR_DEFAULT_HV_PATH) < 0) {
        printf("Unable to initialize channel manager\n");
        return -1;
    }
    add_host_channel();
    printf("Running core monitor on lcore id %d\n", lcore_id);
    run_cli(NULL);
    branch_monitor_exit();
    free(ci->cd);
    return 0;
}