/******************************* MAIN HEADER **********************************
    Title:       Assignment #1: Aquarium Simulation
    Files:       Aquarium.java, Fish.java, Piranha.java, FoodCenter.java
    
    Author:      James D. Skrentny, skrentny@cs.wisc.edu
                 copyright 2000 all rights reserved
    Course:      CS 302: All Lectures
    
    Compiler:    CodeWarrior IDE 4.0 (JDK 1.2)
    Platform:    Windows NT 4.0
 **************************** 80 columns wide *********************************/

import javabook2.*;

/** 
 * This program is an aquarium simulation with a user specified number of
 * fish, piranha, and food centers.  Both the fish and piranha move about
 * (i.e swim) the tank. Fish can eat at food centers, and piranha can eat
 * fish.  A graphical representation of the tank is shown.
 * 
 * The program user can choose to display the status of the contents of the
 * aquarium as well as running the simulation for one cycle, n cycles, or
 * continuously until there are no living things in the aquarium.
 * 
 * Bugs: Known bugs
 **/ 

class Aquarium {           
           
    private static Tank tank;        // contains fish, piranha, food centers
                                     // draws the graphical aquarium
    private static ListBox list;     // for simulation menu
    private static InputBox input;   // for user input (# items, N cylces)
    private static OutputBox output; // for displaying aquarium stats
    
    // for the menu options chosen by the user
    private final static int DISPLAY_STATS = 0;
    private final static int NEXT_MOVEMENT = 1;
    private final static int NEXT_N_MOVES  = 2;
    private final static int CONTINUOUS    = 3;
    private final static int QUIT          = 4;
    

    public static void main (String [] args) {           
   
        // construct a tank and draw it
        tank = new Tank();
        tank.refreshDisplay();

        // construct user I/O objects
        input  = new InputBox (tank);
        output = new OutputBox(tank, "Aquarium Output");

        // construct and configure the menu
        list = new ListBox  (tank, "Menu Choice");
        list.addItem("Display Aquarium Status");
        list.addItem("Next Movement");
        list.addItem("Next N Movements");
        list.addItem("Continuous  Mode");
        list.addItem("Quit");

        // Get quantities of tank items
        int fishQty = readPositiveInt("How many fish do you want?");
        int piranhaQty = readPositiveInt("How many piranha do you want?");
        int foodQty = readPositiveInt("How many food centers do you want?");

        // add items to the tank
        addFish(fishQty);
        addPiranha(piranhaQty);
        addFoodCenters(foodQty);
        
        // redraw the tank
        tank.refreshDisplay();
        
        while (somethingStillAlive()) {
        
            // display the options for the user
            int menuChoice = list.getSelectedIndex();

            // process the chosen option
            switch (menuChoice) {
                case DISPLAY_STATS: displayStats();   break;
                case NEXT_MOVEMENT: nextMovement();   break;
                case NEXT_N_MOVES:  nextNMovements(); break;
                case CONTINUOUS:    continuous();     break;
                case QUIT:          System.exit(0);   break;
                default:            System.out.println("Choose an option.");
            }
        }
        
        System.out.println("SIMULATION OVER: no living things");
        System.exit(0);
    }           

    /**
     * Asks the user for the number of Fish, and constructs and adds them
     * to the tank.
     **/
    private static void addFish (int quantity) {           
        for ( int i=0; i <= quantity; i++) {
            tank.addFish(new Fish());
        }
    }           

    /**
     * Asks the user for the number of Piranha, and constructs and adds
     * them to the tank.
     **/
    private static void addPiranha (int quantity) {           
        for (int i=0; i<quantity; i++) {
            tank.addPiranha(new Piranha());
        }
    }           

    /**
     * Asks the user for the number of FoodCenters, and constructs and adds
     * them to the tank.
     **/
    private static void addFoodCenters (int quantity) {           
        for (int i=0; i<quantity; i++) {
            tank.addFoodCenter(new FoodCenter());
        }
    }           

    /** 
     * Reads from the user and returns a positive integer.
     *
     * @param prompt the prompt that is displayed
     * @return a positive integer
     **/
    private static int readPositiveInt (String prompt) {           
        int number;
        do {
            number = input.getInteger(prompt + ":");
            if (number < 0) {
                System.out.println("Negatives aren't allowed.");
            }
        } while (number < 0);
        
        return number;
    }           
    
    
    
    /**
     * Displays the status of the Fish, Piranha and FoodCenters in the
     * Aquarium.
     **/
    private static void displayStats () {           
        displayFish();
        displayPiranha();
        displayFoodCenters();
        output.waitUntilClose();
    }           
        
    /**
     * Displays the status of Fish in the Aquarium.
     **/
    private static void displayFish () {           
        output.skipLine(2);
        output.printLine("Fish Info:");
        FishList fl = tank.getFishList();
        while (fl.hasMoreFish()) {
            Fish f = fl.nextFish();
            output.printLine(f.toString());
        }
    }           

    /**
     * Displays the status of Piranha in the Aquarium.
     **/
    private static void displayPiranha () {           
        output.skipLine(2);
        output.printLine("Piranha Info: ");
        PiranhaList pl = tank.getPiranhaList();
        while (pl.hasMorePiranha()) {
            Piranha p = pl.nextPiranha();
            output.printLine(p.toString());
        }
    }           
    
    /**
     * Displays the status of FoodCenters in the Aquarium.
     **/
    private static void displayFoodCenters () {           
        output.skipLine(2);
        output.printLine("Food Centers Info:");
        FoodCentersList fcl = tank.getFoodCentersList();
        while (fcl.hasMoreFoodCenters()) {
            FoodCenter fc = fcl.nextFoodCenter();
            output.printLine(fc.toString());
        }
    }           

    
    
    /**
     * Allows the user to specify how many moves each fish and piranha should
     * take.  The number of moves must be a positive int.  The Aquarium then
     * runs for this many moves, or until nothing is living.
     **/
    private static void nextNMovements () {           
        int numberMoves = readPositiveInt("Enter the number of moves");
        for (int i=0; somethingStillAlive() && i<numberMoves; i++) {
            nextMovement();
        }
    }           

    /**
     * The Aquarium runs until nothing is living.
     **/
    private static void continuous () {           
        while (somethingStillAlive()) {
            nextMovement();
        }
        
        System.exit(0);
    }           

    /**
     * Checks if any fish or piranha in the Aquarium are still alive.
     *
     * @return false if there are no living fish or piranha, true otherwise
     **/
    private static boolean somethingStillAlive () {           
        boolean alive = false;
        FishList fl = tank.getFishList();
        while (fl.hasMoreFish()) {
            Fish f = fl.nextFish();
            alive = alive || f.isAlive();
        }
        
        PiranhaList pl = tank.getPiranhaList();
        while (pl.hasMorePiranha()) {
            Piranha p = pl.nextPiranha();
            alive = alive || p.isAlive();
        }
       return alive;
    }           


    /**
     * Runs the Aquarium for one movement. This includes: moving all of
     * the fish; feeding the fish if any are on a food center; moving the
     * piranha; feeding the hungry piranha if it is near any weak fish;
     * displaying the updated Tank
     **/
    private static void nextMovement () {           
        // any order of these steps will do
        moveFish();
        movePiranha();
        feedFish();
        feedPiranha();
        // redraw the tank
        tank.refreshDisplay();
    }           

    /**
     * Moves each Fish.
     **/
    private static void moveFish () {           
        FishList fl = tank.getFishList();
        while (fl.hasMoreFish()) {
            Fish f = fl.nextFish();
            f.move();
        }
    }           

    /**
     * Moves each Piranha.
     **/
    private static void movePiranha () {           
        PiranhaList pl = tank.getPiranhaList();
        while (pl.hasMorePiranha()) {
            Piranha p = pl.nextPiranha();
            p.move();
        }
    }           

    /**
     * Feeds each Fish if it is on a FoodCenter that has food.
     **/
    private static void feedFish () {           
        // for each fish
        FishList fl = tank.getFishList();
        while (fl.hasMoreFish()) {
            Fish f = fl.nextFish();
            // check if this fish is on any of the food centers
            FoodCentersList fcl = tank.getFoodCentersList();
            while (fcl.hasMoreFoodCenters()) {
                FoodCenter fc = fcl.nextFoodCenter();
                if (f.getLocation().equals(fc.getLocation())) {
                    f.eat(fc);
                }
            }
        }
    }           

    /**
     * Feeds each hungry Piranha if it is near a weak Fish.
     **/
    private static void feedPiranha () {           
        // for each piranha
        PiranhaList pl = tank.getPiranhaList();
        while (pl.hasMorePiranha()) {
            Piranha p = pl.nextPiranha();
            // check if this piranha is near any fish
            FishList fl = tank.getFishList();
            while (fl.hasMoreFish()) {
                Fish f = fl.nextFish();
                if (p.getLocation().chessBoardDistance(f.getLocation())<= 1) {
                    p.eat(f);
                }
            }
        }
    }           
           
}           
