//==================================================== file = callcenter.c =====
//=  A CSIM simulation of a call center                                        =
//==============================================================================
//=  Notes: Adapted from H. Schwetman, "CSIM17: A Simulation Model-Building    =
//=         Toolkit," Proceedings of the 1994 Winter Simulation Conference,    =
//=         pp. 464 - 470, 1994.                                               =
//=----------------------------------------------------------------------------=
//=  Execution: usage by executing "callcenter":                               =
//=                                                                            =
//=      Usage is: 'callcenter a1 a2 a3 a4 a5 a6 a7 a8' where:                 =
//=                  - a1 = Simulation time in hours                           =
//=                  - a2 = Call rate in calls per minute                      =
//=                  - a3 = Service time in seconds                            =
//=                  - a4 = Maximum ring time in seconds                       =
//=                  - a5 = Maximum hold time in seconds                       =
//=                  - a6 = Number of lines                                    =
//=                  - a7 = Number of ports                                    =
//=                  - a8 = Nmber of operators                                 =
//=                                                                            =
//=  Example execution for "callcenter 1000 10 60 30 30 10 10 10":             =
//=                                                                            =
//=      Program is running...                                                 =
//=      =============================================================         =
//=      ==       >>>>> CSIM call center simulation <<<<<           ==         =
//=      =============================================================         =
//=      =  Call arrival rate    = 10.000 calls/min                            =
//=      =  Cust max ring time   = 30.000 sec                                  =
//=      =  Cust max hold time   = 30.000 sec                                  =
//=      =  Cust service time    = 60.000 sec                                  =
//=      =  Simulation time      = 1000.000 hours                              =
//=      =  Number of lines      = 10                                          =
//=      =  Number of ports      = 10                                          =
//=      =  Number of operators  = 10                                          =
//=      =============================================================         =
//=      =  CPU time             =  1.219 sec                                  =
//=      =============================================================         =
//=      =  Operator utilization = 78.616 %                                    =
//=      =  Total calls          = 600908                                      =
//=      =  Successful calls     = 472052                                      =
//=      =  Blocked calls        = 128850                                      =
//=      =  Port balks           = 0                                           =
//=      =  Operator balks       = 0                                           =
//=      =  Calls in progress    = 6                                           =
//=      =  Success percentage   = 78.556 %                                    =
//=      =============================================================         =
//=----------------------------------------------------------------------------=
//=  History:   KJC (04/14/99) - Genesis                                       =
//=             KJC (11/14/04) - Cleaned-up                                    =
//==============================================================================
//----- Includes ---------------------------------------------------------------
#include <stdio.h>              // Needed for printf()
#include <stdlib.h>             // Needed for atoi(), atof(), and exit()
#include "csim.h"               // Needed for CSIM18 stuff

//----- Globals ----------------------------------------------------------------
STORE    Line;                  // Lines to be allocated and de-allocated
STORE    Port;                  // Ports to be allocated
FACILITY Operator;              // Operators to be reserved and released
double   SimTime;               // Simulation run time
double   CallRate;              // Mean arrival rate of calls per second
double   ServTime;              // Customer service time in seconds
double   MaxHold;               // Maximum customer hold time in seconds
double   MaxRing;               // Maximum customer ring time in seconds
int      NumAct;                // Number of actual calls in gen()
int      NumCalls;              // Number of calls in call()
int      NumSuccessCalls;       // Number of successful calls
int      NumOperatorBalks;      // Number of Operator balks
int      NumPortBalks;          // Number of Port balks
int      NumBusySignals;        // Number of busy signals

//----- Prototypes -------------------------------------------------------------
void gen(void);                 // Generate Poisson calls
void call(void);                // Process calls

//===============================================================================
//==  Main program                                                             ==
//===============================================================================
void sim(int argc, char *argv[])
{
  int  numLines;               // Number of lines
  int  numPorts;               // Number of ports
  int  numOperators;           // Number of operators

  // Create the main simulation process
  create("sim");

  // Describe usage if insufficient command line paramters
  if (argc != 9)
  {
    printf("  Usage is: 'callcenter a1 a2 a3 a4 a5 a6 a7 a8' where:        \n");
    printf("              - a1 = Simulation time in hours                  \n");
    printf("              - a2 = Call rate in calls per minute             \n");
    printf("              - a3 = Service time in seconds                   \n");
    printf("              - a4 = Maximum ring time in seconds              \n");
    printf("              - a5 = Maximum hold time in seconds              \n");
    printf("              - a6 = Number of lines                           \n");
    printf("              - a7 = Number of ports                           \n");
    printf("              - a8 = Nmber of operators                        \n");
    exit(1);
  }

  // Initialize simulation parameters from command line arguments
  SimTime = atof(argv[1]) * 3600.0;
  CallRate = atof(argv[2]) / 60.0;
  ServTime = atof(argv[3]);
  MaxRing = atof(argv[4]);
  MaxHold = atof(argv[5]);
  numLines = atoi(argv[6]);
  numPorts = atoi(argv[7]);
  numOperators = atoi(argv[8]);

  // Initialize CSIM objects
  Line = storage("lines", numLines);
  Port = storage("ports", numPorts);
  Operator = facility_ms("Operators", numOperators);

  // Reset all counters
  NumCalls = NumSuccessCalls = NumOperatorBalks = NumPortBalks = 0;
  NumBusySignals = 0;

  // Output a program is running banner
  printf("Program is running... \n");

  // Initiate the generate process and hold for SimTime
  gen();
  hold(SimTime);

  // Retrieve, compute, and output results
  printf("============================================================= \n");
  printf("==       >>>>> CSIM call center simulation <<<<<           == \n");
  printf("============================================================= \n");
  printf("=  Call arrival rate    = %6.3f calls/min \n", 60.0 * CallRate);
  printf("=  Cust max ring time   = %6.3f sec       \n", MaxRing);
  printf("=  Cust max hold time   = %6.3f sec       \n", MaxHold);
  printf("=  Cust service time    = %6.3f sec       \n", ServTime);
  printf("=  Simulation time      = %6.3f hours     \n", SimTime / 3600.0);
  printf("=  Number of lines      = %d              \n", numLines);
  printf("=  Number of ports      = %d              \n", numPorts);
  printf("=  Number of operators  = %d              \n", numOperators);
  printf("============================================================= \n");
  printf("=  CPU time             = %6.3f sec       \n", cputime());
  printf("============================================================= \n");
  printf("=  Operator utilization = %6.3f %% \n",
    100.0 * util(Operator) / numOperators);
  printf("=  Total calls          = %d       \n", NumCalls);
  printf("=  Successful calls     = %d       \n", NumSuccessCalls);
  printf("=  Blocked calls        = %d       \n", NumBusySignals);
  printf("=  Port balks           = %d       \n", NumPortBalks);
  printf("=  Operator balks       = %d       \n", NumOperatorBalks);
  printf("=  Calls in progress    = %d       \n", (numLines - avail(Line)));
  printf("=  Success percentage   = %6.3f %% \n",
    100.0 * ((double) NumSuccessCalls / NumCalls));
  printf("============================================================= \n");
}

//===============================================================================
//==  Function to generate Poisson calls                                       ==
//===============================================================================
void gen(void)
{
  create("gen");

  // Loop to create Poisson calls
  while(1)
  {
    call();
    hold(expntl(1.0 / CallRate));
  }
}

//===============================================================================
//==  Function to process calls                                                ==
//===============================================================================
void call(void)
{
  int    portStatus;           // Timed allocated status for port
  int    operStatus;           // Timed reserve status for operator
  double waitTime;             // Computed wait time

  create("call");

  // Increment the number of incoming calls
  NumCalls++;

  // Allocate a line if one is available (else a busy signal)
  if(avail(Line) > 0)
  {
    allocate(1, Line);

    // Timed wait for a port (else a port balk)
    waitTime = uniform(0.0, MaxRing);
    portStatus = timed_allocate(1, Port, waitTime);
    if (portStatus != TIMED_OUT)
    {
      // Timed wait for an operator (else an operator balk)
      waitTime = uniform(0.0, MaxHold);
      operStatus = timed_reserve(Operator, waitTime);
      if (operStatus != TIMED_OUT)
      {
        hold(expntl(ServTime));
        release(Operator);
        NumSuccessCalls++;
      }
      else
      {
        NumOperatorBalks++;
      }

      deallocate(1, Port);
    }
    else
    {
      NumPortBalks++;
    }

    deallocate(1, Line);
  }
  else
  {
    NumBusySignals++;
  }
}

