package nxm.dsp.prim;

import nxm.sys.inc.Constants;
import nxm.sys.lib.BaseFile;
import nxm.sys.lib.Data;
import nxm.sys.lib.DataFile;
import nxm.sys.lib.DataOp;
import nxm.sys.lib.Primitive;

/**
  Creates HILBERT transform impulse response

  @author Jeff Schoen
*/
public class firhlbrt extends Primitive {

  private DataFile ho;
  private Data dbo,dbw;
  private int ntap,nhlf,tl;
  private double scale;
  private String wname;

  /** default constructor */
  public firhlbrt () {}

  public int open() {

    // get number of taps
    tl = MA.getL("/TL",Constants.B1M);
    ntap = MA.getL("NTAP");
    if (ntap<3 || ntap>tl)
      M.error("Number taps="+ntap+" out of range [3,"+tl+"]");
    if (ntap%2==0) {
      ntap -= 1;
      M.warning("Number taps reduced by one to an odd value="+ntap);
    }
    nhlf = ntap/2;

    wname = MA.getS("WIND");
    if (wname.startsWith("Y")) wname = "HANN";   // YES = HANN
    scale = MA.getD("/SCALE",1.0);

    // Open output file
    ho = MA.getDataFile("OUT","1000","SF",0);
    ho.setSize (ntap);
    ho.setXStart (-nhlf);
    ho.open(BaseFile.OUTPUT);

    // get data buffers
    dbo = ho.getDataBuffer(ntap,FLOAT);
    float[] fbo = dbo.castF(false);
    // the -ntap creates a symmetric window
    dbw = DataOp.getWindow(wname,-ntap,scale,M);
    float[] fbw = dbw.castF(true);

    // generate HILBERT taps
    generate (ntap,fbw,fbo);

    // write data buffers
    dbw.uncast(fbw,false);
    dbo.uncast(fbo,true);
    ho.write (dbo,ntap);
    ho.close();

    return FINISH;
  }

  /** generate HILBERT taps
   *  @param ntap number of taps
   *  @param wind window to apply, YES (= apply Hanning), or NONE
   *  @param filt buffer for filter result
   */
  public static void generate (int ntap, float[] wind, float[] filt) {
    int nhlf = ntap/2;
    float c = (float)(2/Constants.PI);

    // initialize bins
    for (int i=0; i<ntap; i++) filt[i] = wind[i];

    // populate odd bins
    for (int i=1; i<=nhlf; i+=2) {
      float s = c/i;
      filt[nhlf+i] = s*filt[nhlf+i];
      filt[nhlf-i] = -filt[nhlf+i];
    }
    // populate even bins
    for (int i=0; i<=nhlf; i+=2) {
      filt[nhlf+i] = 0;
      filt[nhlf-i] = 0;
    }
  }

}
