// File: prg8_3.cpp
// the program uses a queue to simulate the flow of customers
// in and out of an automated car wash. prompt the user for the
// fixed probability that a car will arrive at any minute of the
// day and the fixed number of minutes it takes for a
// car wash. also input the opening and closing times. the
// simulation steps from opening to closing time in increments
// of 1 minute. each iteration determines if a car arrives and,
// if so pushes the time of arrival in the queue of waiting
// customers. next, determine whether the car wash is busy. if
// it is avaiable, pop the longest waiting customer from the
// queue and update simulation parameters. when the simulation
// loop terminates, output the accumuated parameters, that
// include the total number of cars washed, the maximum waiting
// time for a customer, the average customer waiting time, the
// percentage of the day the car wash operates, and the number
// of customers remaining to serve when the car wash closes

#include <iostream>
#include <queue>

#include "time24.h"
#include "random.h"

using namespace std;

// returns the time t in minutes
int Minutes(const Time24& t);

int main()
{
   Time24 carArrival;                   // stores time of customer's arrival
   queue<Time24> waitQueue;             // queue for car arrival objects

   Time24 waitTime, maxWaitTime;        // maxWaitTime initially 0:00
   Time24 totalWaitTime;                // total time customers wait                     
   Time24 totalServiceTime;             // total time equipment is in use
   Time24 startTime, endTime;           // times for the simulation
   Time24 t, finishWash;                // used in simulation loop

   RandomNumber rnd;                    // use for random number generation

   double probOfArrival;                // probability customer arrives
   int numberOfWashes = 0;              // number of cars washed in study
   int washTime;                        // fixed time for a wash in minutes

   bool washAvailable = true;           // indicates whether wash available

   // real number output is fixed format, with 1 decimal place
   cout.setf(ios::fixed, ios::floatfield);
   cout.precision(1);

   // series of inputs to customize the simulation run
   cout << "Enter probability of arrival and wash time: ";
   cin >> probOfArrival >> washTime;
   cout << "Enter time to start and end simulation: ";
   cin >> startTime >> endTime;
   cout << endl;

   // loop views and updates system each minute of the study
   for (t = startTime; t < endTime; t += 1)
   {  
      // check if customer arrives; if so store arrival time in queue
      if(rnd.frandom() <= probOfArrival)
      {
         carArrival = t; 
         waitQueue.push(carArrival);
      }

      // if car finishes wash, indicate wash is available
      if (!washAvailable && t == finishWash)
         washAvailable = true;

      // if wash is available, get front car from queue
      if ((washAvailable) && (!waitQueue.empty()))
      {
         // pop next car from queue and update data for summary
         carArrival = waitQueue.front();
         waitQueue.pop();
         
         // find the waiting time of the next customer
         waitTime = t - carArrival;
         // update the maximum customer waiting time
         if (maxWaitTime  < waitTime)
            maxWaitTime = waitTime;
         // add waiting time for customer to totalWaitTime.
         totalWaitTime += waitTime;
         // add time to wash car to totalServiceTime for the equipment
         totalServiceTime += washTime;
         // determine the time the car will exit from the wash
         finishWash = t + washTime;
         // increment the number of customers served
         numberOfWashes++;
         // set washAvailable to false since equipment back in service
         washAvailable  = false;
      }
   }

   // output the summary data for the simulation include number of cars
   // washed, average customer waiting time and pct of time wash operates
   cout << "Total number of cars washed is " << numberOfWashes << endl;
   cout << "Maximum customer waiting time for a car wash is " 
        << Minutes(maxWaitTime) << " minutes" << endl;
   cout << "Average customer waiting time for a car wash is " 
        << double(Minutes(totalWaitTime))/numberOfWashes << " minutes"
        << endl;
   cout << "Percentage of time car wash operates is  " 
        << double(Minutes(totalServiceTime))/Minutes(endTime-startTime)*100.0
        << '%' << endl;
   cout << "Number of customers remaining at " << endTime 
        << " is " << waitQueue.size() << endl;

   return 0;
}

int Minutes(const Time24& t)
{
   return t.GetHour() * 60 + t.GetMinute();
}
