package nxm.sys.libg;

import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.LookupOp;
import java.awt.image.ShortLookupTable;

import nxm.sys.inc.PlotFile;
import nxm.sys.lib.Args;
import nxm.sys.lib.ImageFile;
import nxm.sys.lib.Table;
import nxm.sys.prim.plot;

/**
  A class to hold and plot an image.

  @author Jeff Schoen
*/
public class LayerImage extends Layer {

  BufferedImage bi;

  /** Constructor */
  public LayerImage () {
    super("Image");
    typeClass = 7;
  }

  @Override
  protected void init (plot p, String layerName, int layerIndex, Layer oldLayer) { // since 3.3.2
    super.init(p, layerName, layerIndex, oldLayer);
    if ((MP.initValues&MPlot.I_AXIS) != MPlot.I_AXIS) MP.setAxis("FRAME");  // Bug 467
    p.setImageFlag(true);                                                   // Bug 467
  }

  @Override
  public boolean setFile (PlotFile pf, Table tab, Args MA) {
    setFile(pf);
    ImageFile imf = (ImageFile)pf;
    bi = imf.readImage();
    size = imf.getYFrame();
    frame = imf.getXFrame();
    xstart = imf.getXStart();
    xdelta = imf.getXDelta();
    ystart = imf.getYStart();
    ydelta = imf.getYDelta();
    return true;
  }

  @Override
  public void process () {
    // TODO: Why is this here??? We probably want the default implementation from Layer
  }

  @Override
  public void findRange () {
    // Set Minimum and Maximum axis values
    x1 = xstart - xdelta/2;
    x2 = x1 + frame*xdelta;
    if (x1>x2) { double t=x1; x1=x2; x2=t; }
    y1 = ystart - ydelta/2;
    y2 = y1 + size*ydelta;
    if (y1>y2) { double t=y1; y1=y2; y2=t; }
    z1 = 0; z2 = 1;
    // Set Minimum and Maximum actual auto-scale value (since 3.7.0 for NXM-2984)
    a1 = y1;
    a2 = y2;
  }

  @Override
  public void findFullRange () {
    // this differs from Layer.findFullRange(PlotFile) in that the frame size is used to determine fx2 (since 3.3.3 - Bug 2748)
    fx1 = x1; fx2 = x2;
    fy1 = y1; fy2 = y2;
    fz1 = z1; fz2 = z2;
    if (pf!=null && !realtime) {
      fx1 = pf.getXStart();
      fx2 = fx1 + (frame)*pf.getXDelta();
      if (fx1>fx2) { double t=fx1; fx1=fx2; fx2=t; }
    }
  }

  @Override
  public void draw (int flag) {
    super.draw(flag);
    // moved into MPlot class to be shared by LayerGMap and LayerMToc
    MP.drawImage (bi,null,false, xstart,xdelta,frame, ystart,ydelta,size);
  }

  /** Gets the buffered image
      @return buffered image
   */
  public BufferedImage getBufferedImage () { return bi; }

  @Override
  public void invertColorMap () {
    short[] invert = new short[256];
    for (int ii = 0; ii < 256; ii++) { invert[ii] = (short)(255 - ii); }
    BufferedImageOp invertOp = new LookupOp(new ShortLookupTable(0, invert), null);
    invertOp.filter(bi, bi); // apply color inversion directly back onto BufferedImage
    refresh();
  }

  /** Utility method to return a new Layer.
   *  @return the new {@link LayerImage}
   *  @since NeXtMidas 3.9.2
   */
  public static Layer getLayer () {
    return new LayerImage();
  }

}
