package nxm.sys.prim;

import nxm.sys.lib.BaseFile;
import nxm.sys.lib.Data;
import nxm.sys.lib.DataFile;
import nxm.sys.lib.Primitive;
import nxm.sys.libm.MMath;
import nxm.sys.libm.Subtract;

/**
  Fits a polynomial to series of data frames (or just 1)

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

  DataFile hi,ho,hf,he;
  Data dbi,dbo,dbf,dbe;
  int order,ndata;
  String label;
  double xs,xd;

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

  public int open() {

    hi = MA.getDataFile ("IN","1000,2000","S#",0);
    hi.open();
    xs = hi.getXStart();
    xd = hi.getXDelta();

    order = MA.getL("ORDER");
    label = MA.getU("COEF");

    ho = MA.getDataFile ("OUT","2000","SD",0);
    ho.setSubSize(order+1);
    ho.setInternals();
    ho.open(BaseFile.OUTPUT|BaseFile.OPTIONAL);

    hf = MA.getDataFile ("FIT",hi,0);
    hf.open(BaseFile.OUTPUT|BaseFile.OPTIONAL);

    he = MA.getDataFile ("ERR",hi,0);
    he.open(BaseFile.OUTPUT|BaseFile.OPTIONAL);


    if (hi.typeClass==1) {
      ndata = (int)hi.getSize();
      hi.setDFS(ndata);
      hf.setDFS(ndata);
      he.setDFS(ndata);
    } else {
      ndata = hi.getSubSize();
    }

    dbi = hi.getDataBuffer(1,Data.DOUBLE);
    dbo = ho.getDataBuffer(1,Data.DOUBLE);
    dbf = hf.getDataBuffer(1,Data.DOUBLE);
    dbe = he.getDataBuffer(1,Data.DOUBLE);

    return NORMAL;
  }

  public int process() {

    int n = hi.read(dbi);
    if (n==0) return NOOP;
    if (n<0) return FINISH;

    double[] vi,vo,vf,ve;
    vi = dbi.castD(true);
    vo = dbo.castD(false);
    vf = dbf.castD(false);
    ve = dbe.castD(false);

    MMath.leastSquaresFit(vo,order, vi,ndata, 0,ndata);
    MMath.leastSquaresEval(vo,order, vf,ndata);
    MMath.deNormalizeCoef(vo,order, xs,xd, ndata);
    Subtract.SSS(vi,vf,ve,ndata);

    dbi.uncast(vi,false);
    dbo.uncast(vo,true); ho.write(dbo);
    dbf.uncast(vf,true); hf.write(dbf);
    dbe.uncast(ve,true); he.write(dbe);

    return NORMAL;
  }

  public int close() {
    if (!ho.isOpen && !hf.isOpen && !he.isOpen
       && label.length()==0) M.info("Coef = "+dbo);
    MR.put(label,dbo);
    hi.close();
    ho.close();
    hf.close();
    he.close();
    return NORMAL;
  }

}
