/** Time.cpp -- implements the Time member functions **/

#include "Time.h"
#include <cassert>
using namespace std;

//----- Function to implement the explicit-value  constructor -----

/*** Utility Functions -- Prototypes ***/

int ToMilitary(unsigned hours, unsigned minutes, char am_pm);

void ToStandard(unsigned military,
                unsigned & hours, unsigned & minutes, char & AMPM);

Time::Time(unsigned initHours, unsigned initMinutes, char initAMPM)
{
  // Check class invariant
  assert(initHours >= 1 && initHours <= 12 && 
         initMinutes >= 0 && initMinutes <= 59 &&
         (initAMPM == 'A' || initAMPM == 'P'));

  myHours = initHours;
  myMinutes = initMinutes;
  myAMorPM = initAMPM;
  myMilTime = ToMilitary(initHours, initMinutes, initAMPM);
}

//----- Function to implement the Set operation -----

void Time::Set(unsigned hours, unsigned minutes, char am_pm)
{ 
  // Check class invariant
  if (hours >= 1 && hours <= 12 && 
      minutes >= 0 && minutes <= 59 && 
      (am_pm == 'A' || am_pm == 'P'))
  {
    myHours = hours;
    myMinutes = minutes;
    myAMorPM = am_pm;
    myMilTime = ToMilitary(hours, minutes, am_pm);
  }
  else
    cout << "*** Can't set time with these values ***\n";
    // Object's data members remain unchanged
}

//----- Function to implement ostream output -----

ostream & operator<<(ostream & out, const Time & t)
{
  out << t.myHours << ':'
      << (t.myMinutes < 10 ? "0" : "") << t.myMinutes
      << ' ' << t.myAMorPM << ".M.  ("
      << t.myMilTime << " mil. time)";

  return out;
}

//----- Function to implement istream input -----

istream & operator>>(istream & in, Time & t)
{
   char ch;    // gobble up separators

   in >> t.myHours >> ch >> t.myMinutes >> t.myAMorPM>> ch;

   // Check the class myHours
   assert(t.myHours >= 1 && t.myHours <= 12 && 
          t.myMinutes >= 0 && t.myMinutes <= 59 &&
          (t.myAMorPM == 'A' || t.myAMorPM == 'P'));
   t.myMilTime = ToMilitary(t.myHours, t.myMinutes, t.myAMorPM);
   return in;
}

//----- Function to implement Advance() -----

void Time::Advance(unsigned hours, unsigned minutes)
{
  // Increment the myMilTime member
  myMilTime += 100 * hours + minutes;

  // Adjust to proper format
  unsigned  milHours = myMilTime / 100,
            milMins = myMilTime % 100;
  milHours +=  milMins / 60;
  milMins %= 60;
  milHours %= 24;
  myMilTime = 100 * milHours + milMins;

  // Now set the standard time data members
  ToStandard(myMilTime, myHours, myMinutes, myAMorPM);
}

// ToStandard() is the utility function we used in our "procedural" 
// implementation of Time in Figure 2.2  We add its declaration 
// and definition to Time.cpp.

/*** Utility Functions -- Definitions ***/

/* ToMilitary converts standard time to military time.
 *
 *  Receive: hours, minutes, am_pm
 *  Return:  The military time equivalent
 ********************************************************/

int ToMilitary (unsigned hours, unsigned minutes, char am_pm)
{
  if (hours == 12)
    hours = 0;

  return hours * 100 + minutes + (am_pm == 'P' ? 1200 : 0);
}

/*-----------------------------------------------------------------
 ToStandard converts military time to standard time.

  Receive: military, a time in military format
  Return:  hours, minutes, AMPM -- equivalent standard time
-------------------------------------------------------------------*/

void ToStandard(unsigned military,
                unsigned & hours, unsigned & minutes, char & AMPM)
{
  hours = (military / 100) % 12;
  if (hours == 0)
     hours = 12;
  minutes = military % 100;
  AMPM = (military / 100) < 12 ? 'A' : 'P';
}

