import java.awt.Image;

public class Layer extends Raster
{
  private int m_x;
  private int m_y;
  private int m_scale;

  /*
   *  Creates a parallax layer from the specified Image object.
   */ 
  public Layer(Image image)
  {
    super(image);
    m_x = 0;
    m_y = 0;
    m_scale = 1;
  }

  /*
   *  Draws this Layer to the specified Raster object.
   *  If transparent is false, does not test for transparent
   *  pixels, yielding greater efficiency.  
   */
  public void draw(Raster raster, boolean transparent)
  {
    if (transparent) draw(raster);
    else
      {
	int x;
	int y;
	int height;
	int width;
	int pixel;
	int[] pixels;
	int[] rasterPixels;
	int rasterHeight;
	int rasterWidth;
	
	
	x             = m_x;                  // The x-offset of the layer
	y             = m_y;                  // The y-offset of the layer
	height        = this.getHeight();     // The height of this layer
	width         = this.getWidth();      // The width of this layer
	rasterHeight  = raster.getHeight();   // The height of the raster
	rasterWidth   = raster.getWidth();    // The width of the raster
	pixels        = this.getPixels();     // Alias for our pixel array
	rasterPixels  = raster.getPixels();   // Alias for raster's pixel array
	
	//
	// If for some reason the layer's width and height 
	// are less than those of the raster, do not attempt to
	// draw it.  (This feature may be added if necessary)
	//
	if ((width < rasterWidth) ||
	    (height < rasterHeight))
	  {
	    return;  
	  }
	else
	  {
	    int x_offset1, x_offset2;
	    int y_offset1, y_offset2;
	    int x_read, x_write, x_readEnd, x_writeEnd;
	    int y_read, y_write, y_readEnd, y_writeEnd;
	    
	    y_read     = y * width;
	    y_readEnd  = height * width;
	    y_write    = 0;
	    y_writeEnd = rasterWidth * rasterHeight;
	    
	    for (;
		 ((y_read < y_readEnd) && (y_write < y_writeEnd));
		  )
	      {
		x_read     = x;
		x_readEnd  = width;
		x_write    = 0;
		x_writeEnd = rasterWidth;

		for (; 
		     ((x_read < x_readEnd) && (x_write < x_writeEnd));
		      x_read++, x_write++)
		  {
		    pixel = pixels[y_read + x_read];
		    rasterPixels[y_write + x_write] = pixel;
		  }

		x_read     = 0;
		x_readEnd  = rasterWidth - width + x;
		
		for (;
		     ((x_read < x_readEnd) && (x_write < x_writeEnd));
		     x_read++, x_write++)
		  {
		    pixel = pixels[y_read + x_read];
		    rasterPixels[y_write + x_write] = pixel;
		  }
		y_read  += width;
		y_write += rasterWidth;
	      }
				
	    y_read      = 0;
	    y_readEnd   = rasterWidth * (rasterHeight - height + y);

	    for (;
		 (y_read < y_readEnd) && (y_write < y_writeEnd);
		  )
	      {
		x_read     = x;
		x_readEnd  = width;
		x_write    = 0;
		x_writeEnd = rasterWidth;

		for (; 
		     ((x_read < x_readEnd) && (x_write < x_writeEnd));
		      x_read++, x_write++)
		  {
		    pixel = pixels[y_read + x_read];
		    rasterPixels[y_write + x_write] = pixel;
		  }

		x_read     = 0;
		x_readEnd  = rasterWidth - width + x;
		
		for (;
		     ((x_read < x_readEnd) && (x_write < x_writeEnd));
		     x_read++, x_write++)
		  {
		    pixel = pixels[y_read + x_read];
		    rasterPixels[y_write + x_write] = pixel;
		  }
		y_read  += width;
		y_write += rasterWidth;
	      }
	  }
      }
  }	
       
  /*
   *  Draws this Layer to the specified Raster object,
   *  checking for transparent pixels.  If the Layer is guaranteed
   *  not to have transparent pixels, instead call
   *  this.draw(raster, false)  which optimizes for this case
   */
  public void draw(Raster raster)
  {
    int x;
    int y;
    int height;
    int width;
    int pixel;
    int[] pixels;
    int[] rasterPixels;
    int rasterHeight;
    int rasterWidth;
	
	
    x             = m_x;                  // The x-offset of the layer
    y             = m_y;                  // The y-offset of the layer
    height        = this.getHeight();     // The height of this layer
    width         = this.getWidth();      // The width of this layer
    rasterHeight  = raster.getHeight();   // The height of the raster
    rasterWidth   = raster.getWidth();    // The width of the raster
    pixels        = this.getPixels();     // Alias for our array of pixels
    rasterPixels  = raster.getPixels();   // Alias for array of raster pixels
	
    if ((width < rasterWidth) ||
	(height < rasterHeight))
      {
	return;  // Should not happen
      }
    else
      {
	int x_offset1, x_offset2;
	int y_offset1, y_offset2;
	int x_read, x_write, x_readEnd, x_writeEnd;
	int y_read, y_write, y_readEnd, y_writeEnd;
	    
	y_read     = y * width;
	y_readEnd  = height * width;
	y_write    = 0;
	y_writeEnd = rasterWidth * rasterHeight;
	    
	for (;
	     ((y_read < y_readEnd) && (y_write < y_writeEnd));
	      )
	  {
	    x_read     = x;
	    x_readEnd  = width;
	    x_write    = 0;
	    x_writeEnd = rasterWidth;

	    for (; 
		 ((x_read < x_readEnd) && (x_write < x_writeEnd));
		 x_read++, x_write++)
	      {
		pixel = pixels[y_read + x_read];
		if (!Ps1Defs.IsPixelTransparent(pixel))
		  rasterPixels[y_write + x_write] = pixel;
	      }

	    x_read     = 0;
	    x_readEnd  = rasterWidth - width + x;
		
	    for (;
		 ((x_read < x_readEnd) && (x_write < x_writeEnd));
		 x_read++, x_write++)
	      {
		pixel = pixels[y_read + x_read];
		if (!Ps1Defs.IsPixelTransparent(pixel))
		  rasterPixels[y_write + x_write] = pixel;
	      }
	    y_read  += width;
	    y_write += rasterWidth;
	  }
				
	y_read      = 0;
	y_readEnd   = rasterWidth * (rasterHeight - height + y);

	for (;
	     (y_read < y_readEnd) && (y_write < y_writeEnd);
	      )
	  {
	    x_read     = x;
	    x_readEnd  = width;
	    x_write    = 0;
	    x_writeEnd = rasterWidth;

	    for (; 
		 ((x_read < x_readEnd) && (x_write < x_writeEnd));
		 x_read++, x_write++)
	      {
		pixel = pixels[y_read + x_read];
		if (!Ps1Defs.IsPixelTransparent(pixel))
		  rasterPixels[y_write + x_write] = pixel;
	      }

	    x_read     = 0;
	    x_readEnd  = rasterWidth - width + x;
		
	    for (;
		 ((x_read < x_readEnd) && (x_write < x_writeEnd));
		 x_read++, x_write++)
	      {
		pixel = pixels[y_read + x_read];
		if (!Ps1Defs.IsPixelTransparent(pixel))
		  rasterPixels[y_write + x_write] = pixel;
	      }
	    y_read  += width;
	    y_write += rasterWidth;
	  }
      }
  }


  /*
   * Scrolls this parallax layer in the specified direction,
   * at the specified magnitude.  The magnitude of the scroll
   * is scaled by some scale-factor specific to each Layer
   */
  public void scroll(int magnitude, int direction)
  {
    magnitude *= m_scale;

    switch (direction)
      {
      case Ps1Defs.LEFT: m_x -= magnitude; break;
      case Ps1Defs.RIGHT: m_x += magnitude; break;
      case Ps1Defs.UP:  m_y -= magnitude; break;
      case Ps1Defs.DOWN: m_y += magnitude; break;
      case Ps1Defs.UP_LEFT: m_x -= magnitude; m_y -= magnitude; break;
      case Ps1Defs.UP_RIGHT: m_x += magnitude; m_y -= magnitude; break;
      case Ps1Defs.DOWN_LEFT: m_x -= magnitude; m_y += magnitude; break;
      case Ps1Defs.DOWN_RIGHT: m_x += magnitude; m_y += magnitude; break;
      }
    m_x = (m_x + getWidth()) % getWidth();
    m_y = (m_y + getHeight()) % getHeight();
  }

  /*
   * Sets the scale factor which controlls how fast this Layer
   * scrolls.
   */ 
  public void setScale(int scale)
  {
    m_scale = scale;
  }
}






