#include <stdlib.h>
#include <string.h>

#include "marsio_io.h"
#include "dumpfile_io.h"

struct packet_io
{
    enum packet_io_mode mode;
    struct marsio_io *marsio;
    struct dumpfile_io *dumpfile;
};

struct packet_io *packet_io_new(struct packet_io_options *opts)
{
    struct packet_io *packet_io = (struct packet_io *)calloc(1, sizeof(struct packet_io));
    if (packet_io == NULL)
    {
        return NULL;
    }

    packet_io->mode = opts->mode;
    if (opts->mode == PACKET_IO_MARSIO)
    {
        packet_io->marsio = marsio_io_new(opts->app_symbol, opts->dev_symbol, opts->cpu_mask, opts->nr_threads);
    }
    else
    {
        packet_io->dumpfile = dumpfile_io_new(opts->dumpfile_path, packet_io->mode, opts->nr_threads);
    }
    if (packet_io->marsio == NULL && packet_io->dumpfile == NULL)
    {
        goto error_out;
    }

    return packet_io;

error_out:
    packet_io_free(packet_io);
    return NULL;
}

void packet_io_free(struct packet_io *packet_io)
{
    if (packet_io)
    {
        if (likely(packet_io->mode == PACKET_IO_MARSIO))
        {
            marsio_io_free(packet_io->marsio);
        }
        else
        {
            dumpfile_io_free(packet_io->dumpfile);
        }
        free(packet_io);
        packet_io = NULL;
    }
}

int packet_io_isbreak(struct packet_io *packet_io) // used for dumpfile mode
{
    if (likely(packet_io->mode == PACKET_IO_MARSIO))
    {
        return 0;
    }
    else
    {
        return dumpfile_io_isbreak(packet_io->dumpfile);
    }
}

int packet_io_init(struct packet_io *packet_io, uint16_t thr_idx)
{
    if (likely(packet_io->mode == PACKET_IO_MARSIO))
    {
        return marsio_io_init(packet_io->marsio, thr_idx);
    }
    else
    {
        return dumpfile_io_init(packet_io->dumpfile, thr_idx);
    }
}

uint16_t packet_io_input(struct packet_io *packet_io, uint16_t thr_idx, struct packet *pkts, uint16_t nr_pkts)
{
    if (likely(packet_io->mode == PACKET_IO_MARSIO))
    {
        return marsio_io_input(packet_io->marsio, thr_idx, pkts, nr_pkts);
    }
    else
    {
        return dumpfile_io_input(packet_io->dumpfile, thr_idx, pkts, nr_pkts);
    }
}

void packet_io_output(struct packet_io *packet_io, uint16_t thr_idx, struct packet *pkts, uint16_t nr_pkts)
{
    if (likely(packet_io->mode == PACKET_IO_MARSIO))
    {
        marsio_io_output(packet_io->marsio, thr_idx, pkts, nr_pkts);
    }
    else
    {
        dumpfile_io_output(packet_io->dumpfile, thr_idx, pkts, nr_pkts);
    }
}

void packet_io_drop(struct packet_io *packet_io, uint16_t thr_idx, struct packet *pkts, uint16_t nr_pkts)
{
    if (likely(packet_io->mode == PACKET_IO_MARSIO))
    {
        marsio_io_drop(packet_io->marsio, thr_idx, pkts, nr_pkts);
    }
    else
    {
        dumpfile_io_drop(packet_io->dumpfile, thr_idx, pkts, nr_pkts);
    }
}

uint16_t packet_io_inject(struct packet_io *packet_io, uint16_t thr_idx, struct packet *pkts, uint16_t nr_pkts)
{
    if (likely(packet_io->mode == PACKET_IO_MARSIO))
    {
        return marsio_io_inject(packet_io->marsio, thr_idx, pkts, nr_pkts);
    }
    else
    {
        return dumpfile_io_inject(packet_io->dumpfile, thr_idx, pkts, nr_pkts);
    }
}

void packet_io_yield(struct packet_io *packet_io, uint16_t thr_idx, uint64_t timeout_ms)
{
    if (likely(packet_io->mode == PACKET_IO_MARSIO))
    {
        marsio_io_yield(packet_io->marsio, thr_idx, timeout_ms);
    }
    else
    {
        dumpfile_io_yield(packet_io->dumpfile, thr_idx, timeout_ms);
    }
}

struct packet_io_stat *packet_io_stat(struct packet_io *packet_io, uint16_t thr_idx)
{
    if (likely(packet_io->mode == PACKET_IO_MARSIO))
    {
        return marsio_io_stat(packet_io->marsio, thr_idx);
    }
    else
    {
        return dumpfile_io_stat(packet_io->dumpfile, thr_idx);
    }
}
