package nxm.sys.libg;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.ColorModel;
import java.awt.image.ImageObserver;
import java.awt.image.MemoryImageSource;

import nxm.sys.lib.MidasException;
import nxm.sys.lib.Shell;

/** A class to handle memory based images.

    @author Jeff Schoen, Neon Ngo
*/
public class MImage extends Object implements ImageObserver {
  /** The image */
  public Image image;
  /** Image ColorModel, see setColors(..) */
  public ColorModel colormodel;
  /** image Source */
  public MemoryImageSource source;
  /** image width */
  public int w;
  /** image height */
  public int h;
  /** MWindow used */
  private MWindow MW;
  /** array of pixels (uses colormodel for colormap) */
  private byte[] buf;
  /** array of pixels (ARGB colors values, no color map) */
  private int[] bufARGB;

  /** Initialize parameters and create image in memory. If rgbBuf is not null, it will be used as
      the pixel data containing ARGB colors to render and buf and colors will be ignored.
      @param MW     the MWindow on which to draw the image
      @param width  the image width
      @param height the image height
      @param buf    array of pixel data. Must also set colors for the colormap to use.
      @param colors The array of colors to use in producing a color model for this image
      @param rgbBuf array of pixel data (containing ARGB color values) for this image (when this is
                    used, buf and rgbBuf should be set to null).
   */
  public MImage (MWindow MW, int width, int height, byte[] buf, Color[] colors, int[] rgbBuf) {
    this.MW=MW; this.w=width; this.h=height;
    if (rgbBuf != null) {
      if ((buf != null) || (colors != null)) {
        throw new MidasException("MImage: When using rgbBuf, need to set buf=null and colors=null, "
                               + "given buf="+buf+" colors="+colors+".");
      }
      this.bufARGB = rgbBuf;
      source = new MemoryImageSource(w,h,rgbBuf,0,w);
    } else {
      this.buf=buf;
      setColors(colors);
      source = new MemoryImageSource(w,h,colormodel,buf,0,w);
    }
    source.setAnimated(true);
    image = MW.panel.createImage(source);
  }

  /** Same as <code>MImage(MW,width,height,buf,colors,null)</code>.
      @param MW     the MWindow on which to draw the image
      @param width  the image width
      @param height the image height
      @param buf    array of pixel data. Must also set colors for the colormap to use.
      @param colors The array of colors to use in producing a color model for this image
   */
  public MImage (MWindow MW, int width, int height, byte[] buf, Color[] colors) {
    this(MW,width,height,buf,colors,null);
  }

  /** Same as <code>MImage(MW,width,height,null,null,buf)</code>.
      @param MW     the MWindow on which to draw the image
      @param width  the image width
      @param height the image height
      @param buf    array of pixel data. Must also set colors for the colormap to use.
   */
  public MImage (MWindow MW, int width, int height, int[] buf) {
    this(MW,width,height,null,null,buf);
  }

  /** Creates a new color model and implements it. Note that when using ARGB colored pixels
      directly, there is no need to set a colormap.
      @param colors An array of colors to create the color model
   */
  public void setColors (Color[] colors) {
    if (bufARGB!=null) {
      Shell.warning("MImage: Can not use MImage.setColors() when rgbBuf is being used.");
      return;
    }
    colormodel = MColor.getColorModel(colors);
    if (source!=null) source.newPixels(buf,colormodel,0,w);
  }

  /** Draws the image on the MWindow graphics panel
      @param dx1 the <I>x</I>-coordinate of the first corner of the destination rectangle.
      @param dy1 the <I>y</I>-coordinate of the first corner of the destination rectangle.
      @param dx2 the <I>x</I>-coordinate of the second corner of the destination rectangle.
      @param dy2 the <I>y</I>-coordinate of the second corner of the destination rectangle.
      @param sx1 the <I>x</I>-coordinate of the first corner of the source rectangle.
      @param sy1 the <I>y</I>-coordinate of the first corner of the source rectangle.
      @param sx2 the <I>x</I>-coordinate of the second corner of the source rectangle.
      @param sy2 the <I>y</I>-coordinate of the second corner of the source rectangle.
      @deprecated in NeXtMidas 3.9.0 to solve graphical timing issues -
                  use {@link #draw(Graphics, int, int, int, int, int, int, int, int)}
   */
  @Deprecated
  public void draw (int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2) {
    draw(MW.g, dx1,dy1,dx2,dy2, sx1,sy1,sx2,sy2);
  }

  /** Draws the image on the MWindow graphics panel
      @param g   the graphics object
      @param dx1 the <I>x</I>-coordinate of the first corner of the destination rectangle.
      @param dy1 the <I>y</I>-coordinate of the first corner of the destination rectangle.
      @param dx2 the <I>x</I>-coordinate of the second corner of the destination rectangle.
      @param dy2 the <I>y</I>-coordinate of the second corner of the destination rectangle.
      @param sx1 the <I>x</I>-coordinate of the first corner of the source rectangle.
      @param sy1 the <I>y</I>-coordinate of the first corner of the source rectangle.
      @param sx2 the <I>x</I>-coordinate of the second corner of the source rectangle.
      @param sy2 the <I>y</I>-coordinate of the second corner of the source rectangle.
    */
  public void draw (Graphics g, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2) {
    g.drawImage(image, dx1,dy1,dx2,dy2, sx1,sy1,sx2,sy2, this);
  }

  public boolean imageUpdate (Image img, int infoflags, int x, int y, int width, int height) {
    return true;
  }
}
