package nxm.sys.prim;

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

/**
  Evaluate a polynomial on a range of integers.

  @author Scott Fernandez
  @since NeXtMidas 2.9.3
 */
public class polyeval extends Primitive {

  DataFile outFile;
  Data coefs, outData;
  double[] coefficients, outArray;
  /** number of elements to output */
  int ndata;

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

  public int open () {

    String format = MA.getS("FORMAT", "SD");
    double start  = MA.getD("START", 0.0);
    double delta  = MA.getD("DELTA", 1.0);
    int    units  = MA.getL("UNITS", Units.NONE);

    ndata = MA.getL("NDATA", 1024);
    coefs = MA.getData("COEF");
    MA.testFormat(coefs.getFormat(), "S#");

    outFile = MA.getDataFile("OUT", "1000", format, DataFile.OUTPUT);
    outFile.setStart(start);
    outFile.setDelta(delta);
    outFile.setUnits(units);
    outFile.open();
    outData = outFile.getDataBuffer(ndata);

    return NORMAL;
  }

  public int process () {

    coefficients = coefs.castD(true);
    outArray = outData.castD(false);

    evaluate(coefficients, outArray, 0, ndata);

    coefs.uncast(coefficients,false);
    outData.uncast(outArray,true);
    outFile.write(outData);

    return FINISH;
  }

  /** Evaluates a polynomial with the given coefficients at integers up to the given value.
      @param coefficients Array of coefficients for the polynomial being evaluated (cannot be null)
      @param outArray Array to write to (must be large enough to hold end-start entries).
      @param start Where to start evaluating from
      @param end   Where to end
   */
  protected void evaluate (double[] coefficients, double[] outArray, int start, int end) {
    int order = coefficients.length - 1;
    for (int i = start; i < end; i++) {
      double sum = 0;
      double xpow = 1;
      for (int j = 0; j <= order; j++) {
        sum += coefficients[j]*xpow;
        xpow *= i;
      }
      outArray[i] = sum;
    }
  }

  public int close () {
    outFile.close();
    return NORMAL;
  }

}
