function Sts = simulate_server(max_time)
   st = initial_state();
   Sts = [st];
   while !stop(Sts(end), max_time)
	   st = update(st);
	   Sts = [Sts, st];
   end
end

function st = initial_state()
   st.tm_stamp = 0;
   st.srv_time = +inf;              % not applicable
   st.next_arr = next_arrival();
   st.n_accept = 0;
   st.n_reject = 0; 
   st.usd_time = 0; 
   printf("starting at %6.2f; next arrival at %6.2f\n", 
         0, st.next_arr);
end

function st1 = update(st0)
   if       st0.srv_time == inf           % server is empty    
      st1 = arrival_event(st0);    % a  dequeue event  
   elseif   st0.srv_time < st0.next_arr   % a service ends before arrival  
      st1 = serviced_event(st0);   % a serviced event  
   elseif   st0.srv_time < inf && ...                   % buffer is full
            st0.srv_time > st0.next_arr   % the service ends after arrival
      st1 = reject_event(st0);     % a reject event
   else
      printf("error - unclear transition in state:\n")
      st1 = st0
      st1.tm_stamp = + inf;
   end;
end

function st1 = reject_event(st0)
   st1 = st0;
   t0 = st0.tm_stamp;
   t1 = st0.next_arr;
   st1.tm_stamp = t1;
   st1.next_arr = t1 + next_arrival();    % next arrival time is computed
   st1.n_reject = st0.n_reject + 1;  	   % increase rejected requests
   printf("rejected at %6.2f: busy until %6.2f; next arrival \
at %6.2f\n", t1, st1.srv_time, st1.next_arr);
end 
       
function st1 = arrival_event(st0)
   st1 = st0;
   t0 = st0.tm_stamp;
   t1 = st0.next_arr;
   st1.tm_stamp = t1;
   st1.srv_time = t1 + service_time();	   % new end service time 
	st1.next_arr = t1 + next_arrival();	   % next arrival time is kept
 	st1.n_accept = st0.n_accept + 1;	      % increase accepted requests
   st1.usd_time = st1.usd_time + (st1.srv_time - t1); 
   printf("arriving at %6.2f: busy until %6.2f; next arrival \
at %6.2f\n", t1, st1.srv_time, st1.next_arr);
end

function st1 = serviced_event(st0)
   st1 = st0;
   t0 = st0.tm_stamp;
   t1 = st0.srv_time;
   st1.tm_stamp = t1;
   st1.srv_time = +inf;     	            % server becomes idle
   printf("serviced at %6.2f: busy until %6.2f; next arrival \
at %6.2f\n", t1, st1.srv_time, st1.next_arr);
end

function t_next = next_arrival()
% an exponential distribution with lambda = 0.2
% i.e. mean time between arrivals of 1/lambda = 5	
   lambda = 0.2; r = rand();	
   t_next = -log(1-r)/lambda;
end

function t = erlang()
% função de distribuição
   M = 0.15;
   T = 25;
   lambda = 0.4;
   k = 2;
   aceite = false;
   while ! aceite
      t = T * rand();
      r = M * rand();
      aceite = (r < (lambda^2 * t * exp(-lambda * t)));
   end
end

function t = service_time()
   mode = 1;
   if mode == 1  % an erlang (k=2, lambda= 0.4) distribution 
      t = erlang();        % average time = 2 / 0.4  = 5
   else           % a uniform distribution between 2 and 8
       t = 2 + 6*rand(); % average time = (2+8)/2 = 5
   end
end

function b = stop(st, max_time)
   b = (st.tm_stamp >= max_time);
end


