import java.awt.*;
import java.awt.image.*;
import java.util.*;

/**
 * implements a playfield class
 * the Sprites are all managed using this class
 */
class Playfield extends Raster  
{

    
    // creates a hashtable indexed by sprites, that has the position (Point) of each
    // sprite indexed by the sprite
    Hashtable spriteList = new Hashtable();
    // my background
    Raster myBG;
    
    // current floor
    int floor;

    public Playfield(Image img)
    {
        super(img);
        myBG = new Raster(img);
    }
    
    public Playfield(Raster r, Component root)
    {
        super(r.toImage(root));
        myBG = r;
    }
    
    /**
     * Checks for transparency
     * returns null if transparent
     * otherwise, returns (the one [there can be only one]) Sprite
     * that is in that x, y positoin
     */
    public Sprite checkTrans(int x, int y)
    {
        Sprite spr;
        Enumeration sprites;
        Point loc;
        
        if( spriteList.isEmpty() ) return null;
       
        sprites = spriteList.keys();

        while( sprites.hasMoreElements() )
        {
            spr = (Sprite)sprites.nextElement();
            loc = (Point)spriteList.get(spr);
            /*debug*///System.out.println("> " + x + " " + loc.x + " " + y + " " + loc.y + ";" + spr.width + " " + spr.height);
            //System.out.println(spr.toString());
            
            if(x - loc.x < 0 || y - loc.y < 0 || x - loc.x > spr.width || y - loc.y > spr.height)
            {
                
            }
            else {
                if( !spr.isTrans(x - loc.x, y - loc.y) )
                {
                    //System.out.println("found non trans");
                    return spr;
                }
            }
            
        }
        return null;
    }
        

    /**
     * puts a sprite in the playfield at a given x, y
     * puts sprite into the Hashtable of sprites in the field
     */
    public void putSprite(Sprite spr, int x, int y)
    {
        Point oldLoc = (Point)spriteList.put(spr, new Point(x, y));
        if( oldLoc == null)
        {
            drawSprite(spr, x, y);
        }
        else
        {
            delSprite(spr, oldLoc.x, oldLoc.y);
            drawSprite(spr, x, y);
            //pixBlt(spr, oldLoc.x, oldLoc.y, x, y);
        }
    }
    
    /**
     * for readability, moveSprite is the same as putSpite
     */
    public void moveSprite(Sprite spr, int x, int y)
    {
        putSprite(spr, x, y);
    }

    /**
     * for readability, addSprite is the same as putSpite
     */
    public void addSprite(Sprite spr, int x, int y)
    {
        putSprite(spr, x, y);
    }

    /**
     * drwas a sprite at x, y of the playField
     */
    public void drawSprite(Sprite spr, int x, int y)
    {
        int istart = 0, jstart = 0;
        int maxi = spr.width;
        int maxj = spr.height;
        int pix;
        
        if( x + maxi > width )
        {
            maxi = width - x - 1;
        }
        if( y + maxj > height )
        {
            maxj = height - y - 1;
        }
        if( x < 0 )
        {
            istart = -x;
        }
        if( y < 0 )
        {
            jstart = -y;
        }


        // perhaps modify these values for error checking
        for(int i = istart; i < maxi; i++ )
        {
            for(int j = jstart; j < maxj; j++ )
            {
                pix = spr.getPixel(i, j);
                if( (pix >> 24) != 0 )
                {
                    setPixel(pix, x+i, y+j);
                }
            }
        }
    }
    
    /** completely removes a sprite, attempts to undraw it, and removes
     *  from table
     */
    public void removeSprite(Sprite spr)
    {
        delSprite(spr);
        spriteList.remove(spr);
    }
    
    /** delted the physical presenece of the sprite on the picture
     *  but leaves the hash table of what is in the playfield alone
     */
    public void delSprite(Sprite spr)
    {
        if( spriteList.isEmpty() ) return;
        Point pt = (Point)spriteList.get(spr);
        if( pt == null ) return;
        delSprite(spr, pt.x, pt.y);
    }
    
    /**
     * drwas a sprite at x, y of the playField
     */
    public void delSprite(Sprite spr, int x, int y)
    {
        if( spr == null ) { return; }
        
        int istart = 0, jstart = 0;
        int maxi = spr.width;
        int maxj = spr.height;
        int pix;
        
   
        
        if( x + maxi > width )
        {
            maxi = width - x - 1;
        }
        if( y + maxj > height )
        {
            maxj = height - y - 1;
        }
        if( x < 0 )
        {
            istart = -x;
        }
        if( y < 0 )
        {
            jstart = -y;
        }


        // perhaps modify these values for error checking
        for(int i = istart; i < maxi; i++ )
        {
            for(int j = jstart; j < maxj; j++ )
            {
                pix = spr.getPixel(i, j);
                if( (pix >> 24) != 0 )
                {
                    setPixel(myBG.getPixel(x+i, y+j), x+i, y+j);
                }
            }
        }
    }
    
    /*
     * Returns the position on the play field of a given sprite
     * or null if it isn't there
     */
    public Point getSpritePos(Sprite spr)
    {
        if( spriteList.isEmpty() ) return null;
        return (Point)spriteList.get(spr);
    }
    
    public void setFloor(int fl)
    {
        floor = fl;
    }
    
    public int getFloor()
    {
        return floor;
    }
    
    /**
     * returns whether sprite is in playfield
     */
    public boolean isSprite(Sprite spr)
    {
        return spriteList.containsKey(spr);
    }
    
    
    /**
     * returns whether sprite is in playfield
     */
    public boolean containsSprite(Sprite spr)
    {
        return spriteList.containsKey(spr);
    }
    
    
    /** so in the end I did not decide to debug this code, since I sent e-mail
        asking if pixBlt was necessary, and never got a response, and being
        that there was no mention of it, and being that my implementation would
        have little use for it, the code is commented out. **/
    /**
     * My version of pixBlt which takes a sprite,
     * and moves it's upleft corner to a new position
     * given it's current implementatin, this is a massive waste of time,
     * it would make far more sense, just to delete the original sprite,
     * and redraw it using the Sprite held in the hashtable whihc must be kept
     * around to know which pixels should be transparent.
     * however, to ensure that my project satisifies requirements, I will use
     * it anyways, or at least try
     */
     /*
    public void pixBlt(Sprite spr, int xs, int ys, int xd, int yd)
    {
        // it would take equal time and more sense if i just had the following
        // delSprite(spr);
        // putSprite(spr, xd, yd);
        
        int i, j;
        int width = spr.width;
        int height = spr.height;
        int x_start, x_stop;
        int y_start, y_stop;
        int dx, dy;
        
        
        if( xs < xd )
        {
            x_start = xs;
            x_stop = xd;
            dx = 1;
        }
        else
        {
            x_start = xd;
            x_stop = xs;
            dx = -1;
        }
        if( ys < yd )
        {
            y_start = ys;
            y_stop = yd;
            dy = 1;
        }
        else
        {
            y_start = yd;
            y_stop = ys;
            dy = -1;
        }
        
        for(i = x_start; i < x_stop; i += dx )
        {
            for(j = y_start; j < y_stop; j += dy )
            {
                pix = spr.getPixel(i - xs, j - y_start);
                if( (pix >> 24) != 0 )
                {
                    setPixel(myBG.getPixel(x+i, y+j), x+i, y+j);
                }
            }
        }
        
    }
    
    public void pixBlt(Sprite spr, int xd, int yd)
    {
        Point pt = (Point)spriteList.get(spr);
        pixBlt(spr, pt.x, pt.y, xd, yd);
    }
    */
}
