/* simple specialized JSON parser */
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <cstdint>
#include <string.h>
#include <stdlib.h>

typedef int64_t i64;
typedef double f64;

const char* T0="{\"pairs\":[\n    {\"x0\":";
const char* T1=", \"y0\":";
const char* T2=", \"x1\":";
const char* T3=", \"y1\":";
const char* T4="},\n    {\"x0\":";
const char* T5="}\n]}\n";

i64 buf_sz = 4096*512;
char *buf;
int pos_read=0;
int pos_used=0;
int all_read=0;

int buffer(int fd, int n){
  if(pos_used >= buf_sz) {
    /* adjust indexes */
    pos_used -= buf_sz;
    pos_read -= buf_sz;
  }
  if(pos_read-pos_used >= n) return 1;

  /* user needs more data */
  int n_read = read(fd, &buf[pos_read], buf_sz-pos_read+pos_used);
  all_read = 0==n_read;
  pos_read+=n_read;

  return pos_read-pos_used >= n;
}

int first_diff(const char* b0, const char* b1, int n){
  for(int i=0; i<n; ++i){
    if(b0[i]!=b1[i]) return i;
  }
  return n;
}

int min(int a,int b){
  if(a<b) return a;
  return b;
}

f64 read_f64(char separator){
  /* uses at most 18 digits */
  int minus = '-' == buf[pos_used];
  pos_used+=minus;
  int p1 = 0;
  while('.' != buf[pos_used+p1]) ++p1;
  int p2 = p1+1;
  while(separator != buf[pos_used+p2]) ++p2;

  i64 v=0;
  i64 m=1;
  for(int i=19; i>p2;--i) m*=10;
  
  for(int i=min(p2,19); --i > p1;) {
    v += m*(buf[pos_used+i]-'0');
    m*=10;
  }
  for(int i=p1; i--;) {
    v += m*(buf[pos_used+i]-'0');
    m*=10;
  }
  const f64 ft[3] = {1E-17,1E-16,1E-15};
  const f64 fs[2] = {1.0, -1.0};
  pos_used+=p2;

  return v*fs[minus]*ft[p1-1];
}

int
main()
{
  /* https://www.github.com/tmick0 code adapted from https://lo.calho.st/posts/black-magic-buffer/ */
  /* create buffer from same memory twice  */
  int buffd = memfd_create("readbuf", 0);
  int err = ftruncate(buffd, buf_sz);
  buf = (char*)mmap(NULL, 2 * buf_sz, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  mmap((void*)buf, buf_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, buffd, 0);
  mmap((void*)(buf + buf_sz), buf_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, buffd, 0);

  int fd=0; /* stdin */
  
  int T0L = strlen(T0);
  int T1L = strlen(T1);
  int T2L = strlen(T2);
  int T3L = strlen(T3);
  int T4L = strlen(T4);
  int T5L = strlen(T5);

  int n=0;
  
  if(!buffer(fd, T0L)) {
    fprintf(stderr,"File is shorter than T0.\n");
    exit(1);
  }
  if(T0L != first_diff(T0, &buf[pos_used], T0L)) {
    fprintf(stderr,"File does not start with T0.\n");
    exit(1);
  }
  pos_used+=T0L;

  f64 x0, y0, x1, y1;
  while(true) {
    ++n;
    if(!buffer(fd, 21)) {
      fprintf(stderr,"File ended when trying to read x0.\n");
      exit(1);
    }
    x0 = read_f64(',');
    if(!buffer(fd, T1L)) {
      fprintf(stderr,"File ended when trying to read T1.\n");
      exit(1);
    }
    if(T1L != first_diff(T1, &buf[pos_used], T1L)) {
      fprintf(stderr,"Expected T1.\n");
      exit(1);
    }
    pos_used+=T1L;
    if(!buffer(fd, 21)) {
      fprintf(stderr,"File ended when trying to read y0.\n");
      exit(1);
    }
    y0 = read_f64(',');
    if(!buffer(fd, T2L)) {
      fprintf(stderr,"File ended when trying to read T2.\n");
      exit(1);
    }
    if(T2L != first_diff(T2, &buf[pos_used], T2L)) {
      fprintf(stderr,"Expected T2.\n");
      exit(1);
    }
    pos_used+=T2L;
    if(!buffer(fd, 21)) {
      fprintf(stderr,"File ended when trying to read x1.\n");
      exit(1);
    }
    x1 = read_f64(',');
    if(!buffer(fd, T3L)) {
      fprintf(stderr,"File ended when trying to read T3.\n");
      exit(1);
    }
    if(T3L != first_diff(T3, &buf[pos_used], T3L)) {
      fprintf(stderr,"Expected T3.\n");
      exit(1);
    }
    pos_used+=T3L;
    if(!buffer(fd, 21)) {
      fprintf(stderr,"File ended when trying to read final y1.\n");
      exit(1);
    }
    y1 = read_f64('}');
    if(!buffer(fd, T4L)) {
      break;
    }
    if(T4L != first_diff(T4, &buf[pos_used], T4L)) {
      fprintf(stderr,"Expected T4.\n");
      exit(1);
    }
    pos_used+=T4L;
  }
  if(!buffer(fd, T5L)) {
    fprintf(stderr,"File ended when trying to read T5.\n");
    exit(1);
  }
  if(T5L != first_diff(T5, &buf[pos_used], T5L)) {
    fprintf(stderr,"Expected T5.\n");
    exit(1);
  }
    pos_used+=T5L;
  if(buffer(fd,1)) {
    fprintf(stderr,"File didn't end where expected.\n");
    exit(1);
  }
  printf("%d rows read.\n", n);
  return 0;
}
