#include "haversine.h"
#include <bits/types/FILE.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define DEBUG 0

#define EARTH_RADIUS_KM 6371.0

#if DEBUG
#define ITEM_COUNT 4
#else
#define ITEM_COUNT 10000000
#endif

struct Item {
  double x0;
  double y0;
  double x1;
  double y1;
};

int main(int argc, char *argv[]) {
#if DEBUG
  FILE *fp = fopen("../test_data.json", "rb");
#else
  FILE *fp = fopen("../data_10000000_flex.json", "rb");
#endif

  Item *items = (Item *)malloc(ITEM_COUNT * sizeof(Item));
  int index = 0;

  clock_t start_time = clock();

  {
    char buf[256];
    int read = fread(buf, 1, 256, fp);

    for (int i = 1; i < read; ++i) {
      if (buf[i] == '{') {
        fseek(fp, i, SEEK_SET);
        break;
      }
    }
  }

  while (true) {
    fscanf(fp, "{\n");

    int scanned = fscanf(fp,
                         "      \"x0\": %lf,\n      \"y0\": %lf,\n      "
                         "\"x1\": %lf,\n      \"y1\": %lf\n    },\n    ",
                         &(items[index].x0), &(items[index].y0),
                         &(items[index].x1), &(items[index].y1));

    if (scanned == 0) {
      break;
    }

    ++index;
  }

  clock_t mid_time = clock();

  double sum = 0.0;

  for (int i = 0; i < ITEM_COUNT; ++i) {
    sum += haversine_of_degrees(items[i].x0, items[i].y0, items[i].x1,
                                items[i].y1, EARTH_RADIUS_KM);
  }

  double average = sum / ITEM_COUNT;

  clock_t end_time = clock();

  printf("Result: %.16f\n", average);
  printf("Input = %.16f seconds\n",
         (double)(mid_time - start_time) / CLOCKS_PER_SEC);
  printf("Math = %.16f seconds\n",
         (double)(end_time - mid_time) / CLOCKS_PER_SEC);
  printf("Total = %.16f seconds\n",
         (double)(end_time - start_time) / CLOCKS_PER_SEC);
  printf("Throughput = %.16f haversines/second\n",
         ITEM_COUNT / ((double)(end_time - start_time) / CLOCKS_PER_SEC));

#if DEBUG
  for (int i = 0; i < ITEM_COUNT; ++i) {
    printf("%.16f\n%.16f\n%.16f\n%.16f\n\n", items[i].x0, items[i].y0,
           items[i].x1, items[i].y1);
  }
#endif

  free(items);

  fclose(fp);

  return 0;
}