#ifdef TEST_DISCONTIG_ADDR

#include "nvfs-dma.h"
#include <linux/random.h>

uint64_t address[1024];
uint64_t address_1[1024];
uint64_t address_2[1024];

uint64_t gpu_addr = 0xabcd1234;
uint64_t gpu_addr_1 = 0xabcd1234;
uint64_t gpu_addr_2 = 0xabcd1234;

#define GPU_PAGE_SZ 65536

void nvfs_init_simulated_address(void)
{
        int j = 0;
        while (j < 1024) {
                address[j] = gpu_addr;
                address_1[j] = gpu_addr_1;
                address_2[j] = gpu_addr_2;
		j += 1;

                if ((j > 0) && (j % 16) == 0)
                        gpu_addr_1 += (PAGE_SIZE * 2);
                else
                        gpu_addr_1 += PAGE_SIZE;

                if ((j > 0) && (j % 32) == 0)
                        gpu_addr_2 += (PAGE_SIZE * 2);
                else
                        gpu_addr_2 += PAGE_SIZE;

                gpu_addr += PAGE_SIZE;
        }
}

uint64_t nvfs_get_simulated_address(int key, int index)
{
        switch(key) {
                case 0:
                        return address[index];
                case 1:
                        return address_1[index];
                case 2:
                        return address_2[index];
                default:
                        exit(1);
        }
}

int nvfs_get_simulated_key_index(void)
{
        return (unsigned long)prandom_u32() % 3;
}

static void print()
{
        printk("Printing address\n");
        for (int j = 0; j < 1024; j++) {
                printk("%lx\n", address[j]);
                if (j != 0) {
                        if (!is_gpu_page_contiguous(address[j - 1], address[j]))
                                printk("**************Discontiguous Address found at %d\n", j);
                }
        }

        printk("\nPrinting address_1\n");
        for (int j = 0; j < 1024; j++) {
                printk("%lx\n", address_1[j]);
                if (j != 0) {
                        if (!is_gpu_page_contiguous(address_1[j - 1], address_1[j]))
                                printk("**************Discontiguous Address found at %d\n", j);
                }
        }

        printk("\nPrinting address_2\n");
        for (int j = 0; j < 1024; j++) {
                printk("%lx\n", address_2[j]);
                if (j != 0) {
                        if (!is_gpu_page_contiguous(address_2[j - 1], address_2[j]))
                                printk("**************Discontiguous Address found at %d\n", j);
                }
        }
}

static void simulate_dma_address_contiguity(int dma_length, int key)
{
        uint64_t *addr;

        switch (key) {
                case 0:
                        addr = address;
                        break;
                case 1:
                        addr = address_1;
                        break;
                case 2:
                        addr = address_2;
                        break;
        }

        printk("Simulate_dma_address Invoked with dma_length %d key %d\n",
                                dma_length, key);

	// Simulate the logic in nvfs_get_dma()
        if ((dma_length > GPU_PAGE_SZ)) {
                uint64_t start_addr = *addr;
                size_t sg_length = dma_length;

		//Start at a random index within DMA range
                int index = (unsigned long)prandom_u32() % 1024;

                while (dma_length > 0) {
                        if (dma_length > GPU_PAGE_SZ) {
                                dma_length -= GPU_PAGE_SZ;
                                start_addr += GPU_PAGE_SZ;
                                index += 16;

                                // If this is true, then sg->length isn't right
                                if (index >= 1024) {
                                        printk("Invalid sg->length %ld\n", sg_length);
                                        return;
                                }

                                if (start_addr != addr[index]) {
                                        printk("Discontiguous address found at index %d\n", index);
                                        start_addr = addr[index]; // Only for testing
                                        continue;
                                }
                        } else {
                                break;
                        }
                }
        }
}

#if 0
int main(void)
{
        nvfs_init_simulated_address();

        print();

        int key = nvfs_get_key();
        for (int i = 0; i < 1024; i++) {

                printf("PhyAddr %lx key %d i %d\n", nvfs_get_simulated_address(key, i), key, i);

        }

        key = nvfs_get_key();
        for (int i = 0; i < 1024; i++) {
                printf("PhyAddr %lx key %d i %d\n", nvfs_get_simulated_address(key, i), key, i);
        }


        for (int i = 0; i < 5; i++) {
                int key = nvfs_get_key();
                simulate_dma_address_contiguity((128 * 1024), key);
                simulate_dma_address_contiguity((1 * 1024 * 1024), key);
                simulate_dma_address_contiguity((2 * 1024 * 1024), key);
                simulate_dma_address_contiguity((64 * 1024), key);
                simulate_dma_address_contiguity((64 * 1024 * 1024), key);
        }
        return 0;
}
#endif

#endif
