
#ifdef GNU
#define std
#include <iostream.h>
#else
#include <iostream>
#endif

#include "Scheduler.h"
#include <algorithm>


Scheduler::Scheduler( )
{
}
  
Scheduler::~Scheduler()
{
}

void 
Scheduler::AddCage( const Cage& cage )
{
  cages_.push_back( cage );
}


//  Schedule an animal, assuming it is not already in the schedule.
//
Scheduler::Status
Scheduler::Schedule( Animal& animal )
{
  bool in_weight_range=false;
  bool in_schedule=false;

  //  Take the first empty cage the animal fits in.  Keep track of
  //  whether it fit into any cage.
  //
  
  //*********ADD CODE HERE**********

  // Save the animal on the scheduled list or the waiting list, as
  // appropriate.
  //
  if ( in_schedule ) {
    scheduled_.push_back( animal );
    return SCHEDULED;
  }
  else if ( in_weight_range ) {
    waiting_.push_back( animal );
    return WAITING_LIST;
  }
  else {
    return NO_FIT;
  }
}


//  Cancel an animal from the schedule or from the waiting list.
//
void
Scheduler::Cancel( const std::string& name,
		   std::list<Animal>& added )
{
  // Use standard library find algorithm to test first the scheduled
  // list and second the waiting list.  If the animal is removed from
  // the schedule, try waiting animals.
  //
  std::list<Animal>::iterator p =
	  std::find( scheduled_.begin(), scheduled_.end(), name );
  if ( p != scheduled_.end() ) {
    int was_in_cage = (*p).GetCage();
    cages_[was_in_cage].Cancel( *p );
    scheduled_.erase(p);
    TryFromWaitList( was_in_cage, added );
  }
  else {
    waiting_.remove( name );
  }
}


// Determine where an animal is in the schedule, if at all.  Set the
// status and fill in the details.
//
bool
Scheduler::InSchedule( const std::string& name,
		       Scheduler::Status& status,
		       Animal& animal )
{
  std::list<Animal>::iterator p = 
	  std::find( scheduled_.begin(), scheduled_.end(), name );
  if ( p != scheduled_.end() ) {
    animal = *p;
    status = SCHEDULED;
    return true;
  }
  else if ( (p = std::find(waiting_.begin(), waiting_.end(), name))
	    != waiting_.end() ) {
    animal = *p;
    status = WAITING_LIST;
    return true;
  }
  else
    return false;
}


//  Change an animal's schedule if possible.  If it can be changed,
//  try animals from the waiting list.  If it can't, don't remove it
//  from the current position in the schedule.
//
bool
Scheduler::Change( const std::string& name,
		   const Date& new_start,
		   int new_days,
		   std::list<Animal>& added)
{
  //  Find the animal in the schedule, temporarily remove it, and try
  //  to reschedule.
  //
  std::list<Animal>::iterator p = 
	  std::find( scheduled_.begin(), scheduled_.end(), name );
  if ( p != scheduled_.end() ) {
    Animal old_animal( *p );
    int old_cage = old_animal.GetCage(); 
    cages_[old_cage].Cancel( old_animal );  //  remove from cage
    Animal new_animal( name, old_animal.Weight(), new_start, new_days );
    scheduled_.erase( p );              // remove from scheduled animals
    bool in_schedule=false;
    for ( int c=0; c<cages_.size() && !in_schedule; c++ ) {
      if ( cages_[c].InWeightRange( new_animal ) &&
	   cages_[c].Schedule( new_animal ) ) {
	new_animal.AssignCage( c );
        scheduled_.push_back( new_animal );
	in_schedule = true;
      }
    }
    
    //  If it could be changed, try waiting animals (if any of the
    //  days it was previously scheduled are now free).  Otherwise,
    //  put it back in the schedule.
    //
    if ( in_schedule ) {
       //********ADD CODE FOR CHECKING IN WAITING LIST ************
      return true;
    }
    else {
       // *****ADD CODE FOR RESTORING OLD VALUES***********
      return false;
    }
  }
  return false;
}


//  Print the schedule for the given day.
//
void
Scheduler::OutputSchedule( std::ostream& out_str,
			 const Date& day )
{
  std::cout << "\nSchedule for " << day << std::endl;
  for ( int c=0; c<cages_.size(); c++ ) {
    Animal animal;
    if ( cages_[c].OnDay(day, animal) ) 
      std::cout << "  " << c << ": " << animal.Name() << std::endl;
    else
      std::cout << "  " << c << ": _____ " << std::endl;
  }
}


//  Test animals from the waiting list for the given cage.  Do this in
//  order.  It might be that more than one can be accommodated.
//  Return the list of animals moved from the waiting list to the schedule.
//
void
Scheduler::TryFromWaitList( int cage_num,
			    std::list<Animal> & added )
{
  added.erase(added.begin(), added.end());
  std::list<Animal>::iterator p = waiting_.begin();
  while ( p != waiting_.end() ) {
     //*****ADD CODE HERE*********
  }
}

