import java.awt.Color;
import java.awt.Component;
import java.awt.Image;

import java.awt.image.ImageObserver;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;

class      Raster 
implements ImageObserver 
{
    protected int     width;
    protected int     height;
    protected int     pixel[];
    private   boolean available;  // for indicating image download status




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


    /**
     *  This constructor creates an uninitialized
     *  Raster Object of a given size (w x h).
     */
    public Raster( int w, int h )
    {
        width  = w;
        height = h;
        pixel  = new int[w*h];
    }


    /**
     *  This constructor creates an Raster initialized
     *  with the contents of an image.
     */
    public Raster( Image img )
    {
        width  = img.getWidth( this );
        height = img.getHeight( this );

        try {
            if ( ( width < 0 ) || ( height < 0 ) ) {
                available = false;
                while (!available) {
                    Thread.sleep((long) 100);
                    System.out.println( "Sleeping for image" );
                }
             }
            
          pixel = new int[width*height];
          
          PixelGrabber grabber = new PixelGrabber( img,
                                                     0,
                                                   0,
                                                   width,
                                                   height,
                                                   pixel,
                                                   0,
                                                   width);
          grabber.grabPixels();
        } catch ( InterruptedException e ) {
          width  = 0;
          height = 0;
          pixel  = null;
          return;
        }
    }

    public boolean 
    imageUpdate( Image img, int flags, int x, int y, int w, int h )
    {
        if ( (flags & WIDTH)  != 0) width  = w;
        if ( (flags & HEIGHT) != 0) height = h;
        available = ( (width >= 0) && (height >= 0) );
        return !available;
    }


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

    /**
     *  Returns the number of pixels in the Raster
     */
    public int getSize() 
    {
        return pixel.length;
    }

    /**
     *  Returns the number of pixels in the Raster
     */
    public int getWidth() 
    {
        return width;
    }

    /**
     *  Returns the number of pixels in the Raster
     */
    public int getHeight() 
    {
        return height;
    }

    public int[] 
    getPixelBuffer() 
    {
        return pixel;
    }

    /**
     *  Fills a Raster with a solid color
     */
    public void 
    fill( int argb )
    {
        int s = pixel.length;
        for (int i = 0; i < s; i++) {
            pixel[i] = argb;
        }
    }


    public void 
    fill( Color c ) 
    {
        fill(c.getRGB());
    }


    /**
     *  Converts Rasters to Images
     */
    public Image 
    toImage( Component root )
    {
        return root.createImage( new MemoryImageSource( width, 
                                                          height, 
                                                        pixel, 
                                                        0, 
                                                        width) );
    }


    /**
     * The following helper routine
     * test that x and y are valid
     */
    private final boolean 
    invalid( int x, int y ) 
    {
        return ( ( x < 0       ) ||
                 ( x >= width  ) || 
                 ( y < 0       ) ||  
                 ( y >= height ) );
    }

    /**
     *  Get a pixel from a Raster
     */
    public int 
    getPixel( int x, int y )
    {
        if ( invalid( x, y ) )
            return 0;
        else
            return pixel[y*width+x];
    }

    /**
     *  Get a color from a Raster
     */
    public Color 
    getColor( int x, int y ) 
    {
        return new Color( getPixel(x,y) );
    }

    /**
     *  Set a pixel to a given value
     */
    public boolean 
    setPixel( int pix, int x, int y ) 
    {
        if ( invalid( x, y ) ) {
            return false;
        } else {
            pixel[y*width+x] = pix;
            return true;
        }
    }


    /**
     *  Set a pixel to a given color
     */
    public boolean 
    setColor( Color c, int x, int y )
    {
        return setPixel( c.getRGB(), x, y );
    }
}
