// supermarket.h: defines the class Sim, used to create one object "sim".
//
// The object sim is declared here for inclusion everywhere, but defined
// and initialized in main.C. It carries global variables and constants
// used throughout the simulation.
// (modified)

#ifndef _SUPERMARKET_H
#define _SUPERMARKET_H

#include "random.h"
#include "stats.h"
#include "custqueue.h"
#include "cashierstand.h"
#include "evlist.h"

class SupermarketSim {
private:

   // Simulation constants:
   // demand: maximum amount of items needed by a customer
   // See Cust constructor.
   static const double itemsBoughtMax;
   
   // service times: constant base time + time per item 
   // See Cashier.serviceTime().
   static const double serviceTimeBase;

   // time to scan and put in package (per item)
   static const double serviceTimePerItem;
   
   // Total number of cashiers in simulation
   static const int cashierCount;

   // maximum number of items allowed in express cashier
   int maxExpressItems;

   // proportion of customers that go to express cashier
   double proportExpressCust; 

   double simulationTime; // Current simulation time
   double endingTime;
   bool simulating; // set to false by end-of-simulation event

   // customer arrival rate
   // See ArrivalEvent.interarrivalTime().
   double meanInterarrivalTime; // seconds

   double reportInterval; // How often should we report?
      
   // random-number streams used to model the world
   Random arrivalStream; // auto arrival times
   Random itemsStream; // number of items needed
   
   // major data structures
   EventList eventList;
   CashierStand cashierStand;
   Statistics stats;
   
public:
   SupermarketSim( double repInterval,
		   double endTime,
		   double meanInterArrTime,
		   unsigned long custArrSeed,
		   unsigned long itemsSeed,
		   int numExpCashiers,
		   int maxExpItems,
		   double expCustRatio ) :
      maxExpressItems( maxExpItems ), proportExpressCust( expCustRatio ),
      simulationTime( 0 ), endingTime( endTime ), simulating( false ),
      meanInterarrivalTime( meanInterArrTime ),
      reportInterval( repInterval ), 
      arrivalStream( custArrSeed ), itemsStream( itemsSeed ),
      cashierStand( numExpCashiers, cashierCount - numExpCashiers ) {}

   // Accessor functions
   int getTotalCashierCount() const { return cashierCount; }
   double getTime() const { return simulationTime; }
   double getServiceTimeBase() const { return serviceTimeBase; }
   int getMaxExpressItems() const { return maxExpressItems; }
   double getMeanInterarrivalTime() const { return meanInterarrivalTime; }
   double getReportInterval() const { return reportInterval; }
   
   void insertEvent( Event *event ) { eventList.insert( event ); }

   void sendCustomerToCashierStand( Cust *customer )
   { cashierStand.sendCustomerToCashier( customer ); }

   void addWaitingTime( double time ) { stats.accumWaitingTime( time ); }
   void addServiceTime( double time ) { stats.accumServiceTime( time ); }
   void addItemsSold( int count ) { stats.accumSale( count ); }
   void newCustomerArrival() { stats.countArrival(); }

   void statSnapshot() { stats.snapshot(); }

   // Start/stop simulation
   void start();
   void stop() { simulating = false; }
};

extern SupermarketSim *sim;

#endif
