##############################
# mmkn.tcl                   #
# written by Michael Savoric #
##############################
#        date: 31.05.2001    #
# last update: 01.06.2001    #
##############################

#
# define the parameters of the M/M/k/n-queueing system:
#

set k 1
set n 0

set lambda 8
set mu 50

#
# define the end of the simulation:
#

set sim_end_time 1000.0

#
# define the array of state dwell times of the queueing system:
#

if {$n == 0} {
  set maximum_state 50
} else {
  set maximum_state $n
}

# the state dwell time of the state maximum_state collects all dwell times
# of those states which are equal to or greater than maximum_state

for {set index 0} {$index <= $maximum_state} {incr index} {
  set state_time($index) 0.0
}

#
# define the current state (= the number of customers) of the queueing system:
#

set current_state 0

#
# define some variables for the statistical evaluation of the queueing system:
#

set customer_arrivals 0
set customer_services 0
set customer_blocks 0

#
# define the pseudo-random number-generator (PRNG):
#

global rng

set rng [new RNG]

#
# choose a random seed for the PRNG:
#

$rng seed 0

#
# generate the simulator:
#

set ns [new Simulator]

#
# define the simulation run:
#

set current_sim_time 0.0

set last_state_transition_time $current_sim_time

$ns at $current_sim_time {
  $ns at [expr $current_sim_time+[$rng exponential 1.0/$lambda]] {
     customer_arrival [$ns now]
  }   
}

proc customer_arrival {time} {
  global ns rng \
         k n lambda mu \
         customer_arrivals customer_blocks \
         maximum_state current_state state_time last_state_transition_time

  incr customer_arrivals

  if {$n > 0} {
    if {$current_state < $n} {
      set state_time($current_state) \
        [expr $state_time($current_state)+$time-$last_state_transition_time]

      set last_state_transition_time $time

      incr current_state

      if {$current_state <= $k} {
        $ns at [expr $time+[$rng exponential 1.0/$mu]] {
          customer_service [$ns now]
        }
      }
    } else {
      incr customer_blocks
    }
  } else {
    if {$current_state < $maximum_state} {
      set state_time($current_state) \
        [expr $state_time($current_state)+$time-$last_state_transition_time]

      set last_state_transition_time $time

      incr current_state
    } else {
      set state_time($maximum_state) \
        [expr $state_time($maximum_state)+$time-$last_state_transition_time]

      set last_state_transition_time $time

      incr current_state
    }
    if {$current_state <= $k} {
      $ns at [expr $time+[$rng exponential 1.0/$mu]] {
        customer_service [$ns now]
      }
    }
  }

  $ns at [expr $time+[$rng exponential 1.0/$lambda]] {
    customer_arrival [$ns now]
  }
}

proc customer_service {time} {
  global ns rng \
         k mu \
         customer_services \
         maximum_state current_state state_time last_state_transition_time

  incr customer_services

  if {$current_state < $maximum_state} {
    set state_time($current_state) \
      [expr $state_time($current_state)+$time-$last_state_transition_time]
  } else {
    set state_time($maximum_state) \
      [expr $state_time($maximum_state)+$time-$last_state_transition_time]
  }

  set last_state_transition_time $time

  incr current_state -1

  if {$current_state >= $k} {
    $ns at [expr $time+[$rng exponential 1.0/$mu]] {
      customer_service [$ns now]
    }
  }
}

#
# end of the simulation:
#

$ns at $sim_end_time {
  puts "Beende die Simulation."

  puts "\nSimulationsergebnis:"
  puts "--------------------\n"

  if {$sim_end_time > 0.0} {
    for {set index 0} {$index <= $maximum_state} {incr index} {
      puts [format "Zustand = %3d: Zeit = %12.6lf ZE, p = %7.5lf" \
            $index $state_time($index) [expr $state_time($index)/$sim_end_time]]
    }
  }

  if {$sim_end_time > 0.0} {
    set mean_customers 0.0

    for {set index 0} {$index <= $maximum_state} {incr index} {
      set mean_customers \
       [expr $mean_customers+$index*$state_time($index)/$sim_end_time]
    }

    puts [format "\nmittlere Anzahl der Kunden = %9.5lf" $mean_customers]
  }

  if {$customer_arrivals > 0} {
    puts ""

    puts [format "Angekommene Kunden = %5d" $customer_arrivals]

    puts [format "   Bediente Kunden = %5d" $customer_services]

    puts [format " Blockierte Kunden = %5d (p = %6.4lf)" \
          $customer_blocks [expr 1.0*$customer_blocks/$customer_arrivals]]
  }

  puts [format "\n Simulationszeit: %s\n" \
        [clock format [expr [clock seconds]-$sim_start_time] \
               -format "%H Stunde(n), %M Minute(n), %S Sekunde(n)" -gmt true]]

  puts [format "Simulationsdatum: %s\n" [clock format [clock seconds]]]

  finish
}

proc finish {} {
  global ns

  exit 0
}

#
# start of the simulation:
#

puts "\nSimulation eines M/M/K/N-Warteschlangensystems"
puts "==============================================\n"

puts [format "K = %3d" $k]

if {$n == 0} {
  set hint "(= unendlich)"
} else {
  set hint ""
}

puts [format "N = %3d %s" $n $hint]

puts ""

puts [format "Lambda = %6.2lf" $lambda]

puts [format "    Mu = %6.2lf" $mu]

puts [format "\nSimulierte Zeit = %12.6lf ZE (Zeiteinheiten)" $sim_end_time]
 
puts "\nStarte die Simulation."

puts "\nSimulation laeuft ...\n"

set sim_start_time [clock seconds]

$ns run


