/////////////////////
// Sidney Chang    //
// 6.837 Project 1 //
// TA: Jacob F11   //
// 9/28/98         //
/////////////////////

import java.awt.*;
import java.awt.image.*;

class Sprite extends Raster {

  // Variables

  int x, y;             // current position of sprite on playfield
  int oldX, oldY;       // previous position of sprite on playfield

  int coveredPixels[];  // playfield pixels under sprite (transparent also)

  boolean onField;      // state of sprite (in playfield or not)

  // Constructors 
  public Sprite(Image image) {         // initialize sprite with an image
    // Constructs a Sprite with the image image positioned at the default
    // coordinate (0,0).

    super(image);

    x = 0; y = 0;
    oldX = 0; oldY = 0;
    
    coveredPixels = new int[super.width*super.height];

    onField = false;
  }

  public Sprite(Image image, int xPos, int yPos) {
    // Constructs a Sprite with the image image at (xPos,yPos).

    super(image);

    x = xPos; y = yPos;
    oldX = xPos; oldY = yPos;

    coveredPixels = new int[super.width*super.height];

    onField = false;
  }

  // Methods 
  public void Draw(Raster bgnd) {
    // Draws entire sprite image on given raster taking into account
    // clipping at the edges of the playfield and transparent pixels.

    int drawWidth = width;         // width of non-clipped portion
    int drawHeight = height;       // height of non-clipped portion

    int startX = 0;                // starting position of non-clipped
    int startY = 0;                // portion to be drawn

    // replace any pixels that the sprite has covered
    if (onField)
      erase(bgnd);

    // *** CLIPPING ***
    
    // sprite is completely off playfield - don't draw anything
    if (x >= bgnd.width || y >= bgnd.height ||
	x+width < 0 || y+height < 0) {
      onField = false;
      return;
    }

    onField = true;
    
    // sprite is partially off left edge of playfield
    if (x < 0) {
      startX = -x;
    }
    // sprite is partially off right edge of playfield
    else 
      if (x+width >= bgnd.width) {
	drawWidth = bgnd.width - x;
      }
    // sprite is partially off top edge of playfield
    if (y < 0) {
      startY = -y;
    }
    // sprite is partially off bottom edge of playfield
    else 
      if (y+height >= bgnd.height) {
	drawHeight = bgnd.height - y;
      }

    oldX = x;
    oldY = y;

    for (int i=startY; i<drawHeight; i++) {
      for (int j=startX; j<drawWidth; j++) {
	// save all pixels under sprite
	coveredPixels[i*width+j] = bgnd.getPixel(x+j,y+i);

	// *** TRANSPARENT PIXELS ***

	int current_pix = super.getPixel(j,i);
	// find transparency = alpha byte of 32-bit pixel
	int alpha = (current_pix >> 24) & 0xff;	
	// draw pixel only if it is not transparent
	if (alpha != 0) {
	  bgnd.setPixel(current_pix, x+j, y+i);
	}
      }
    }
  }

  public void erase(Raster bgnd) {
    // erase will replace the covered pixels to the background. This also
    // takes into account clipping.

    int backWidth = width;         // width of portion to be replaced
    int backHeight = height;       // height of portion to be replaced

    int backX = 0;                 // starting postion of portion to 
    int backY = 0;                 // be replaced

    // *** CLIPPING ***

    // find clipping values for background to replace

    // sprite is completely off playfield - don't draw anything
    if (oldX >= bgnd.width || oldY >= bgnd.height ||
	oldX+width < 0 || oldY+height < 0)
      return;

    // sprite is partially off left edge of playfield
    if (oldX < 0) {
      backX = -oldX;
    }
    // sprite is partially off right edge of playfield
    else 
      if (oldX+width >= bgnd.width) {
	backWidth = bgnd.width - oldX;
      }
    // sprite is partially off top edge of playfield
    if (oldY < 0) {
      backY = -oldY;
    }
    // sprite is partially off bottom edge of playfield
    else 
      if (oldY+height >= bgnd.height) {
	backHeight = bgnd.height - oldY;
      }

    // replace covered pixels to bgnd
    for (int i=backY; i<backHeight; i++) {
      for (int j=backX; j<backWidth; j++) {
	bgnd.setPixel(coveredPixels[i*width+j],oldX+j,oldY+i);
      }
    }
  }

  public boolean collidesWith(Sprite s) {
    // collidesWith returns true if the bounding boxes of sprite s and this
    // sprite collide otherwise returns false.
    
    // upper lefthand corner of s is inside this
    if ((x >= s.x && x < s.x+s.width) ||
	(x+width >= s.x && x+width < s.x+s.width) ||
	(y >= s.y && y<s.y+s.height) ||
	(y+height>s.y && y+height<s.y+s.height))
      return true;
    else
      return false;
  }

  public void moveSpriteTo(int xPos, int yPos) {
    // moveSpriteTo moves the position of the sprite to the given one.

    // save old position
    oldX = x; oldY = y;

    x = xPos; y = yPos;
  }

  public void displaceSprite(int xDisp, int yDisp) {
    // displaceSprites displaces the position of the sprite by the 
    // given amounts.

    x = x + xDisp; y = y + yDisp;
  }


  public boolean isSprite(int xPos, int yPos) {
    // isSprite returns true if the given coordinates are at
    // a non-transparent pixel of this sprite

    if (xPos >= x && xPos <= x+width &&
	yPos >= y && yPos <= y+height) {
      int pix = super.getPixel(xPos-x,yPos-y);
      int alpha = (pix >> 24) & 0xff;
      if (alpha == 0) // transparent
	return false;
      else            // non-transparent
	return true;
    }
    else {
      return false;
    }
  }
}
