import java.awt.Color;

public class FallingObject extends MobileSimObject {
    // OVERVIEW: A FallingObject is a simulator object that moves in a constant
    // downward direction in addition to moving left and right.
    
    //@ghost public boolean isInitialized;
    public boolean inTurn; // Currently in the middle of a turn (used for coloring)
    public boolean isFalling;
    
    public FallingObject () 
    //@ensures !isInitialized;
    {
        // will create attached objects here
        inTurn = false;
        isFalling = true;
    }  
    public Color getColor()
    {
        if (isFalling) {
            return Color.cyan;
        } else {
            return Color.blue;
        }
    } //@nowarn NonNullResult // ESC/Java doesn't know Color constants are not null
      
    public void executeTurn() throws RuntimeException
    // Note: requires isInitialized is inherited from SimObject
    // Modifies: this
    // EFFECTS: Moves south.
    //          If the move is successful, return true. If the move fails
    //          because the spot being attempted to move into is already
    //          occupied then return false.  
    {
        Grid thisgrid = getGrid ();
        inTurn = true;
        
        Direction dir = thisgrid.UserDirection();
        
        int newrow = getRow () + dir.northerlyDirection ();
        int newcol = getColumn () + dir.easterlyDirection ();
        
        if (getGrid ().validLocation (newrow, newcol) ) {
            synchronized (getGrid ()) {
                if (getGrid().isSquareEmpty (newrow, newcol))
                {
                    setLocation(newrow, newcol);
                    
                }
                else if (getGrid().isSquareEmpty(newrow, getColumn())){
                    setLocation (newrow, getColumn());
                }
                else {
                    isFalling = false;
                }
            }
        }
        else if (getGrid ().validLocation (newrow, getColumn ())){
            if (getGrid().isSquareEmpty(newrow, getColumn())){
                setLocation (newrow, getColumn());
            }
            else {
                isFalling = false;
            }
        }
        else {
            isFalling = false;
        }
        inTurn = false;
    }
    public boolean isFalling () {
        return isFalling;
    }
    
    public boolean canExecuteTurn(Direction direct) throws RuntimeException
    // Note: requires isInitialized is inherited from SimObject
    // Modifies: this
    // EFFECTS: Moves south.
    //          If the move is successful, return true. If the move fails
    //          because the spot being attempted to move into is already
    //          occupied then return false.    
    {
        Grid thisgrid = getGrid ();
        inTurn = true;
        
        int newrow = getRow () + direct.northerlyDirection ();
        int newcol = getColumn () + direct.easterlyDirection ();
        
        if (getGrid ().validLocation (newrow, newcol) ) {
            synchronized (getGrid ()) {
                if (getGrid().isSquareEmpty (newrow, newcol))
                {
                    return true;
                }
                return false;
            }
        }
        return false;
    }
    
    public void run ()
    // REQUIRES: this has been initialized
  
    //    We use also_requires instead of requires, because we are adding a precondition
    //    to an inherited method.  This violates the substitution principle --- subtypes
    //    should make preconditions weaker, not stronger.
    // EFFECTS: The object thread.  If the object is not paused, executes one turn by calling
    //    the executeTurn method, and sleeps for a time and repeats.  If the object is paused,
    //    does nothing (until the object is unpaused).
    {
        //isPaused ()= false;
        while (isFalling) {
            if (!isPaused()) {
                executeTurn ();
            }
        }
    }
}