classdef am_queueA < atomic
  %% Description
  %  standard FIFO queue
  %% Ports
  %  inputs: 
  %    in   incoming entities
  %    bl   blocking status of output
  %  outputs: 
  %    out  outgoing entities
  %% States
  %  phase: 0|1|2|3 == 
  %    empty unblocked|empty blocked|queueing unblocked|queueing blocked
  %  queue: vector of queued entities
  %  n: queue length
  %% System Parameters
  %  none
  
  methods
    function obj = am_queueA(name, debug)
      if nargin == 2
        x = {'in', 'bl'};
        y = {'out'};
        s = {'phase','queue', 'n'};
        sysparams =  struct('debug', debug);
     else
        error('mistake at constructor method for class am_queueA');
      end
      obj = obj@atomic(name,x,y,s,0,sysparams); % call parent
      obj.s.phase = 0;
      obj.s.queue = [];
      obj.s.n = 0;
    end
        
    function ta = tafun(obj)
      switch obj.s.phase
        case 0    % empty unblocked
          ta = inf;
        case 1    % empty blocked
          ta = inf;
        case 2    % queueing unblocked
          ta = 0;
        case 3    % queueing blocked
          ta = inf;
        otherwise
          fprintf('wrong phase %d in %s\n', obj.s.phase, obj.name);
      end
    end
        
    function deltaconffun(obj,gt)
      % first current entity leaves, then new one enters
      if obj.sysparams.debug
        fprintf('%4.1f %8s con, in phase %d\n', gt, obj.name, obj.s.phase)
      end
      deltaintfun(obj);
      deltaextfun(obj,gt);
    end
    
    function deltaextfun(obj,gt)
      if obj.sysparams.debug
        fprintf('%4.1f %8s entering ext, being in phase %d\n', ...
		gt, obj.name, obj.s.phase)
        showState(obj);
      end
      [bl, in] = readInputBag(obj);
      switch obj.s.phase
        case 0    % empty unblocked
          if bl == true && isempty(in)
            obj.s.phase = 1;
          elseif bl == true && ~isempty(in)
            obj.s.phase = 3;
            obj.s.queue = [obj.s.queue, in];
          elseif ~isempty(in)
            obj.s.phase = 2;
            obj.s.queue = [obj.s.queue, in];             
          else
            % no entities, bl status remains
          end
        case 1    % empty blocked
          if bl == false && isempty(in)
            obj.s.phase = 0;
          elseif bl == false && ~isempty(in)
            obj.s.phase = 2;
            obj.s.queue = [obj.s.queue, in];
          elseif ~isempty(in)
            obj.s.phase = 3;
            obj.s.queue = [obj.s.queue, in];             
          else
            % no entities, bl status remains
          end
        case 2    % queueing unblocked
          if bl == true
            obj.s.phase = 3;
            obj.s.queue = [obj.s.queue, in];
          else
            obj.s.queue = [obj.s.queue, in];             
          end
        case 3    % queueing blocked
          if bl == false
            obj.s.phase = 2;
            obj.s.queue = [obj.s.queue, in];
          else
            obj.s.phase = 3;
            obj.s.queue = [obj.s.queue, in];             
          end
        otherwise
          fprintf('wrong phase %d in %s\n', obj.s.phase, obj.name);
      end
      obj.s.n = length(obj.s.queue);
      if obj.sysparams.debug
        fprintf('     %8s  leaving ext, going to phase %d\n', ...
		obj.name, obj.s.phase)
        showState(obj);
      end
   end
        
    function deltaintfun(obj)
      if obj.sysparams.debug
        fprintf('%4.1f %8s entering int, being in phase %d\n', ...
		obj.tnext, obj.name, obj.s.phase)
        showState(obj);
      end
      switch obj.s.phase
        case 2    % queueing unblocked
          if length(obj.s.queue) == 1
            obj.s.phase = 0;
          else
            obj.s.phase = 2;
          end
          obj.s.queue = obj.s.queue(2:end);
        otherwise
          fprintf('wrong phase %d in %s\n', obj.s.phase, obj.name);
      end
      obj.s.n = length(obj.s.queue);
      if obj.sysparams.debug
        fprintf('     %8s  leaving int, going to phase %d\n', ...
		obj.name, obj.s.phase)
        showState(obj);
      end
    end
               
    function lambdafun(obj)
      switch obj.s.phase
        case 2    % queueing unblocked
          obj.y.out = {obj.s.queue(1)};
        otherwise
          fprintf('la: wrong phase %d in %s\n', obj.s.phase, obj.name);
      end
      if obj.sysparams.debug
        fprintf('%4.1f %8s OUT, out=', obj.tnext, obj.name)
        fprintf('%2d', cell2mat(obj.y.out))
        fprintf('\n')
      end
    end
    
    function [bl, in] = readInputBag(obj)
      % returns last blocking input, -1, if there is none
      % returns vector of input entities
      if ~isempty(obj.x.bl)
        bl = obj.x.bl{end};
      else
        bl = -1;
      end

      if ~isempty(obj.x.in)
        in = cell2mat(obj.x.in);
      else
        in = [];
      end 
    end
    
    function showState(obj)
      % debug function, prints current state
      fprintf('         phase=%1d n=%1d queue=', obj.s.phase, obj.s.n)
      fprintf('%2d ', obj.s.queue)
      fprintf('\n')
    end

  end  % methods
end   % classdef
