package nxm.dsp.prim;

import nxm.sys.inc.Chainable;
import nxm.sys.lib.BaseFile;
import nxm.sys.lib.Data;
import nxm.sys.lib.DataFile;
import nxm.sys.lib.MPULib;
import nxm.sys.lib.Parser;
import nxm.sys.lib.Primitive;

/**
  Implements various demodulators on a complex baseband input.

  This primitive has multiple algorithms: Standard and LookUpTable.
  This primitive has multiple implementations: Java, Native-C, and FPGA

  @author Jeff Schoen
*/
public class demod extends Primitive implements Chainable {

  /** list of currently supported modulation types */
  public String modeList,algList;

  private int mode,alg,tl=4096;
  private DataFile hi,ho,hlut;
  private Data dbi,dbo;
  private MPULib dm;

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

  public int open() {

    hi = MA.getDataFile ("IN","1000","C#",0);
    hi.open();

    ho = MA.getDataFile ("OUT",hi,0);
    ho.setFormatMode(SCALAR);
    ho.open();

    dm = MPULib.forName("Demod",MA);

    modeList = dm.getS("MODULATIONS");
    mode = MA.getChoice("MODE",modeList,0);
    dm.set("MODULATION",mode);

    hlut = MA.getDataFile ("/LUT","2000","SI",0);
    hlut.open(BaseFile.OPTIONAL);
    boolean lut = hlut.isOpen();
    if (lut) {
      int nlut = (int)hlut.size;
      int flags = hlut.keywords.getL("FLAGS",0);
      Data dlut = hlut.getDataBuffer(nlut);
      hlut.read(dlut);
      dm.set("LUT",dlut);
      dm.set("LUTFLAGS",flags);
      hlut.close();
    }
    else {
      algList = dm.getS("ALGORITHMS");
      alg = MA.getChoice("/ALG",algList,0);
      dm.set("ALGORITHM",alg);
      lut = (alg>1);
    }

    double fullScale =  1.0;
         if (ho.getFormatType()==INT) fullScale = 65536.0;
    else if (ho.getFormatType()==LONG) fullScale = 4294967296.0;
    if (MA.getState("/FREQOUT")) {
      if (hi.getFormatType()==FLOAT || hi.getFormatType()==DOUBLE) fullScale *= 1.0/hi.getXDelta();
      else M.warning("Can not use frequency scale for non-Float data types");
    }
    dm.set("FULLSCALE",fullScale);
    dm.open();

    tl = MA.getL("/TL", tl);
    byte dtype = lut? INT : FLOAT;
    dbi = hi.getDataBuffer(tl,dtype);
    dbo = ho.getDataBuffer(tl,dtype);

    return NORMAL;
  }

  public int process() {
    int n = hi.read(dbi);
    if (n<0) return FINISH;
    n = dm.process (dbi.buf,n, dbo.buf,tl);
    ho.write(dbo,n);
    return NORMAL;
  }

  public int close() {
    dm.close();
    hi.close();
    ho.close();
    return NORMAL;
  }

  /** Set the new demodulation mode
   *  @param value the new demodulation mode
   */
  public void setMode (String value) {
    setMode ( Parser.find(modeList,value,mode) );
  }
  /** Get the current demodulation mode
   *  @return the current demodulation mode
   */
  public String getMode () {
    return Parser.get(modeList,mode);
  }
  private void setMode (int mode) {
    this.mode = mode;
    dm.set("MODULATION",mode);
  }

  public Object getNextLink() { return dm; }
  public Object getPrevLink() { return null; }

}
