#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <arpa/inet.h>  // for htonl() and ntohl()

#include "ll.h"
#include "ll_file.h"

void *TestPayloadToByteArray(void *payload, uint32_t *arraylen);
void *TestByteArrayToPayload(void *array, uint32_t arraylen);

// Our main is a unit test for our WriteToFile() and ReadFromFile()
// functions.  (Note that WriteToFile() and ReadFromFile() are
// declared in ll_file.h and defined in ll_file.c.)
int main(int argc, char **argv) {
  // cons up a list.
  LinkedList list = AllocateLinkedList();
  assert(list != NULL);

  // add some elements to it.
  int i;
  for (i = 0; i < 100; i++) {
    uint32_t *next = (uint32_t *) malloc(sizeof(uint32_t));
    assert(next != NULL);
    *next = (uint32_t) i;

    assert(AppendLinkedList(list, (void *) next) == 1);
  }

  // write the list to a file.
  assert(WriteToFile(list, "ofile.bin", &TestPayloadToByteArray) == 1);

  // free the list.
  FreeLinkedList(list, &free);

  // read the list from the file.
  list = ReadFromFile("ofile.bin", &TestByteArrayToPayload);
  assert(list != NULL);

  // verify that the payloads are right.
  for (i = 0; i < 100; i++) {
    uint32_t *next;

    assert(PopLinkedList(list, (void **) &next) == 1);
    assert(*next == (uint32_t) i);
    free(next);
  }

  // verify we exhausted the list.
  assert(NumElementsInLinkedList(list) == 0);

  // excellent!  everything worked.  clean up.
  FreeLinkedList(list, &free);
  assert(unlink("ofile.bin") == 0);

  return EXIT_SUCCESS;
}

// Our payload is a malloc'ed uint32_t.  But, we have to be
// careful to make our on-file representation be a standard
// representation.  We'll convert to network byte order
// (big endian) using htonl() and ntohl() as our standard
// representation.  See the man pages for these for more
// information.
void *TestPayloadToByteArray(void *payload, uint32_t *arraylen) {
  uint32_t *intptr = (uint32_t *) malloc(sizeof(uint32_t));
  assert(intptr != NULL);

  *intptr = htonl(*((uint32_t *) payload));
  *arraylen = sizeof(uint32_t);
  return (void *) intptr;
}

void *TestByteArrayToPayload(void *array, uint32_t arraylen) {
  assert(arraylen == sizeof(uint32_t));
  uint32_t *intptr = (uint32_t *) malloc(sizeof(uint32_t));
  assert(intptr != NULL);

  *intptr = ntohl(*((uint32_t *) array));
  return (void *) intptr;
}