/* Copyright (C) 2000  Free Software Foundation

   This file is part of libgcj.

This software is copyrighted work licensed under the terms of the
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
details.  */

package java.awt.image;

import java.awt.*;

/**
 * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
 */
public class Raster
{
  protected SampleModel sampleModel;
  protected DataBuffer dataBuffer;
  protected int minX;
  protected int minY;
  protected int width;
  protected int height;
  protected int sampleModelTranslateX;
  protected int sampleModelTranslateY;
  protected int numBands;
  protected int numDataElements;
  protected Raster parent;
  
  protected Raster(SampleModel sampleModel, Point origin)
  {
    this(sampleModel, sampleModel.createDataBuffer(), origin);
  }
  
  protected Raster(SampleModel sampleModel, DataBuffer dataBuffer,
		   Point origin)
  {
    this(sampleModel, dataBuffer,
	 new Rectangle(origin.x, origin.y,
		       sampleModel.getWidth(), sampleModel.getHeight()),
	 origin, null);
  }

  protected Raster(SampleModel sampleModel, DataBuffer dataBuffer,
		   Rectangle aRegion,
		   Point sampleModelTranslate, Raster parent)
  {
    this.sampleModel = sampleModel;
    this.dataBuffer = dataBuffer;
    this.minX = aRegion.x;
    this.minY = aRegion.y;
    this.width = aRegion.width;
    this.height = aRegion.height;
    this.sampleModelTranslateX = sampleModelTranslate.x;
    this.sampleModelTranslateY = sampleModelTranslate.y;
    this.numBands = sampleModel.getNumBands();
    this.numDataElements = sampleModel.getNumDataElements();
    this.parent = parent;
  }
    
  public static WritableRaster createInterleavedRaster(int dataType,
						       int w, int h,
						       int bands, 
						       Point location)
  {
    int[] bandOffsets = new int[bands];
    // TODO: Maybe not generate this every time.
    for (int b=0; b<bands; b++) bandOffsets[b] = b;
    
    int scanlineStride = bands*w;
    return createInterleavedRaster(dataType, w, h, scanlineStride, bands,
				   bandOffsets, location);
  }

  public static WritableRaster createInterleavedRaster(int dataType,
						       int w, int h,
						       int scanlineStride,
						       int pixelStride,
						       int[] bandOffsets,
						       Point location)
  {
    SampleModel sm = new ComponentSampleModel(dataType,
					      w, h,
					      pixelStride,
					      scanlineStride,
					      bandOffsets);
    return createWritableRaster(sm, location);
  }

  public static WritableRaster createBandedRaster(int dataType, 
						  int w, int h, int bands,
						  Point location)
  {
    // FIXME: Implement;
    throw new UnsupportedOperationException("not implemented yet");
  }

  public static WritableRaster createBandedRaster(int dataType,
						  int w, int h,
						  int scanlineStride,
						  int[] bankIndices,
						  int[] bandOffsets,
						  Point location)
  {
    // FIXME: Implement;
    throw new UnsupportedOperationException("not implemented yet");
  }
  
  public static WritableRaster createPackedRaster(int dataType,
						  int w, int h,
						  int[] bandMasks,
						  Point location)
  {
    SampleModel sm = new SinglePixelPackedSampleModel(dataType,
						      w, h,
						      bandMasks);
    return createWritableRaster(sm, location);
  }

  public static WritableRaster
  createInterleavedRaster(DataBuffer dataBuffer, int w, int h,
			  int scanlineStride, int pixelStride,
			  int[] bandOffsets, Point location)
  {
    SampleModel sm = new ComponentSampleModel(dataBuffer.getDataType(),
					      w, h,
					      scanlineStride,
					      pixelStride,
					      bandOffsets);
    return createWritableRaster(sm, dataBuffer, location);
  }

  public static
  WritableRaster createBandedRaster(DataBuffer dataBuffer,
				    int w, int h,
				    int scanlineStride,
				    int[] bankIndices,
				    int[] bandOffsets,
				    Point location)
  {
    // FIXME: Implement;
    throw new UnsupportedOperationException("not implemented yet");
  }
  
  public static WritableRaster
  createPackedRaster(DataBuffer dataBuffer,
		     int w, int h,
		     int scanlineStride,
		     int[] bandMasks,
		     Point location) {
    SampleModel sm =
      new SinglePixelPackedSampleModel(dataBuffer.getDataType(),
				       w, h,
				       scanlineStride,
				       bandMasks);
    return createWritableRaster(sm, dataBuffer, location);
  }
    
  public static Raster createRaster(SampleModel sm, DataBuffer db,
				    Point location)
  {
    return new Raster(sm, db, location);
  }

  public static WritableRaster createWritableRaster(SampleModel sm,
						    Point location)
  {
    return new WritableRaster(sm, location);
  }

  public static WritableRaster createWritableRaster(SampleModel sm,
						    DataBuffer db,
						    Point location)
  {
    return new WritableRaster(sm, db, location);
  }

  public Raster getParent()
  {
    return parent;
  }

  public final int getSampleModelTranslateX()
  {
    return sampleModelTranslateX;
  }

  public final int getSampleModelTranslateY()
  {
    return sampleModelTranslateY;
  }

  public WritableRaster createCompatibleWritableRaster()
  {
    return new WritableRaster(getSampleModel(), new Point(minX, minY));
  }

  public WritableRaster createCompatibleWritableRaster(int w, int h)
  {
    return createCompatibleWritableRaster(minX, minY, w, h);
  }

  public WritableRaster createCompatibleWritableRaster(Rectangle rect)
  {
    return createCompatibleWritableRaster(rect.x, rect.y,
					  rect.width, rect.height);
  }

  public WritableRaster createCompatibleWritableRaster(int x, int y,
						       int w, int h)
  {
    SampleModel sm = getSampleModel().createCompatibleSampleModel(w, h);
    return new WritableRaster(sm, sm.createDataBuffer(),
			      new Point(x, y));
  }

  public Raster createTranslatedChild(int childMinX, int childMinY) {
    int tcx = sampleModelTranslateX - minX + childMinX;
    int tcy = sampleModelTranslateY - minY + childMinY;
    
    return new Raster(sampleModel, dataBuffer,
		      new Rectangle(childMinX, childMinY,
				    width, height),
		      new Point(tcx, tcy),
		      this);
  }

  public Raster createChild(int parentX, int parentY, int width,
			    int height, int childMinX, int childMinY,
			    int[] bandList)
  {
    /* FIXME: Throw RasterFormatException if child bounds extends
       beyond the bounds of this raster. */

    SampleModel sm = (bandList == null) ?
      sampleModel :
      sampleModel.createSubsetSampleModel(bandList);

    /*
        data origin
       /
      +-------------------------
      |\. __ parent trans
      | \`.  
      |  \ `.    parent origin
      |   \  `. /
      |   /\   +-------- - -
      |trans\ /<\-- deltaTrans
      |child +-+-\---- - - 
      |     /|`|  \__ parent [x, y]
      |child | |`. \
      |origin| :  `.\
      |      |    / `\
      |      :   /    +
      | child [x, y] 

      parent_xy - parent_trans = child_xy - child_trans

      child_trans = parent_trans + child_xy - parent_xy
    */

    return new Raster(sm, dataBuffer,
		      new Rectangle(childMinX, childMinY,
				    width, height),
		      new Point(sampleModelTranslateX+childMinX-parentX,
				sampleModelTranslateY+childMinY-parentY),
		      this);
  }

  public Rectangle getBounds()
  {
    return new Rectangle(minX, minY, width, height);
  }

  public final int getMinX()
  {
    return minX;
  }

  public final int getMinY()
  {
    return minY;
  }

  public final int getWidth()
  {
    return width;
  }

  public final int getHeight()
  {
    return height;
  }

  public final int getNumDataElements()
  {
    return numDataElements;
  }
    
  public final int getTransferType()
  {
    return sampleModel.getTransferType();
  }

  public DataBuffer getDataBuffer()
  {
    return dataBuffer;
  }

  public SampleModel getSampleModel()
  {
    return sampleModel;
  }

  public Object getDataElements(int x, int y, Object outData)
  {
    return sampleModel.getDataElements(x-sampleModelTranslateX,
				       y-sampleModelTranslateY,
				       outData, dataBuffer);
  }

  public Object getDataElements(int x, int y, int w, int h,
				Object outData)
  {
    return sampleModel.getDataElements(x-sampleModelTranslateX,
				       y-sampleModelTranslateY,
				       w, h, outData, dataBuffer);
  }

  public int[] getPixel(int x, int y, int[] iArray)
  {
    return sampleModel.getPixel(x-sampleModelTranslateX,
				y-sampleModelTranslateY,
				iArray, dataBuffer);
  }

  public float[] getPixel(int x, int y, float[] fArray)
  {
    return sampleModel.getPixel(x-sampleModelTranslateX,
				y-sampleModelTranslateY,
				fArray, dataBuffer);
  }

  public double[] getPixel(int x, int y, double[] dArray)
  {
    return sampleModel.getPixel(x-sampleModelTranslateX,
				y-sampleModelTranslateY,
				dArray, dataBuffer);
  }

  public int[] getPixels(int x, int y, int w, int h, int[] iArray)
  {
    return sampleModel.getPixels(x-sampleModelTranslateX,
				 y-sampleModelTranslateY,
				 w, h, iArray, dataBuffer);
  }

  public float[] getPixels(int x, int y, int w, int h,
			   float[] fArray)
  {
    return sampleModel.getPixels(x-sampleModelTranslateX,
				 y-sampleModelTranslateY,
				 w, h, fArray, dataBuffer);
  }

  public double[] getPixels(int x, int y, int w, int h,
			    double[] dArray)
  {
    return sampleModel.getPixels(x-sampleModelTranslateX,
				 y-sampleModelTranslateY,
				 w, h, dArray, dataBuffer);
  }

  public int getSample(int x, int y, int b)
  {
    return sampleModel.getSample(x-sampleModelTranslateX,
				 y-sampleModelTranslateY,
				 b, dataBuffer);
  }

  public float getSampleFloat(int x, int y, int b)
  {
    return sampleModel.getSampleFloat(x-sampleModelTranslateX,
				      y-sampleModelTranslateY,
				      b, dataBuffer);
  }

  public double getSampleDouble(int x, int y, int b)
  {
    return sampleModel.getSampleDouble(x-sampleModelTranslateX,
				       y-sampleModelTranslateY,
				       b, dataBuffer);
  }

  public int[] getSamples(int x, int y, int w, int h, int b,
			  int[] iArray)
  {
    return sampleModel.getSamples(x-sampleModelTranslateX,
				  y-sampleModelTranslateY,
				  w, h, b, iArray, dataBuffer);
  }

  public float[] getSamples(int x, int y, int w, int h, int b,
			    float[] fArray)
  {
    return sampleModel.getSamples(x-sampleModelTranslateX,
				  y-sampleModelTranslateY,
				  w, h, b, fArray, dataBuffer);
  }

  public double[] getSamples(int x, int y, int w, int h, int b,
			     double[] dArray)
  {
    return sampleModel.getSamples(x-sampleModelTranslateX,
				  y-sampleModelTranslateY,
				  w, h, b, dArray, dataBuffer);
  }
}