/* See frb_match.h */
/* Last edited on 2004-12-31 12:20:06 by stolfi */

#include <frb_match.h>
#include <frb_types.h>
#include <frb_segment.h>
#include <frb_proc.h>

#include <fget.h>
#include <nget.h>
#include <filefmt.h>

#include <string.h>
#include <assert.h>

frb_match_t frb_match_most_perfect ( int n0, int n1 )
  { int np = frb_imax(n0, n1);
    frb_match_t mt = frb_match_new(np);
    frb_match_domost_perfect(n0, n1, &mt);
    return mt;
  }

void frb_match_domost_perfect ( int n0, int n1, frb_match_t *mt )
  {
    affirm(n0 > 0, "bad n0");
    affirm(n1 > 0, "bad n1");
    int np = mt->nel;
    affirm(np == frb_imax(n0,n1), "bad length");
    if (np == 1)
      { mt->el[0] = (i2_t){{0,0}}; }
    else
      { double fn0 = (double)(n0-1);
        double fn1 = (double)(n1-1);
        double fnp = (double)(np-1);
        int i;
        for (i = 0; i < np; i++)
          { double fi = (double)i;
            int p0 = frb_round((fn0 * fi)/fnp);
            int p1 = frb_round((fn1 * fi)/fnp);
            mt->el[i] = (i2_t){{p0, p1}};
          }
      }
  }

frb_match_t frb_match_unpack ( frb_match_packed_t *pm )
  { int np = pm->np;
    frb_match_t mt = frb_match_new(np);
    frb_match_do_unpack(pm, &mt);
    return mt;
  }

void frb_match_do_unpack ( frb_match_packed_t *pm, frb_match_t *mt )
  { int np = pm->np;
    int i;
    affirm(mt->nel == np, "size mismatch");
    affirm(strlen(pm->steps) == np, "wrong size");
    affirm(pm->steps[0] == '|', "bad start");
    mt->el[0] = pm->ini;
    for (i = 1; i < np; i++)
    { char c = pm->steps[i];
      i2_t *ant = &(mt->el[i-1]), *ths = &(mt->el[i]);
      if (c == '/')
        { ths->c[0] = ant->c[0] + 1; ths->c[1] = ant->c[1]; }
      else if (c == '\\')
        { ths->c[0] = ant->c[0];     ths->c[1] = ant->c[1] + 1; }
      else if (c == '|')
        { ths->c[0] = ant->c[0] + 1; ths->c[1] = ant->c[1] + 1; }
      else
        { affirm(FALSE, "bad char"); }
    }
    affirm(mt->el[np-1].c[0] == pm->fin.c[0], "ends dont match");
    affirm(mt->el[np-1].c[1] == pm->fin.c[1], "ends dont match");
  }

frb_match_packed_t *frb_match_pack( frb_match_t *mt )
  {
    int np = (mt->nel);
    char *ch = (char *)notnull(malloc((1+np)*sizeof(char)), "no mem");
    char *q = ch;
    int i;
    (*q) = '|'; q++;
    for (i = 1; i < np; i++)
      {
        int ri = mt->el[i].c[0], ra = mt->el[i-1].c[0];
        int si = mt->el[i].c[1], sa = mt->el[i-1].c[1];
        if ((ri == ra+1) && (si == sa))
          { (*q) = '/'; }
        else if ((ri == ra) && (si == sa+1))
          { (*q) =  '\\'; }
        else if ((ri == ra+1) && (si == sa+1))
          { (*q) = '|'; }
        else
          { fprintf(stderr, "bad matching: (%d,%d) (%d,%d)\n", ra, sa, ri, si);
            assert(FALSE);
          }
        q++;
      }
    (*q) = '\000'; 
    frb_match_packed_t *pm = (frb_match_packed_t *)
      notnull(malloc(sizeof(frb_match_packed_t)), "no mem");
    pm->np = np;
    pm->ini = mt->el[0];
    pm->fin = mt->el[np-1];
    pm->steps = ch;
    return pm;
  }

frb_match_packed_t *frb_match_pack_perfect( int nSamples )
  { 
    int np = nSamples; /* One pair per sample. */
    char *ch = (char *)notnull(malloc((1+np)*sizeof(char)), "no mem");
    char *q = ch;
    int i;
    for (i = 0; i < np; i++) { (*q) = '|'; q++; }
    (*q) = '\000'; 
    frb_match_packed_t *pm = (frb_match_packed_t *)
      notnull(malloc(sizeof(frb_match_packed_t)), "no mem");
    pm->np = np;
    pm->ini = (i2_t){{0,0}};
    pm->fin = (i2_t){{nSamples-1,nSamples-1}};
    pm->steps = ch;
    return pm;
  } 

void frb_match_write_packed ( FILE *wr, frb_match_packed_t *pm )
  {
    int np = pm->np;
    int j;
    assert(strlen(pm->steps) == np );
    fprintf(wr, "%d (", np); 
    for (j = 0; j <= 1 ; j++)
      { fprintf(wr, "%d %d  ", pm->ini.c[j], pm->fin.c[j]); }
    fprintf(wr, "%s)", pm->steps);
  }

frb_match_packed_t *frb_match_read_packed ( FILE *rd )
  {
    frb_match_packed_t *pm = (frb_match_packed_t *)
      notnull(malloc(sizeof(frb_match_packed_t)), "no mem");
    int np = fget_int(rd);
    pm->np = np;
    fget_skip_spaces(rd);
    fget_match(rd, "(");
    int i, j;
    for (j = 0; j <= 1; j++)
      { pm->ini.c[j] = fget_int(rd);
        pm->fin.c[j] = fget_int(rd);
      }
    /* Read the packed pairing: */
    fget_skip_spaces(rd);
    char *ch = (char *)notnull(malloc((1+np)*sizeof(char)), "no mem");
    fget_match(rd, "|"); ch[0] = '|';
    for (i = 1; i < np; i++)
      { int c = fgetc(rd);
        affirm(c != EOF, "unexpected end-of-file");  
        affirm((c == '/') || (c == '|') || (c == '\\'), "invalid char");
        ch[i] = c;
      }
    ch[np] = '\000';
    fget_skip_spaces(rd);
    fget_match(rd, ")");
    pm->steps = ch;
    return pm;
  }

void frb_debug_int_pair ( char *title, int r, int s )
  {
    fprintf(stderr, "%s %d %d\n", title, r, s);
  }


