#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>

#include <sys/time.h>

#define PRESERVES_IMPLEMENTATION
#include "preserves.h"

static double now() {
  struct timeval tv;
  if (gettimeofday(&tv, NULL) < 0) {
    perror("gettimeofday");
  }
  return (double) tv.tv_sec + ((double) tv.tv_usec) / 1000000.0;
}

int main(__attribute__ ((unused)) int argc,
         __attribute__ ((unused)) char const * const argv[])
{
  preserves_bytes_t input = preserves_create_bytes();
  bool silent = getenv("SILENT") != NULL;

  double start = now();

  {
    preserves_bytes_t chunk = preserves_create_bytes();
    if (preserves_resize_bytes(&chunk, 131072) == -1) {
      perror("allocating chunk");
      return EXIT_FAILURE;
    }

    while (true) {
      size_t count = fread(chunk.ptr, 1, chunk.len, stdin);
      if (count == 0) {
        if (ferror(stdin)) {
          perror("reading");
          return EXIT_FAILURE;
        }
        break;
      }
      if (preserves_extend_bytes(&input, preserves_bytes_subsequence(&chunk, 0, count)) == -1) {
        perror("appending");
        return EXIT_FAILURE;
      }
    }

    preserves_free_bytes(&chunk);
  }

  double mid = now();

  {
    preserves_reader_t reader = preserves_create_reader();
    preserves_reader_result_t result = preserves_read_binary(&reader, &input, 1);
  more_input:
    if (result.index == NULL) {
      perror("parsing");
      return EXIT_FAILURE;
    }

    if (!silent) {
      printf("Size of index: %lu bytes; %lu entries\n",
             reader.index_pos * sizeof(preserves_index_entry_t),
             reader.index_pos);
    }

    if (!silent) {
      for (preserves_index_entry_t *i = result.index; i != result.end_marker; i++) {
        preserves_dump_index_entry(stdout, &reader.input, i, true);
      }
      preserves_dump_index_entry(stdout, &reader.input, result.end_marker, true);
    }

    if (result.end_marker->data._err == PRESERVES_END_MORE_INPUT_REMAINING) {
      if (!silent) {
        printf("\n");
      }
      reader.index_pos = 0;
      result = preserves_read_binary_continue(&reader, 1);
      goto more_input;
    }

    preserves_free_reader(&reader);
  }

  double end = now();

  printf("stage 1: %g s\n", mid - start);
  printf("stage 2: %g s\n", end - mid);
  printf("total: %g s\n", end - start);

  preserves_free_bytes(&input);
  return EXIT_SUCCESS;
}
