#! /usr/bin/gawk -f
# Last edited on 2021-08-27 23:01:38 by stolfi

BEGIN { 
  # Reads an isolated run, prints the range and avg of each electrode within the fixation and stimulus phases. 
  
  abort = -1;
  
  # Temporary:
  ne = -1; # Number of electrodes.
  nc = -1; # Number of channels.
  nt = -1; # Total number of frames in dataset.
  
  split("", chan);   # {chan[ic]} is the name of channel {ic} (from 1). */
  
  # The phase index {ip} ranges in {1..np}
  split("", icmk);   # {icmk[ip]} is the marker channel's index (from 1) for phase {ip}.
  split("", phname); # {phname[ip]} is the name of phase {ip}.

  # Specific for Gislain's 128 electrode dataset: 
  np = 2;  # Number of phases.
  phname[1] = "FX"; # Fixation.
  phname[2] = "ST"; # Stimulus.
  
  split("", ns_p);   # {ns_p[ip]} is number of times phase {ip} was seen.
  split("", nt_p);   # {nt_p[ip]} is number of frames in phase {ip}.
  
  split("", it_ini_p); # {it_ini_p[ip]} is the index (from 0) of the first frame of phase {ip}.
  split("", it_fin_p); # {it_fin_p[ip]} is the index (from 0) of the last frame of phase {ip}.
  
  split("", vmin_pe); # {vmin_pe[ip,ie]} is min value of electrode {ie} (from 1) during phase {ip} (1 or 2).
  split("", vmax_pe); # {vmax_pe[ip,ie]} is max value of electrode {ie} (from 1) during phase {ip} (1 or 2).
  split("", vsum_pe); # {vsum_pe[ip,ie]} is total value of electrode {ie} (from 1) during phase {ip} (1 or 2)
  
  split("", up); #  {up[ip]} tells whether the marker for phase {ip} was positive (1) or zero (0) in last frame. 

  for (ip = 1; ip <= np; ip++)
    { ns_p[ip] = 0;
      nt_p[ip] = 0;
      it_ini_p[ip] = +9999999;
      it_fin_p[ip] = +9999999;
      up[ip] = 0;
      for (ie = 1; ie <= ne; ie++) 
        { vmin_pe[ip,ie] = +9999999;
          vmax_pe[ip,ie] = -9999999; 
          vsum_pe[ip,ie] = 0;
        }
    }
  nframes = 0; # Number of data frames seen. 
}

(abort >= 0) { exit(abort); }

# Ignore comments and blank lines: 
// { gsub(/[#].*$/, "", $0); }
/^ *$/ { next; }

# Parse {nc,nt,} from header:
/^ *nt *[=] */ { nt = $3 + 0; next; }
/^ *nc *[=] */ { nc = $3 + 0; next; }

# Parse {chan} from header:
/^ *channels *[=] */ {
  if (nc < 0) { prog_error("did not find {nc} in header"); }
  if (NF != nc + 2) { prog_error("wrong num of channel names in header"); }
  for (ic = 1; ic <= nc; ic++) { chan[ic] = $(ic + 2); } 
  next
}

# Parse {ne} from header, define {icmk[1..np],phname[1..np]}:
/^ *ne *[=] */ { 
  if (nc < 0) { prog_error("did not find {nc} in header"); }
  ne = $3 + 0; 
  if ((ne < 1) || (ne+np > nc)) { prog_error("invalid {ne} in header"); }
  printf "nc = %d  ne = %d  nt = %d", nc, ne, nt > "/dev/stderr";
  # Specific for Gislain's 128 electrode dataset: 
  icmk[1] = nc-1; # Fixation.
  icmk[2] = nc;   # Stimulus.
  for (ip = 1; ip <= np; ip++) 
    { if (chan[icmk[ip]] != phname[ip]) { prog_error("marker channel name mismatch in header"); } }
  next;
}

# Ignore other header lines:
/^ *[a-zA-Z#]/ { next; }

# Process data lines:
/^ *[-+0-9]/ { 
  if (NF != nc) { data_error(("invalid line format")); }
  it = nframes; # Index of current frame (from 0).
  prev_ip = -1; # Last phase active in this frame, or -1 if none.
  for (ip = 1; ip <= np; ip++)
    { vmk = 0 + $(icmk[ip]); # Value of marker channel for phase {ip}.
      if (vmk > 0)
        { # Frame belongs to phase {ip}:
          nt_p[ip]++; # One more frame in phase.
          if (up[ip] == 0) 
            { # Start of phase {ip}.
              if (ns_p[ip] > 0) { data_error(("phase " ip " occurs more than once in run")); }
              it_ini_p[ip] = it;
              ns_p[ip]++;
            }
          it_fin_p[ip] = it;
          for (ie = 1; ie <= ne; ie++)
            { ve = 0 + $(ie); # Value of electrode {ie}.
              if (ve < vmin_pe[ip,ie]) { vmin_pe[ip,ie] = ve; }
              if (ve > vmax_pe[ip,ie]) { vmax_pe[ip,ie] = ve; }
              vsum_pe[ip,ie] += ve;
            }
          up[ip] = 1;
          if (prev_ip > 0) { data_error(("phases " prev_ip " and " ip " both on")); }
          prev_ip = ip;
        }
    }
  nframes ++;
  next;
}

// { 
  data_error(("invalid line format"));
}

END {
  if (abort >= 0) { exit(abort); }
  printf "%d frames read\n", nframes > "/dev/stderr";
  for (ip = 1; ip <= np; ip++)
    { printf "phase %s :", phname[ip];
      if (ns_p[ip] == 0) { data_error(("phase " ip " does not occur in run")); }
      printf " spans %d frames %6d .. %6d", nt_p[ip], it_ini_p[ip], it_fin_p[ip];
      printf "\n";
    }
      
  for (ie = 1; ie <= ne; ie++)
    { printf "electrode %3d :", ie;
      for (ip = 1; ip <= np; ip++)
        { printf "  %s ", phname[ip];
          printf " range  %+9.2f _ %+9.2f ", vmin_pe[ip,ie], vmax_pe[ip,ie]
          printf " del %9.2f ", vmax_pe[ip,ie] - vmin_pe[ip,ie] ;;
          printf " avg %+9.2f", vsum_pe[ip,ie]/nt_p[ip];
        }
      printf "\n";
    }
}

function arg_error(msg) {
  printf "** %s\n", msg > "/dev/stderr";
  abort = 1;
  exit(1);
}

function prog_error(msg) {
  printf "%s:%d: ** prog error: %s\n", FILENAME, FNR, msg > "/dev/stderr";
  abort = 1;
  exit(1);
}

function data_error(msg) {
  printf "  «%s»\n", $0 > "/dev/stderr";
  printf "%s:%d: ** %s\n", FILENAME, FNR, msg > "/dev/stderr";
  abort = 1;
  exit(1);
}