// This program defines and demonstrates a subclass of the Science
// of Computing robots that provides ways of drawing various figures.
// Unfortunately, the drawing methods contain bugs! Students are supposed
// to locate and correct these bugs.
//
// The features provided to clients, and their intended behaviors,
// are as follows:
//
//   o A parameterless constructor, which initializes a buggy robot
//       with a default position and orientation in a default room.
//
//   o A constructor that takes horizontal and vertical tile coordinates,
//       an orientation, and a room as its parameters, and initializes
//       a buggy robot with that position and orientation in that room.
//
//   o plusSign, a parameterless message that causes a robot to draw
//       a red "plus" sign against a yellow background. The background
//       is a 5-by-5 tile area, the "plus" is a red cross through the
//       middle row and column of this area. This message has no
//       return value.
//     Preconditions: The robot is standing on the upper left tile of
//       the background region, facing to the right. There are no obstructions
//       in the 5-by-5 tile area that the figure will occupy.
//     Postconditions: The robot is standing on the lower right tile
//       of the figure (which looks as described above).
//
//   o pointyShape, a message that takes an integer, n, as its only
//       parameter, and that draws a pair of blue lines, n tiles long, with
//       a one-tile gap between them. One tile beyond the end of the
//       lines, there is a single blue tile in the gap, so that the
//       overall shape looks something like this:
//
//            *******
//                   *
//            *******
//
//       This message has no return value.
//     Preconditions: The robot is standing on what will be the first
//       tile (furthest from the point) of the upper or lefthand line,
//       facing in the direction that line should grow. There are no
//       obstructions on the tiles that will be colored, or the tiles
//       adjacent to the point. n >= 0.
//     Postconditions: The robot is standing on the tile furthest from
//       the point on the lower or righthand line, facing away from
//       the point.
//
//   o tree, a message that causes a robot to draw a green "robot tree"
//       of size n, where n is an integer parameter to the message. A
//       "robot tree" is a shape defined as follows:
//         - A robot tree of size 1 is a single green tile.
//         - A robot tree of size n > 1 is a green line n tiles long,
//           with robot trees of size floor(n/2) touching and perpendicular to
//           one end (the "fork" end).
//       This message has no return value.
//     Preconditions: The robot is standing at the base of the future
//       trunk (i.e., the end of the trunk opposite the fork), facing
//       towards the fork. There are no obstructions on the tiles that
//       will be covered by or adjacent to the tree. n >= 1.
//     Postconditions: The robot is standing at the base of the trunk,
//       facing away from the fork.
//
//   o freeSpace, a parameterless message that returns the total number of
//       unobstructed tiles reachable by a robot in its row or column.
//     Preconditions: None.
//     Postconditions: The returned value is the number of tiles the robot
//      can reach by moving forward or backward from its initial tile.
//      This count includes the initial tile. The robot is standing on
//      its original tile, facing in its original direction.

// History:
//   March 2004 -- Created by Doug Baldwin.

// Copyright (C) 2004. Charles River Media.




import java.awt.Color;
import geneseo.cs.sc.Robot;
import geneseo.cs.sc.RobotRoom;




class BuggyRobot extends Robot {




	// The constructors:
	
	public BuggyRobot() {
		super();
	}
	
	
	public BuggyRobot( int col, int row, int orientation, RobotRoom room ) {
		super( col, row, orientation, room );
	}
	
	
	
	
	// The plusSign method. This works by invoking some helper methods,
	// namely one that draws a horizontal strip of background with a
	// piece of the "plus" in the middle, and one that draws the horizontal
	// bar of the "plus". In between each of these strips, the robot uses
	// other helper methods to turn around and move to the next strip.
	
	public void plusSign() {
	
		this.drawBackgroundStrip();		// The top strip of background
		
		this.turnAndMoveRight();
		this.drawBackgroundStrip();		// The second strip of background
		
		this.turnAndMoveRight();
		this.drawLine( 5, Color.red );	// The bar of the plus
		
		this.turnAndMoveRight();
		this.drawBackgroundStrip();		// The 2nd-from-bottom background strip
		
		this.turnAndMoveLeft();
		this.drawBackgroundStrip();		// The bottom strip of background
	}
	
	
	
	
	// The pointyShape method. This is based on the recursive insight that
	// a pointy shape with 0-tile sides is just the central blue tile, while
	// a pointy shape with n>0 tiles per side is a blue tile, a pointy
	// shape of n-1 tiles per side, and a final blue tile.
	
	public void pointyShape( int n ) {
	
		if ( n > 0 ) {
			this.paint( Color.blue );
			this.move();
			this.pointyShape( n - 1 );
			this.move();
			this.paint( Color.blue );
		}
		else {
			this.turnRight();
			this.move();
			this.paint( Color.blue );
			this.turnRight();
			this.move();
		}
	}
	
	
	
	
	// The tree method. This is simply a translation of the definition of
	// "robot tree" into Java. Note that this uses a helper method to draw
	// the tree's trunk.
	
	public void tree( int n ) {
		
		if ( n > 1 ) {
		
			// Draw the trunk:
			this.drawLine( n, Color.green );
			
			// Draw the left branch:
			this.turnLeft();
			this.move();
			this.tree( n / 2 );
			
			// Draw the right branch:
			this.move();
			this.tree( n / 2 );
			
			// Return to the base of the trunk, per the postcondition:
			this.move();
			this.turnLeft();
			this.drawLine( n, Color.green );
		}
		else {

			// Draw the one tile tree:
			this.drawLine( 1, Color.green );
			
			// Turn around to face away from the "fork" end, per the postcondition:
			this.turnLeft();
			this.turnLeft();
		}
	}
	
	
	
	
	// The freeSpace method. This uses a helper method to count the empty tiles in
	// front of the robot and behind the robot, then uses those results to compute
	// the final total.
	
	public int freeSpace() {	
		int spaceAhead = this.countToWall();
		int spaceBehind = this.countToWall();
		return spaceAhead + spaceBehind;
	}
	
	
	
	
	// Helper methods for the others:
	//   drawBackgroundStrip draws a 5-tile strip consisting of 2 yellow
	//     tiles, 1 red, and 2 more yellow. Preconditions are that the
	//     robot is standing on the first tile of the strip, facing in
	//     the direction the strip should grow, and there are no obstacles
	//     on the 4 tiles in front of the robot. Postconditions are that
	//     the robot is standing on the last tile of the strip, facing in
	//     its original direction.
	//   drawLine draws a line n tiles long, where n is a parameter to the
	//     method. The second parameter is the color the line should have.
	//     Preconditions are that the robot is standing on what should be
	//     the first tile of the line, facing along the future line, and
	//     there are no obstacles on the n-1 tiles in front of the robot.
	//     Postconditions are that the robot is standing on the last tile
	//     of the line, facing in its original direction.
	//   turnAndMoveLeft turns a robot 180 degrees, and makes it move one
	//     tile to its left in the process. Preconditions are that the tile
	//     to the robot's left is unobstructed. Postconditions are that the
	//     robot is standing on the tile to the left of its original position,
	//     facing in the opposite of its original direction.
	//   turnAndMoveRight turns a robot 180 degrees, and makes it move one
	//     tile to its right in the process. Preconditions are that the tile
	//     to the robot's right is unobstructed. Postconditions are that the
	//     robot is standing on the tile to the right of its original position,
	//     facing in the opposite of its original direction.
	//   countToWall counts the number of tiles between a robot and the nearest
	//     obstacle that robot is facing, not counting the tile the robot starts
	//     on. There are no preconditions for this method. Postconditions are that
	//     the robot is standing on its original tile, facing in the opposite of
	//     its original direction. 
	
	private void drawBackgroundStrip() {
		this.paint( Color.yellow );
		this.move();
		this.paint( Color.yellow );
		this.move();
		this.paint( Color.red );
		this.move();
		this.paint( Color.yellow );
		this.move();
		this.paint( Color.yellow );
	}
	
	
	private void turnAndMoveLeft() {
		this.turnLeft();
		this.move();
		this.turnLeft();
	}
	
	
	private void turnAndMoveRight() {
		this.turnRight();
		this.move();
		this.turnRight();
	}
	
	
	private void drawLine( int n, Color c ) {
	
		if ( n > 1 ) {
			this.paint( c );
			this.move();
			this.drawLine( n - 1, c );
		}
		else {
			this.paint( c );
		}
	}
	
	
	private int countToWall() {
	
		if ( this.okToMove() ) {
			this.move();
			int distance = this.countToWall();
			this.move();
			return 1 + distance;
		}
		else {
			this.turnLeft();
			this.turnLeft();
			return 0;
		}
	}




	// The main method creates and exercises some buggy robots.
	
	public static void main( String[] args ) {
	

		// Exercise the plusSign message:
		
		RobotRoom plusRoom = new RobotRoom();
		BuggyRobot plus = new BuggyRobot( 2, 2, Robot.EAST, plusRoom );
		
		plus.plusSign();
		

		// Exercise the pointyShape message:
		
		RobotRoom pointRoom = new RobotRoom( "11 7" );
		BuggyRobot nullPoint = new BuggyRobot( 2, 5, Robot.NORTH, pointRoom );
		BuggyRobot bigPoint = new BuggyRobot( 6, 5, Robot.NORTH, pointRoom );
		
		nullPoint.pointyShape( 0 );
		bigPoint.pointyShape( 3 );
		

		// Exercise the tree message:
		
		RobotRoom treeRoom = new RobotRoom( "19 11" );
		BuggyRobot smallTree = new BuggyRobot( 2, 9, Robot.NORTH, treeRoom );
		BuggyRobot simpleTree = new BuggyRobot( 6, 9, Robot.NORTH, treeRoom );
		BuggyRobot oddTree = new BuggyRobot( 13, 9, Robot.NORTH, treeRoom );
		
		smallTree.tree( 1 );
		simpleTree.tree( 4 );
		oddTree.tree( 7 );
		
		RobotRoom bigTreeRoom = new RobotRoom( "15 13" );
		BuggyRobot bigTree = new BuggyRobot( 7, 11, Robot.NORTH, bigTreeRoom );
		bigTree.tree( 8 );
		
		
		// Exercise the freeSpace message:
		
		RobotRoom spaceRoom = new RobotRoom( "6 7  1 2 *  2 4 *  3 1 *" );
		BuggyRobot noSpace = new BuggyRobot( 1, 1, Robot.NORTH, spaceRoom );
		BuggyRobot frontSpace = new BuggyRobot( 2, 3, Robot.NORTH, spaceRoom );
		BuggyRobot backSpace = new BuggyRobot( 3, 2, Robot.NORTH, spaceRoom );
		BuggyRobot muchSpace = new BuggyRobot( 4, 3, Robot.NORTH, spaceRoom );
		
		System.out.println( "no-space robot has " + noSpace.freeSpace() + " tiles." );
		System.out.println( "front-space robot has " + frontSpace.freeSpace() + " tiles." );
		System.out.println( "back-space robot has " + backSpace.freeSpace() + " tiles." );
		System.out.println( "much-space robot has " + muchSpace.freeSpace() + " tiles." );
	}

}