/**/

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <limits.h>

#define INPUT_SAMPLERATE 8 /*kHz*/
#define IGNORE_FIRST 1 /*s*/
#define CONSIDER_ONLY_THEN 30 /*s*/
#define OVERLAP_AREA 20000 /*ms*/

#define MAX_SAMPLES (CONSIDER_ONLY_THEN*1000*INPUT_SAMPLERATE)
#define MAX_OFFSET (MAX_SAMPLES - OVL_SAMPLES)
#define OVL_SAMPLES (OVERLAP_AREA*INPUT_SAMPLERATE)

typedef signed char datum;

static struct data_array {
  int n;
  datum *data;
} ai, aj;

#define input_assert(fd,m) do{ if (!(m)) input_assert_fail(fd,#m); }while(0)

static void input_assert_fail(int fd, const char *msg) {
  fprintf(stderr,"bikecams-audio: input or usage error, fd=%d:"
	  " failed assertion %s\n", fd, msg);
  exit(12);
}

static void read_inputfile(int fd, FILE *f, struct data_array *ar) {
  struct stat stab;
  int r;
  
  r= fstat(fd,&stab);  if (r) { perror("fstat"); exit(-1); }
  input_assert(fd, S_ISREG(stab.st_mode));

  input_assert(fd, stab.st_size > IGNORE_FIRST);
  ar->n= stab.st_size - IGNORE_FIRST;
  if (ar->n > MAX_SAMPLES)
    ar->n= MAX_SAMPLES;

  ar->data= malloc(ar->n * sizeof(*ar->data));
  if (!ar->data) { perror("malloc"); exit(-1); }

  r= fseek(f,IGNORE_FIRST,SEEK_SET);
  if (r) { perror("fseek"); exit(-1); }
  r= fread(ar->data,sizeof(*ar->data),ar->n,f);
  if (ferror(f)) { perror("fread"); exit(-1); }
  input_assert(fd, r==ar->n);
  fprintf(stderr,"from fd=%d read %d samples\n",fd,ar->n);
}

static void compute(void) {
  int offset, i,j,ni,nj,n, best_offset, k;
  datum *gpi, *gpj;
  long sum_of_products;
  double mean, best_mean;

  best_mean= -1e100;
  best_offset= 0;

  for (offset= -MAX_OFFSET;
       offset <= MAX_OFFSET;
       offset++) {
    fprintf(stderr,"off=%8d %7.3fs: ",offset,
	    offset/(1000.0*INPUT_SAMPLERATE));
    sum_of_products= 0;
    if (offset>=0) { i=0; j=offset; } else { i=-offset; j=0; }
    ni= ai.n - i;
    nj= aj.n - j;
    n= ni < nj ? ni : nj;
    if (n < OVL_SAMPLES) {
      fprintf(stderr,"too few (%d,%d)\r",ni,nj);
      continue;
    }
    if (n > OVL_SAMPLES) {
      i += (n - OVL_SAMPLES);
      j += (n - OVL_SAMPLES);
      n= OVL_SAMPLES;
    }
    /*fprintf(stderr,"i:%7x, j=%7x, n=%5x: ",i,j,n);*/
    for (gpi=ai.data+i, gpj=aj.data+j, k=0; k<n; k++,gpi++,gpj++) {
      /*if (k<5) { fprintf(stderr,"%02x*%02x ", 0xff & *gpi, 0xff & *gpj); }*/
      sum_of_products += (*gpi * *gpj);
    }
    mean= (double)sum_of_products / n;
    fprintf(stderr," mean=%10.3f", mean);
    if (mean < best_mean) {
      double percent= 100.0*mean/best_mean;
      fprintf(stderr,": %6.2f%%%c", percent,
	      percent > 90.0 ? '\n' : '\r');
    } else if (mean == best_mean) {
      fprintf(stderr,": equal\n");
    } else {
      best_mean= mean;
      best_offset= offset;
      fprintf(stderr,": **BEST**\n");
    }
  }
  printf("%d %.3fs %d\n",
	 best_offset,
	 best_offset/(1000.0*INPUT_SAMPLERATE),
	 (int)(best_offset * 0.030) / INPUT_SAMPLERATE);
}

int main(int argc, const char **argv) {
  FILE *nonstdin;

  if (argc!=2 || strcmp(argv[1],"--not-interactive")) {
    fputs("this is not an interactive program\n",stderr);
    exit(127);
  }
  nonstdin= fdopen(3,"rb");  if (!nonstdin) { perror("fdopen"); exit(-1); }
  read_inputfile(0,stdin,&ai);
  read_inputfile(3,nonstdin,&aj);
  compute();
  return 0;
}

