package nxm.sys.libg;

import nxm.sys.lib.MidasException;

/** A class to support scatter plots. This is effectively a ground-up rewrite
    of {@link LayerXY} that better supports other file types. {@link LayerXY}
    has minimal support for non-Type 3000 files, and cannot deal with numbers
    as strings. This class borrows heavily from {@link LayerMulti}, on which
    it is based.

    @author  J. Czechowski IV
    @since   NeXtMidas 3.1.1
 */
public class LayerScatter extends LayerMulti {
  protected int X = -1;
  protected int Y = -1;

  /** Constructor */
  public LayerScatter () {
    super("Scatter");
    setTraces("|X|Y|");
    line.setColor(MColor.getColorByIndex(1));
  }

  /** Set X-record name
   *  @param value the X-record name */
  public void setX (String value) {
    setTraces("|"+value+"|"+getY()+"|");
    if (MP!=null) MP.setXAxisLabel(value);  // added in 3.5.0 for Bug 2795
  }

  /** Set Y record name
   *  @param value the Y record name */
  public void setY (String value) {
    setTraces("|"+getX()+"|"+value+"|");
    if (MP!=null) MP.setYAxisLabel(value);   // added in 3.5.0 for Bug 2795
  }

  /** Get X record name
   *  @return the X record name */
  public String getX () {
    String traces = getTraces();    // in "|X|Y|" form
    int    idx    = traces.indexOf('|',1);
    return traces.substring(1, idx);
  }

  /** Get Y record name
   *  @return the Y record name */
  public String getY () {
    String traces = getTraces();    // in "|X|Y|" form
    int    idx    = traces.indexOf('|',1);
    return traces.substring(idx+1, traces.length()-1);
  }

  @Override
  public void setTraces (String traces) {
    if ((traces==null) || traces.equals("*")) {
      super.setTraces("|X|Y|");
    }
    else {
      if (!traces.startsWith("|")) traces = "|"+traces;
      if (!traces.endsWith("|"))   traces = traces + "|";
      int i = traces.indexOf('|',1);
      int j = traces.lastIndexOf('|', traces.length()-2);
      if (i<0 || i!=j) {
        throw new MidasException("Illegal column/trace specification for scatter plot '"+traces+"'. Expected form of '|X|Y|'");
      }
      super.setTraces(traces);
    }
  }

  @Override
  protected void updateRecData (double[][] dbuf, int size) {
    String xName = getX();
    String yName = getY();

    X = -1;
    Y = -1;
    for (int col=0; col<dbuf.length; col++) {
      if (!show(col)) {
        dbuf[col] = null;   // clear out buf for records that are not selected to be shown
      } else if (dbuf[col] == null) {
        dbuf[col] = new double[size];
      } else if (dbuf[col].length != size) {
        // JC4: we might consider keeping the data when possible
        dbuf[col] = new double[size];
      }

      if (X<0 && xName.equals(recNames[col])) X = col;
      if (Y<0 && yName.equals(recNames[col])) Y = col;
    }

    if (X<0 && Y<0) {
      warning("Could not find column X='" + xName + "' or Y='" + yName + "'");
      X = 0;
      Y = 0;
      dbuf[0] = new double[size];
    }
    else if (X<0) {
      warning("Could not find column X='" + xName + "'");
      X = Y;
    }
    else if (Y<0) {
      warning("Could not find column Y='" + yName + "'");
      Y = X;
    }
  }

  @Override
  public void findRange () {
    super.findRange();
    int npts = (ndata>size && realtime)? size : ndata; // adjust number of points for realtime mode

    if (npts < 1) {
      // Defaults from Layer.java
      x1 = 0; x2 = 1;
      y1 = 0; y2 = 1;
    }
    else if (npts == 1) {
      // Special case of just a single point in the file
      x1 = recData[X][0] - 0.5;
      x2 = recData[X][0] + 0.5;
      y1 = recData[Y][0] - 0.5;
      y2 = recData[Y][0] + 0.5;
    }
    else {
      x1 = recData[X][0];
      x2 = recData[X][0];
      y1 = recData[Y][0];
      y2 = recData[Y][0];

      for (int i=1; i<npts; i++) {
        x1 = Math.min(x1, recData[X][i]);
        x2 = Math.max(x2, recData[X][i]);
        y1 = Math.min(y1, recData[Y][i]);
        y2 = Math.max(y2, recData[Y][i]);
      }
    }

    // Based on Layer.java
    z1 = 0;  z2 = 1;
    a1 = y1; a2 = y2;
  }

  @Override
  public void draw (int flag) {
    if (!lock()) return;
    try {
      // taken from Layer.java
      clearNeedRefresh();
      isReset = false;
      // loosely based on LayerXY.java
      Line lin = line.copy();
      int npts = (ndata>size && realtime)? size : ndata;  // adjust number of points for realtime mode
      int i1 = 0;
      int i2 = npts;
      int i21;

      if (size>0) i2=frame;

      i21 = i2-i1;
      if (i21<=0) return;

      double[] dbuf = new double[npts*2];
      for (int i=0, j=0; i<npts; i++,j+=2) {
        dbuf[j]   = recData[X][i];
        dbuf[j+1] = recData[Y][i];
      }
      MP.drawLine(dbuf,0,2,ndata,lin,Pix.NEVERCLIP,false);  // since 3.9.1 never clip as it causes issues with cities
      frameDrawn = true;
    } finally {
      unlock();
    }
  }


}