// Include required headers
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>

#include <doca_ctx.h>
#include <doca_dev.h>
#include <doca_dma.h> 
#include <doca_types.h>
#include <doca_buf.h>
#include <doca_log.h>
#include <doca_buf_inventory.h>
#include <doca_mmap.h>
#include <doca_pe.h>
#include <doca_compress.h>

#include "definitions.h"
#include "callbacks.h"
#include "utils.h"

DOCA_LOG_REGISTER(LAB5::LOGIC);

// Define the main logic function
doca_error_t run(struct program_state *state) {
	struct timespec ts = {
		.tv_sec = 0,
		.tv_nsec = SLEEP_IN_NANOS,
	};

    DOCA_LOG_INFO("Initializing program state");
    memset(state, 0, sizeof(*state));

    DOCA_LOG_INFO("Allocating buffer with size of %d", BUFFER_SIZE);
    state->base.buffer_size = BUFFER_SIZE;
    state->base.buffer = (uint8_t *)malloc(state->base.buffer_size);
	state->base.buf_inventory_size = BUF_INVENTORY_SIZE;

    if (state->base.buffer == NULL)
		return DOCA_ERROR_NO_MEMORY;

	state->base.available_buffer = state->base.buffer;

    struct doca_devinfo **dev_list;
    uint32_t nb_devs;
	int res = doca_devinfo_create_list(&dev_list, &nb_devs);
    if (res != DOCA_SUCCESS) {
		DOCA_LOG_ERR("Failed to load doca devices list: %s", 
			doca_error_get_descr(res));
		return res;
	}
	for (int i = 0; i < nb_devs; i++) {
        res = doca_compress_cap_task_decompress_deflate_is_supported(dev_list[i]);
        if (res != DOCA_SUCCESS) {
            continue;
        }
        if(doca_dev_open(dev_list[i], &state->base.device) == DOCA_SUCCESS) {
            doca_devinfo_destroy_list(dev_list);   
            break;     
        }
    }

	DOCA_LOG_INFO("Creating MMAP");
    EXIT_ON_FAILURE(doca_mmap_create(&state->base.src_mmap));
	EXIT_ON_FAILURE(doca_mmap_add_dev(state->base.src_mmap, state->base.device));
	EXIT_ON_FAILURE(doca_mmap_create(&state->base.dst_mmap));
	EXIT_ON_FAILURE(doca_mmap_add_dev(state->base.dst_mmap, state->base.device));

	DOCA_LOG_INFO("Creating buf inventory");
	EXIT_ON_FAILURE(doca_buf_inventory_create(state->base.buf_inventory_size, 
		&state->base.inventory));
	EXIT_ON_FAILURE(doca_buf_inventory_start(state->base.inventory));

    DOCA_LOG_INFO("Creating PE");
	EXIT_ON_FAILURE(doca_pe_create(&state->base.pe));

}

// Define the run_lab_logic function

