// FILE: organism.h
//
// CLASSES PROVIDED: Organism, Plant, Animal, Herbivore
//
// CLASS TO BE ADDED: Carnivore
//
// DOCUMENTATION for the Organism class:
//   The Organism class can simulate any growing organism, such as a plant or
//   animal.
//
// CONSTRUCTOR for the Organism class:
//   Organism(double init_size = 1, double init_rate = 0)
//     Precondition: init_size >= 0. Also, if init_size = 0, then init_rate is
//     also zero.
//     Postcondition: The organism being simulated has been initialized. The
//     value returned from get_size( ) is now init_size (measured in ounces),
//     and the value returned from get_rate( ) is now init_rate (measured in
//     ounces per week).
//
// MODIFICATION MEMBER FUNCTIONS for the Organism class:
//   void simulate_week( )
//     Postcondition: The size of the organism has been changed by its current
//     growth rate. If the new size is less than zero, then the actual size is
//     set to zero rather than to a negative value, and the growth rate is also
//     set to zero.
//
//   void assign_rate(double new_rate)
//     Postcondition: The organism's growth rate has been changed to new_rate
//     (measured in ounces per week).
//
//   void alter_size(double amount)
//     Postcondition: The given amount (in ounces) has been added to the
//     organism's current size. If this results in a new size less than zero,
//     then the actual size is set to zero rather than to a negative value, and
//     the growth rate is also set to zero.
//
//   void death( )
//      Postcondition: The organism's current size and growth rate have been
//      set to zero.
//
// CONSTANT MEMBER FUNCTIONS for the Organism class:
//   double get_size( ) const
//     Postcondition: The value returned is the organism's current size
//     (in ounces).
//
//   double get_rate( ) const
//     Postcondition: The value returned is the organism's current growth rate
//     (in oz/week).
//
//   bool is_alive( ) const
//     Postcondition: If the current size is greater than zero, then the return
//     value is true; otherwise the return value is false.
//
//
// DOCUMENTATION for the Plant class:
//   Plant is a derived class of the Organism class. All the Organism public
//   member functions are inherited by a Plant. In addition, a Plant has
//   these extra member functions:
//
// CONSTRUCTOR for the Plant class:
//   Plant(double init_size=0, double init_rate=0)
//     Same as the Organism constructor.
//
// MODIFICATION MEMBER FUNCTIONS for the Plant class:
//   void nibbled_on(double amount)
//     Precondition: 0 <= amount <= get_size( ).
//     Postcondition: The size of the plant has been reduced by amount.
//     If this reduces the size to zero, then death is activated.
//
//
// DOCUMENTATION for the Animal class:
//   Animal is a derived class of the Organism class. All the Organism public
//   member functions are inherited by an Animal. In addition, an Animal has
//   these extra member functions:
//
// CONSTRUCTOR for the Animal class:
//   Animal(double init_size=0, double init_rate=0, double init_need=0)
//     Precondition: init_size >= 0, and init_need >= 0. Also, if
//     init_size = 0, then init_rate is also zero.
//     Postcondition: The organism being simulated has been initialized. The
//     value returned from get_size( ) is now init_size (measured in ounces),
//     the value returned from get_rate( ) is now init_rate (measured in ounces
//     per week), and the animal must eat at least init_need ounces of food
//     each week to survive.
//
// MODIFICATION MEMBER FUNCTIONS for the Animal class:
//   void assign_need(double new_need)
//     Precondition: new_need >= 0.
//     Postcondition: The animal's weekly food requirement has been changed to
//     new_need (measured in ounces per week).
//
//   void eat(double amount)
//     Precondition: amount >= 0.
//     Postcondition: The given amount (in ounces) has been added to the amount
//     of food that the animal has eaten this week.
//
//   void simulate_week( ) -- overriden from the Organism class
//     Postcondition: The size of the organism has been changed by its current
//     growth rate. If the new size is less than zero, then the actual size is
//     set to zero rather than to a negative value, and the growth rate is also
//     set to zero. Also, if the animal has eaten less than its required need
//     over the past week, then death has been activated.
//
// CONSTANT MEMBER FUNCTIONS for the Animal class:
//   double still_need( ) const
//     Postcondition: The return value is the ounces of food that the animal
//     still needs to survive the current week (i.e., its total weekly need
//     minus the amount that it has already eaten this week.)
//
//   double total_need( ) const
//     Postcondition: The return value is the total amount of food that the
//     animal needs to survive one week (measured in ounces).
//   
//
// DOCUMENTATION for the Herbivore class:
//   Plant is a derived class of the Animal class. All the Animal public
//   member functions are inherited by a Herbivore. In addition, a Herbivore has
//   this extra member function:
//
// CONSTRUCTOR for the Herbivore class:
//   Herbivore(double init_size=0, double init_rate=0, double init_need=0)
//     Same as the Animal constructor.
//
// MODIFICATION MEMBER FUNCTIONS for the Herbivore class:
//   void nibble(Plant& meal)
//   Postcondition: eat(amount) and meal.nibbled_on(amount) have both been
//   activated. The amount is usually half of the plant, but it will never be
//   more than 10% of the herbivore's weekly need, nor more than the amount that
//   the animal still needs to eat to survive this week.
//
//
// VALUE SEMANTICS for the Organism class and its derived classes:
//    Assignments and the copy constructor may be used with all objects.

#ifndef ORGANISM_H
#define ORGANISM_H

class Organism {
  public:
    Organism(double init_size = 1, double init_rate = 0);
    virtual void simulate_week( ) {
      alter_size(rate); }
    void assign_rate(double new_rate) {
      rate = new_rate; }
    void alter_size(double amount);
    void death( );
    double get_size( ) const {
      return size; }
    double get_rate( ) const {
      return rate; }
    bool is_alive( ) const {
      return (size > 0); }
  private:
    double size;
    double rate;
};

class Plant : public Organism {
  public:
    Plant(double init_size = 1, double init_rate = 0);
    void nibbled_on(double amount);
};

class Animal : public Organism {
  public:
    Animal(double init_size = 1, double init_rate = 0, double init_need = 0);
    void assign_need(double new_need);
    void eat(double amount);
    virtual void simulate_week( );
    double still_need( ) const;
    double total_need( ) const {
      return need_each_week; }
  private:
    double need_each_week;
    double eaten_this_week;
};

class Herbivore : public Animal {
  public:
    Herbivore(double init_size = 1, double init_rate = 0, double init_need = 0);
    void nibble(Plant& meal);
};

#endif