package nxm.dsp.prim;

import nxm.sys.inc.ProvisionalUseOnly;
import nxm.sys.lib.Data;
import nxm.sys.lib.DataFile;
import nxm.sys.lib.Primitive;

/** A class to upsample (i.e. zero pad) data.  The upsample factor needs
 *  to be an integer.  This class is primarily for educational and testing purposes,
 *  as NEWRATE encompasses this functionality and more providing arbitrary resampling.
 *  @author Jeanette McCall
 *  @since NeXtMidas 3.9.1
 */
@ProvisionalUseOnly("This was created for educational purposes and has been minimally tested")
public class upsample extends Primitive {
  private DataFile inFile;              // The input file
  private DataFile outFile;             // The output file
  private Data     dataBuffer;          // The data buffer holding input data
  private Data     outBuffer;           // The data buffer holding output data
  private int      factor;              // the upsampling factor (output samples to input samples ratio)
  private float    fillValue;           // fill value

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

  @Override
  public int open() {
    inFile = MA.getDataFile("IN", "1000", "S#", 0); // only allow type 1000 files
    inFile.open();
    double inXDelta = inFile.getXDelta();

    factor = MA.getL("FACTOR",1);

    fillValue = MA.getF("FILLVALUE",0);

    outFile = MA.getDataFile("OUT", inFile, 0);
    outFile.open();
    outFile.setXDelta(inXDelta/factor); // output sampling rate is factor * input sampling rate

    int xfer = MA.getL("/TL", 1024);
    dataBuffer = inFile.getDataBuffer(xfer,Data.DOUBLE);
    outBuffer = outFile.getDataBuffer(xfer*factor,Data.DOUBLE);

    return NORMAL;
  }

  @Override
  public int process() {
    int status  = NORMAL;
    int numRead = inFile.read(dataBuffer);

    if (numRead < 0) {
      status = FINISH; // End of file
    } else if (numRead == 0) {
      status = NOOP;   // No data available, wait for pipe.
    } else {
      int numOutput = upSample(numRead);
      if (numOutput > 0) outFile.write(outBuffer,numOutput);
    }

    return status;
  }

  /** upsample (zero pad) the data by the specified factor*/
  private int upSample (int numRead) {
    float[] fbuf = dataBuffer.castF(true);
    float[] outBuf = outBuffer.castF(false);
    int numOutput = numRead*factor;

    for (int i = 0; i < numRead; i++) {
      int outIndex = i*factor;
      outBuf[outIndex] = fbuf[i];
      for (int z = 01; z < factor; z++) {
        outBuf[outIndex+z] = fillValue;
      }
    }

    // ready to put values in dataBuffer
    outBuffer.uncast(outBuf, true);
    return numOutput;
  }

  @Override
  public int close() {
    inFile.close();
    outFile.close();

    return NORMAL;
  }
}
