/** A kind of playing field with extra stuff for playing Tetris.
 *
 * @author	Jim Grundy
 * @version	$Revision: 1.20 $ */

import java.awt.Color;	// Colors.

public class TetrisField extends ObjectField
{
    /** Create a Tetris field. */
    public TetrisField(PlayingField field)
    {
	super(field);
    }
    
    /** Check if a TetrisField is full up.
     *
     * @return true iff any space on the top row is occupied. */
    public boolean full()
    {
	boolean tileFound = false;
	for (int column=0; column<getWidth(); column=column+1) {
	    /* INVARIANT: 
	     *   (0 <= column <= getWidth()) &&
	     *   (tileFound = "some tile on the top row in columns 0 to
	                       column -1 is nonempty") */
	    tileFound = tileFound || (getObject(column,getHeight()-1) != null);
	}
	return tileFound;
    }
    
    /** Clears any filled rows on the field.
     * 
     * Any row on the TetrisField that is fully filled, i.e., every space
     * contrains a brick, is cleared. The rows above a cleared row are
     * moved down to take up the space.  This leaves an empty row at the
     * top of the TetrisField. */
    public void clearRows()
    {
	/* We clear the field by stepping two indexes, targetRow and
	 * sourceRow, though it.  At each step the target row is replaced
	 * by the source row.  The target row is incremented by one each
	 * iteration, as is the source row.  However, the source row also
	 * skips over any filled rows.  The result is that the n'th row of
	 * the field is replaced by the n'th unfilled row of the field. */
	
	int sourceRow = 0;
	for (int targetRow=0; targetRow<getHeight(); targetRow=targetRow+1) {
	    /* INVARIANT: 
	     *   (0 <= targetRow <= getHeight()) &&
	     *   (targetRow <= sourceRow) &&
	     *   ("sourceRow is just above the targetRow'th unfilled row.") &&
	     *   ("Every row n < targetRow 
             *     is a copy of the n+1th unfilled row) */
	    
	    /* Find the next unfilled row */
	    while (filled(sourceRow)) {
		sourceRow = sourceRow + 1;
	    }
	    
	    copyRow(sourceRow, targetRow);
	    sourceRow = sourceRow + 1;
	}  

	repaint();
    }
    
    /* Determine if a row is filled. */
    private boolean filled(int row) 
    {
	/* Rows above the field are considered to be empty. */
	if (row >= getHeight()) {
	    return false;
	}
	
	/* Check if a row on the field is filled. */
	boolean filledSoFar = true;
	for (int column=0; column<getWidth(); column=column+1) {
	    /* INVARIANT: 
	     *   (0 <= column <= getWidth()) &&
	     *   (filledSoFar = "All the tiles in row in columns 0
	     *                   to column - 1 are occupied") */
	    
	    filledSoFar = filledSoFar && (getObject(column,row) != null);
	}
	return filledSoFar;
    }
    
    /* Replace the target row with the source row. */
    private void copyRow(int sourceRow, int targetRow) 
    {
	for (int column=0; column<getWidth(); column=column+1) {
	    if (sourceRow < getHeight()) {
		setObject(column, targetRow, getObject(column, sourceRow));
	    } else { //Rows above the field are considered vacant.
		setObject(column, targetRow, null);
	    }
	}
    }
}


