package control;
import control.*;
import java.awt.*;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.*;
import java.awt.geom.AffineTransform;
import java.net.URL;
import javax.swing.ImageIcon;

/**
 *  Sprites are objects that live on the graph object that make it easier to
 * manage animation and collision detection.
 */
public class Sprite {
    
    double angle;
    double x;
    double y;
    double cmx;
    double cmy;
    int width;
    int height;
    String comment = "";
    
    Hurtable obj;

    public void setObj( Hurtable ob )
    {
        obj = ob;
    }
    public Hurtable getObj()
    {
        return obj;
    }
    /**
     * keep a current AffineTransform to go from the Graph frame of reference
     * to the Sprite's frame of reference.
     */
    AffineTransform transform;
    
    int imageWidth;
    int imageHeight;
    boolean isHidden;
    
    Screen graph;
    private Image image;
    
    /**
     * the Area that covers the sprite, used for detecting overlaps
     */
    Area bounds;
    
    /**
     * creates a sprite that lives on the Graph
     * @param filename the file to used for the sprite image, a .gif or .png file.
     * @param graph the graph on which the sprite will live.
     */
    protected Sprite( String filename, Screen graph ) {
        this( filename, graph, 0, 0, -99, -99 );
        
    }    
    
    /**
     * creates a new Sprite from the image in filename on graph.  The center
     * of mass reference cmx, cmy are will be located at x,y when
     * setPosition(x,y) is called, and rotation is done with respect to this
     * point.
     * @param filename name of the sprite filename, a .gif or a .png
     * @param graph graph object on which the sprite will live
     * @param x initial x location
     * @param y initial y location
     * @param cmx pixel coordinate of the anchor of the sprite image.
     * @param cmy pixel coordinate of the anchor of the sprite image.  
     */
    protected Sprite( String filename, Screen graph, int x, int y, double cmx, double cmy ) {
        this.graph= graph;
        
        this.x= x;
        this.y= y;
        this.angle=  0;
        this.isHidden= false;
        
        
        if ( ! filename.startsWith("/") ) filename= "/" + filename;
        
        URL ff= Chess.findResource(filename);
        
        if ( ff==null ) {
            throw new RuntimeException( "unable to find file " + filename );
        }
        
        image= new ImageIcon( ff ).getImage();
        imageWidth= image.getWidth(graph.panel);
        imageHeight= image.getHeight(graph.panel);
        
        if ( cmx==-99 || cmy==-99 ) {
            cmx= imageWidth / 2.;
            cmy= imageHeight / 2.;
        }
        this.cmx= cmx;
        this.cmy= cmy;
        
        this.bounds= new Area( new Rectangle( 0,0, imageWidth, imageHeight ) );
        
        resetTransform();
    }
    
    
    /**
     * paint the sprite onto the graphics object.
     * @param g1 the graphics object to paint on.
     */
    protected void paint( Graphics g1 ) {
        if ( !isHidden ) {
            Graphics2D g= (Graphics2D) g1;
            
            AffineTransform at0= g.getTransform();
            
            g.transform( transform );
            
            g.drawImage( image,0,0,graph.panel );
            
            g.setTransform(at0);
            
            g.setColor( new Color( 1.f, 0.f, 0f, 0.2f ) );
            // g.fill( getBounds() );
        }
    }
    
    /**
     * set the position of the sprite to x,y, where 0,0 is the upper-left
     * corner of the graph.
     * @param x the new x coordinate of the sprite
     * @param y the new y coordinate of the sprite.
     */
    public void setPosition( int x, int y ) {
        this.x= x;
        this.y= y;
        resetTransform();
        graph.repaint();
    }
    
    /**
     * sets the position of the sprite on the graph.
     * @param x the new x coordinate of the sprite's anchor
     * @param y the new y coordinate of the sprite's anchor
     */
    public void setPosition( double x, double y ) {
        this.x= x;
        this.y= y;
        resetTransform();
        graph.repaint();        
    }

    /**
     * sets the position of the sprite's anchor relative to the sprite image.
     * (0,0) is the upper-left corner of the image.
     * @param x the new x coordinate of the sprite's anchor.
     * @param y the new y coordinate of the sprite's anchor
     * @skillLevel week 2
     */
    public void setAnchorPosition( double x, double y ) {
        this.cmx= x;
        this.cmy= y;
        resetTransform();
        graph.repaint();        
    }
    
    /**
     * resets the sprite's image.  (For example, with explosion to indicate a hit.)
     * @param filename sets the new image for the sprite, a .gif or .png file.
     */
    public void setImage( String filename ) {
        URL ff= Chess.findResource(filename);
        if ( ff==null ) {
            throw new RuntimeException( "unable to find file " + filename );
        }
        
        image= new ImageIcon( ff ).getImage();
        graph.repaint();
    }
    
    /**
     * returns the X coordinate of the sprite.
     * @return the x coordinate of the sprite's anchor position
     */
    public int getPositionX(){
        return (int)this.x;
    }
    
    /**
     * returns the Y coordinate of the sprite.
     * @return the Y coordinate of the sprite's anchor position
     */
    public int getPositionY(){
        return (int)this.y;
    }
    
    /**
     * set the orientation of the sprite by turning it so many degrees
     * clockwise from its original position.
     * @param angle angle in degrees of counter-clockwise rotation about the sprite's anchor.
     */
    public void setOrientation( double angle ) {
        this.angle= angle * Math.PI / 180;
        resetTransform();
        graph.repaint();
    }
        
    /**
     * get the current orientation of the sprite.
     * @return the angle in degrees of counter-clockwise rotation about the sprite's anchor.
     */
    public int getOrientation( ) {
        return (int)( angle * 180 / Math.PI );
    }
    public double getRadians()
    {
        return angle;
    }
    
    /**
     * reset the AffineTransform used to draw the sprite from x, y, and angle.
     */
    protected void resetTransform() {
        transform= AffineTransform.getTranslateInstance( this.x, this.y );
        transform.rotate( angle );
        transform.translate(-cmx,-cmy);
    }
    
    /**
     * make the sprite invisible.  Note that the sprite still consumes Graph resources,
     * so use graph.destroySprite() to remove sprites that are no longer needed.
     */
    public void hide() {
        isHidden= true;
        graph.repaint();
    }
    
    /**
     * make the hidden sprite visible again.
     */
    public void reveal() {
        isHidden= false;
        graph.repaint();
    }
    
    /**
     * return true if x,y is overlapped by the sprite.  Note that transparency in gif's and png's is not currently
     * supported, so if the point is within the bounding rectangle then it is an overlap.
     * @param x the x coordinate of the point to check
     * 
     * @param y the y coordinate of the point to check.
     * @return true if the sprite overlaps with this point.
     */
    public boolean overlaps( int x, int y ) {
        
        try {            
            Point2D p= new Point2D.Double( x, y );
            p= transform.createInverse().transform( p, p );
            Shape boundary= new Rectangle( image.getWidth(null), image.getHeight(null) );
            return boundary.contains(p);

        } catch ( NoninvertibleTransformException e ) {
            // this won't happen with translate and rotate
            throw new RuntimeException(e);
        }                
        
    }        
    
    /**
     * sets the Sprite's bounds.  The area specified should be in the image's coordinate system. If not specified, then a rectangle covering the image is used.
     * The value returned by getBounds() will be in the screen's coordinate system.
     * @skillLevel advanced
     */
    public void setBounds( Area a ) {
        this.bounds= a;
    }
        /**
     * get the current orientation of the sprite.
     * @return the angle in degrees of counter-clockwise rotation about the sprite's anchor.
     */
    public void setRadians( double radians )
    {
        angle = radians;
        resetTransform();
        graph.repaint();
    }
        public int getWidth()
    {
        return this.width;
    }
    public int getHeight()
    {
        return this.height;
    }
    public void setHeight( int ht )
    {
        this.height = ht;
    }
    public void setWidth( int wd )
    {
        this.width = wd;
    }
        public void setComment( String newcomment )
    {
        this.comment = newcomment;
    }
    
    public String getComment()
    {
        return Sprite.this.comment;
    }
    
        /**
     * gets the Sprite's bounds.  The area specified should be in the  If not specified, then a rectangle covering the image is used.
     * The value returned by getBounds() will be in the screen's coordinate system.
     * @skillLevel advanced
     */
    public Area getBounds() {
        GeneralPath path= new GeneralPath(bounds);
        path.transform( transform );
        Area a= new Area( path );
        return a;
    }
}