import java.awt.*;
import java.awt.image.*;
import java.lang.*;
import java.applet.*;

class Raster {
    protected int width, height, depth;
    private int pixelBack[];
    private Color colorBack;
    private float curDepthBack[]; 
    public int pixel[];
    public float curDepth[];
    private Toolkit tk;
    //private int back[];
	 private MemoryImageSource source = null;

    ///////////////////////// Constructors //////////////////////

    /**
     *  This constructor which takes no arguments
     *  allows for future extension.
     */
    public Raster()
    {
    }

	public Raster(int w, int h)
	{
      width = w;
      height = h;
		depth = 2 << 14;
      pixel = new int[w*h];
      curDepth = new float[w*h];
      pixelBack = new int[w*h];
      curDepthBack = new float[w*h];
      tk = Toolkit.getDefaultToolkit();
      
		source = new MemoryImageSource(width, height, pixel, 0, width);
			setAnimated(false);
			fullUpdates(false);		
		initDepth();
		colorBack = null;
		fill(Color.white);
		//clearDepth();
	}

    /**
     *  This constructor creates an Raster initialized
     *  with the contents of an image.
     */
	public Raster(Image img)
	{
	
		if (img == null)
		{
			System.err.println("Raster constructed with null image.\n");
		}
      tk = Toolkit.getDefaultToolkit();

      depth = 2<<14;
		try 
		{
			PixelGrabber grabber = new PixelGrabber(img, 0, 0, -1, -1, true);
			if (grabber.grabPixels()) {
				width = grabber.getWidth();
				height = grabber.getHeight();
				pixel = (int []) grabber.getPixels();
			} else
			{
				System.err.println("Raster constructor failed in PixelGrabber.\n");
			}
		} catch (InterruptedException e) {}
		source = new MemoryImageSource(width, height, pixel, 0, width);
			setAnimated(false);
			fullUpdates(false);
			
		curDepth = new float[width*height];
		curDepthBack = new float[width*height];
		initDepth();
		clearDepth();
	}


    ////////////////////////// Methods //////////////////////////

	protected void setAnimated(boolean isAnimated)
	{
		source.setAnimated(isAnimated);
	}

	protected void fullUpdates(boolean updateAll)
	{
		source.setFullBufferUpdates(updateAll);
	}
	
	protected void setPixels(int[] newpix)
	{
		pixel = newpix;
		source.newPixels(newpix, ColorModel.getRGBdefault(), 0, width);		
	}
	

	private void initDepth()
	{
		for (int i = 0; i < curDepthBack.length; i++)
		{
			curDepthBack[i] = depth;
		}
		return;
	}
	
	
	public void clearDepth()
	{
		System.arraycopy(curDepthBack, 0, curDepth, 0, curDepth.length);
	}
	
	
    /**
     *  Returns the number of pixels in the Raster
     */
    public int size( ) {
        return pixel.length;
    }
    
    /**
     *  Access instance variables
     */
    public int getWidth() {
        return width;
    }
    
    public int getHeight() {
        return height;
    }

    public int getDepth() {
    		return depth;
    }
    
    public int [] getPixels() {
        return pixel;
    }

    /**
     *  Fills a Raster with a solid color
     */
    public void fill(Color c) {
        if (!c.equals(colorBack))
        {
	        int rgb = c.getRGB();
  		      for (int i = 0; i < pixelBack.length; i++)
  		          pixelBack[i] = rgb;
  		      colorBack = c;
  		  }
			clearDepth();
			System.arraycopy(pixelBack, 0, pixel, 0, pixel.length);
		//source.newPixels(x, y, w-x+1, h-y+1, false);
    }

    /**
     *  Converts Rasters to Images
     */
    public Image toImage() {
        //Toolkit toolkit = Toolkit.getDefaultToolkit();
        //Image img = toolkit.createImage(new MemoryImageSource(width, height, pixel, 0, width));
        //return img;
        
        return tk.createImage(source);
    }
    
	public synchronized void updateImage() 
	{
		source.newPixels();
	}

	public synchronized void updateImage(int x, int y, int w, int h) 
	{
		source.newPixels(x, y, w, h);
	}

    /**
     *  Gets a pixel from a Raster
     */
    public int getPixel(int x, int y) {
		try {
        int res = pixel[y*width+x];
        return res;
		} catch (ArrayIndexOutOfBoundsException e)
		{
			//System.out.println("Invalid pixel get: " + x + ", " + y);
			return -1;
		}
    }


    public float getDepth(int x, int y) {
		try {
        float res = curDepth[y*width+x];
        return res;
		} catch (ArrayIndexOutOfBoundsException e)
		{
			//System.out.println("Invalid pixel get: " + x + ", " + y);
			return -1;
		}
    }


    /**
     *  Gets a color from a Raster
     */
    public Color getColor(int x, int y) {
		try {
        return new Color(pixel[y*width+x]);
		} catch (ArrayIndexOutOfBoundsException e)
		{
			return null;
		}
    }

    /**
     *  Sets a pixel to a given value
     */
    public boolean setPixel(int pix, int x, int y) {
		try {
        pixel[y*width+x] = pix;
        return true;
		} catch (ArrayIndexOutOfBoundsException e)
		{
			System.out.println("Invalid pixel set: " + x + ", " + y);
			return false;
		}
    }

    public boolean setPixel(int pix, int x, int y, float z) {
		try {
		  if (curDepth[y*width+x] < z) return false;
        //if (curDepth[y*width+x] != depth)
        //{
        //	 System.out.println("Overwriting ("+ x +", "+ y +", "+ curDepth[y*width+x]
        //	 	+"): color 0x"+ Integer.toHexString(pixel[y*width+x]) +"  with z = "+
        //	 	z +", color 0x"+ Integer.toHexString(pix));
        //}
        pixel[y*width+x] = pix;
			curDepth[y*width+x] = z;
        return true;
		} catch (ArrayIndexOutOfBoundsException e)
		{
			//System.out.println("Invalid pixel set: " + x + ", " + y);
			return false;
		}
    }

    /**
     *  Sets a pixel to a given color
     */
    public boolean setColor(Color c, int x, int y) {
		try {
        pixel[y*width+x] = c.getRGB();
        return true;
		} catch (ArrayIndexOutOfBoundsException e)
		{
			return false;
		}
    }

    public boolean setColor(Color c, int x, int y, float z) {
		try {
		  if (curDepth[y*width+x] < z) return false;
        pixel[y*width+x] = c.getRGB();
			curDepth[y*width+x] = z;
        return true;
		} catch (ArrayIndexOutOfBoundsException e)
		{
			return false;
		}
    }

}