/* See frb_signal.h */
/* Last edited on 2008-05-24 12:33:50 by stolfi */

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

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

#include <math.h>
#include <stdio.h>
#include <libiberty.h>
#include <values.h>

void frb_zero_signal (frb_signal_t *sg)
  {
    int nel = sg->nel, i;
    for (i = 0; i < nel; i++) { sg->el[i] = 0.0; }
  }

#define frb_signal_FileVersion "2004-11-21"

void frb_signal_write
  ( FILE *wr, 
    char *cmt, 
    frb_signal_t *c, 
    double stride, 
    double unit 
  )
  {
    auto int frb_signal_to_int( double x );
    int frb_signal_to_int( double x )
      {
        affirm(x > ((double)MININT), "out of range");
        affirm(x < ((double)MAXINT), "out of range");
        return frb_round(x);
      }
      
    filefmt_write_header(wr, "frb_signal_t", frb_signal_FileVersion);
    filefmt_write_comment(wr, cmt, '|');
    fprintf(wr, "stride = %g\n", stride);
    fprintf(wr, "unit = %g\n", unit);
    fprintf(wr, "samples = %d\n", c->nel);
    int i;
    for (i = 0; i < c->nel; i++)
      { fprintf(wr, "%d\n", frb_signal_to_int(c->el[i]/unit)); }
    filefmt_write_footer(wr, "frb_signal_t");
    fflush(wr);
  }

frb_signal_read_data_t frb_signal_read ( FILE *rd, bool_t header_only )
  {
    auto double frb_signal_to_double ( int n );
    double frb_signal_to_double ( int n )
      {
        affirm(n > MININT, "out of range");
        affirm(n < MAXINT, "out of range");
        return ((double)n);
      }

    frb_signal_read_data_t d;
    filefmt_read_header(rd, "frb_signal_t", frb_signal_FileVersion);
    d.cmt = filefmt_read_comment(rd, '|');
    d.stride = nget_double(rd, "stride");  fget_skip_formatting_chars(rd);
    d.unit = nget_double(rd, "unit");      fget_skip_formatting_chars(rd);
    d.samples = nget_int(rd, "samples");   fget_eol(rd);

    int n = d.samples;
    double unit = d.unit;
    if (header_only)
      { d.c = double_vec_new(n); }
    else
      { d.c = double_vec_new(n);
        int j;
        for (j = 0; j < n; j++)
          { fget_skip_formatting_chars(rd);
            d.c.el[j] = frb_signal_to_double(fget_int(rd)) * unit;
          }
        filefmt_read_footer(rd, "frb_signal_t");
      }
    return d;
  }

#define frb_signal_NO_DATA \
  (frb_signal_read_data_t) \
    { /*cmt*/ NULL, \
      /*samples*/ 0, \
      /*c*/ (frb_signal_t){ 0, NULL }, \
      /*stride*/ 0, \
      /*unit*/ 0 \
    }

frb_signal_list_read_data_t frb_signal_list_read
  ( char *dir, /* default was "." */
    char *fileName,
    bool_vec_t *sel,
    bool_t header_only     
  )
  {
    frb_signal_read_data_t *dd = 
      malloc(sel->nel * sizeof(frb_signal_read_data_t));
    double unitMin = +INFINITY;
    double unitMax = -INFINITY;
    char *cmt = ""; 
    
    fprintf(stderr, "reading signals:\n");

    int k;
    for (k = 0; k < sel->nel; k++)
      {
        frb_signal_read_data_t *ddk = &(dd[k]); 
        if (sel->el[k])
          {
            fprintf(stderr, "  %04d: ", k);
            char *full_name = NULL;
            asprintf(&full_name, "%s/%04d/%s", dir, k, fileName);
            FILE *rd = open_read(full_name, TRUE);
            if (rd != NULL)
              { *ddk = frb_signal_read(rd, header_only);
                fprintf(stderr, "read from %s\n", full_name);
                affirm(ddk->unit > 0, "bad unit");
                if (unitMin > unitMax) { cmt = ddk->cmt; }
                unitMin = frb_dmin(unitMin, ddk->unit);
                unitMax = frb_dmax(unitMax, ddk->unit);
                fclose(rd);
              }
            else  
              { *ddk = frb_signal_NO_DATA;
                fprintf(stderr, "file %s not found.\n", full_name);
              }
          }
        else
          { *ddk = frb_signal_NO_DATA; }
      }
    char *buf = NULL; 
    asprintf(&buf, 
      "Signals read from %s/NNNN/%s\nLast entry:\n%s", 
      dir, fileName, cmt
    );
    return (frb_signal_list_read_data_t)
      { /* sgData */  dd,
        /* unitMin */ unitMin,
        /* unitMax */ unitMax,
        /* cmt */     buf
      };
  }


