//================================================== file = callCenter.c =====
//=  A CSIM18 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: callCenter a1 a2 a3 a4 a5 a6 a7 a8                           =
//=              - a1 = Simulation time in hours                             =
//=              - a2 = Call_rate in calls per minute                        =
//=              - a3 = Serv_time service time in seconds                    =
//=              - a4 = Max_ring maximum ring time in seconds                =
//=              - a5 = Max_hold maximum hold time in seconds                =
//=              - a6 = Num_lines number of lines                            =
//=              - a7 = Num_ports number of ports                            =
//=              - a8 = Num_operators number of operators                    =
//=--------------------------------------------------------------------------=
//=  Build: Standard CSIM build                                              =
//=--------------------------------------------------------------------------=
//=  History: KJC (04/14/99) - Genesis                                       =
//=           KJC (06/12/09) - Cosmestic clean-up                            =
//=           KJC (06/24/09) - Changed output format and ordering            =
//============================================================================
//----- Includes --------------------------------------------------------------
#include <stdio.h>              // Needed for printf()
#include <stdlib.h>             // Needed for atol() and atof()
#include "csim.h"               // Needed for CSIM 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   Sim_time;              // Simulation run time
double   Call_rate;             // Mean arrival rate of calls per second
double   Serv_time;             // Customer service time in seconds
double   Max_hold;              // Maximum customer hold time in seconds
double   Max_ring;              // Maximum customer ring time in seconds
long int Num_act;               // Number of actual calls in gen()
long int Num_calls;             // Number of calls in call()
long int Successful_calls;      // Number of successful calls
long int Operator_balks;        // Number of Operator balks
long int Port_balks;            // Number of Port balks
long int Busy_signals;          // Number of busy signals

//----- Prototypes ------------------------------------------------------------
void gen(void);         // Generate Poisson calls
void call(void);        // Process calls

//=============================================================================
//==  Main program                                                           ==
//=============================================================================
void sim(int argc, char *argv[])
{
  long int  num_lines;          // Number of lines
  long int  num_ports;          // Number of ports
  long int  num_operators;      // Number of operators

  // Check if enough arguments
  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 = Serv_time service time in seconds        \n");
    printf("              - a4 = Max_ring maximum ring time in seconds    \n");
    printf("              - a5 = Max_hold maximum hold time in seconds    \n");
    printf("              - a6 = Num_lines number of lines                \n");
    printf("              - a7 = Num_ports number of ports                \n");
    printf("              - a8 = Num_operators number of operators        \n");
    exit(1);
  }

  // Intialize operational parameters from command line entries
  Sim_time  = atof(argv[1]) * 3600.0;
  Call_rate = atof(argv[2]) * (1.0 / 60.0);
  Serv_time = atof(argv[3]);
  Max_ring  = atof(argv[4]);
  Max_hold  = atof(argv[5]);
  num_lines = atol(argv[6]);
  num_ports = atol(argv[7]);
  num_operators = atol(argv[8]);

  // Create the simulation
  create("sim");

  // Initialize CSIM stuff
  Line = storage("line", num_lines);
  Port = storage("port", num_ports);
  Operator = facility_ms("Operator", num_operators);

  // Reset all global counters
  Num_calls = Successful_calls = Operator_balks = Port_balks = Busy_signals = 0;

  // Output begin-of-simulation banner
  printf("*** BEGIN SIMULATION *** \n");

  // Initiate gen() and hold for Sim_time
  gen();
  hold(Sim_time);

  // Output results
  printf("============================================================= \n");
  printf("==      >>>>> CSIM18 call center simulation <<<<<          == \n");
  printf("============================================================= \n");
  printf("=  Simulation time      = %6.3f hours     \n", Sim_time / 3600.0);
  printf("=  Call arrival rate    = %6.3f calls/min \n", 60.0 * Call_rate);
  printf("=  Call service time    = %6.3f sec       \n", Serv_time);
  printf("=  Cust max ring time   = %6.3f sec       \n", Max_ring);
  printf("=  Cust max hold time   = %6.3f sec       \n", Max_hold);
  printf("=  Number of lines      = %ld             \n", num_lines);
  printf("=  Number of ports      = %ld             \n", num_ports);
  printf("=  Number of operators  = %ld             \n", num_operators);
  printf("============================================================= \n");
  printf("=  CPU time             = %6.3f sec       \n", cputime());
  printf("============================================================= \n");
  printf("&1 Success percentage   = %6.3f %% \n",
    100.0 * ((double) Successful_calls / Num_calls));
  printf("&2 Operator utilization = %6.3f %% \n",
    100.0 * util(Operator) / num_operators);
  printf("=  Total calls          = %ld \n", Num_calls);
  printf("=  Successful calls     = %ld \n", Successful_calls);
  printf("=  Blocked calls        = %ld \n", Busy_signals);
  printf("=  Port balks           = %ld \n", Port_balks);
  printf("=  Operator balks       = %ld \n", Operator_balks);
  printf("=  Calls in progress    = %ld \n", (num_lines - avail(Line)));
  printf("============================================================= \n");

  // Output end-of-simulation banner
  printf("*** END SIMULATION *** \n");
}

//=============================================================================
//==  Function to generate Poisson calls                                     ==
//=============================================================================
void gen(void)
{
  create("gen");

  // Loop to create Poisson calls
  while(1)
  {
    call();
    hold(expntl(1.0 / Call_rate));
  }
}

//=============================================================================
//==  Function to process calls                                              ==
//=============================================================================
void call(void)
{
  long int port_status;         // Timed allocated status for port
  long int oper_status;         // Timed reserve status for operator
  double   wait_time;           // Computed wait time

  create("call");

  // Increment the number of incoming calls
  Num_calls++;

  // 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) -- ringing
    wait_time = uniform(0.0, Max_ring);
    port_status = timed_allocate(1, Port, wait_time);
    if (port_status != TIMED_OUT)
    {
      // Timed wait for an operator (else an operator balk) -- hold music
      wait_time = uniform(0.0, Max_hold);
      oper_status = timed_reserve(Operator, wait_time);
      if (oper_status != TIMED_OUT)
      {
        hold(expntl(Serv_time));
        release(Operator);
        Successful_calls++;
      }
      else
        Operator_balks++;

      deallocate(1, Port);
    }
    else
      Port_balks++;

    deallocate(1, Line);
  }
  else
    Busy_signals++;
}

