public class BCDerby {

	private BumperCarArena arena;	// creates an arena data member
					// for every bcderby

	public BCDerby() {

		arena = new BumperCarArena();	// initialize the data member

		Bumper bumper;			// get a Bumper object reference

		// add 10 new Bumpers
		bumper = new Bumper(randomLocation());
		arena.addBumperToArena(bumper);
		bumper = new Bumper(randomLocation());
		arena.addBumperToArena(bumper);
		bumper = new Bumper(randomLocation());
		arena.addBumperToArena(bumper);
		bumper = new Bumper(randomLocation());
		arena.addBumperToArena(bumper);
		bumper = new Bumper(randomLocation());
		arena.addBumperToArena(bumper);
		bumper = new Bumper(randomLocation());
		arena.addBumperToArena(bumper);
		bumper = new Bumper(randomLocation());
		arena.addBumperToArena(bumper);
		bumper = new Bumper(randomLocation());
		arena.addBumperToArena(bumper);
		bumper = new Bumper(randomLocation());
		arena.addBumperToArena(bumper);
		bumper = new Bumper(randomLocation());
		arena.addBumperToArena(bumper);

		BumperCar bumperCar;		// get a BumperCar object reference

		// add 5 new BumperCars
		bumperCar = new BumperCar(randomLocation(),randomDirection());
		arena.addBumperCarToArena(bumperCar);
		bumperCar = new BumperCar(randomLocation(),randomDirection());
		arena.addBumperCarToArena(bumperCar);
		bumperCar = new BumperCar(randomLocation(),randomDirection());
		arena.addBumperCarToArena(bumperCar);
		bumperCar = new BumperCar(randomLocation(),randomDirection());
		arena.addBumperCarToArena(bumperCar);
		bumperCar = new BumperCar(randomLocation(),randomDirection());
		arena.addBumperCarToArena(bumperCar);

		arena.drawArena();

	}

	// returns a random integer on the specified interval
	public int random(int lowerBound, int upperBound) {
		return (int)(Math.random()*(upperBound-lowerBound+1)) + lowerBound;
	}

	// returns a Location objects randomly placed about the arena data members
	public Location randomLocation() {
		int randomX = random(0,arena.FIELD_WIDTH-1);
		int randomY = random(0,arena.FIELD_HEIGHT-1);
		return new Location(randomX,randomY);
	}

	// returns a direction randomly
	public int randomDirection() {
		return random(0,3);
	}

    /************************************************************************/
    /************************************************************************/
    /**             DO NOT MODIFY ANY CODE BELOW HERE                      **/
    /**                (code provided for students)                        **/
    /************************************************************************/
    /************************************************************************/

    /** 
     *  Runs simulation. DO NOT EDIT. 
     *  The execution of this application starts here.
     *  @param args List of additional commands sent by the user.
     */
    public static void main(String [] args){
		BCDerby indy500 = new BCDerby();
		while(true)
		    indy500.moveAllCars();
    }

    /** Moves all the cars.  DO NOT EDIT. */
    public void moveAllCars(){
		BumperCarCollection cars = arena.getAllCars();
		while (cars.hasMoreCars())
		    moveCar(cars.nextCar());
		arena.drawArena();

    }
    
    /** 
     *  Moves one car inbounds. Changes direction if hit something.
     *  DO NOT EDIT. 
     */
    private void moveCar(BumperCar c){

		int dir = c.getDirection();
		
		if (dir == BumperCarArena.NORTH)
		    c.driveNorth();
		else if(dir == BumperCarArena.SOUTH)
		    c.driveSouth();
		else if (dir == BumperCarArena.EAST)
		    c.driveEast();
		else
		    c.driveWest();

		// Out of bounds check, if so, go to boundry and change direction
		boolean changeDir1 = boundsCheck(c);

		// See if + or - points
		boolean changeDir2 = talleyPoints(c);
		
		// Change direction if went out of bounds or hit something
		if(changeDir1 || changeDir2)
		    changeDirection(c);
    }

    /**
     *  Checks if car out of bounds. If car is out of bounds, put car on
     *  boundary. Return true if go out of bounds, false otherwise.  
     *  DO NOT EDIT. 
     */
    private boolean boundsCheck(BumperCar c){

		int x = c.getLocation().getX();
		int y = c.getLocation().getY();
		boolean change = false;
		
		if (x >= BumperCarArena.FIELD_WIDTH){
		    c.getLocation().move(-1,0);
		    change = true;
		}
		if (x < 0){
		    c.getLocation().move(1,0); 
		    change = true;
		}
		if (y >= BumperCarArena.FIELD_HEIGHT){
		    c.getLocation().move(0,-1);
		    change = true;   
		}
		if (y < 0){
		    c.getLocation().move(0,1);
		    change = true;
		}
		
		return change;
    }

    /** 
     *  Gives car a new direction other than the one it was previously going.  
     *  DO NOT EDIT. 
     */
    private void changeDirection(BumperCar c){
		int newDir = -1;
		do{
		    newDir = (int)(Math.random()*4);
		}while(newDir == c.getDirection());
		
		c.setDirection(newDir);
    }

    /**
     *  Checks to see if this car gained or lost any points
     *  Return true if +, - points, false if car did not hit a bumper or
     *  other car.  DO NOT EDIT. 
     */
    private boolean talleyPoints(BumperCar c){

		 int pointsWon = 5;    
		 int pointsLost = 2;
		 boolean change = false;
		 
		// See if get points by hitting a bumper, if so add and change dir.
		BumperCollection bumpers = arena.getAllBumpers();
		while(bumpers.hasMoreBumpers()){
		    if (c.getLocation().equals(bumpers.nextBumper().getLocation())){
			c.setPoints(c.getPoints()+pointsWon);
			change = true;
		    }
		}

		// See if hit other car, if so this car loses points and changes 
		// direction.
		BumperCarCollection cars = arena.getAllCars();
		while(cars.hasMoreCars()){
		    BumperCar next = cars.nextCar();
		    if (!c.equals(next)){
				if ((c.getLocation()).equals(next.getLocation())){
				    c.setPoints(c.getPoints()-pointsLost);
				    change = true;
				}
		    }
		}
		return change;
    }


} // end of BCDerby