%
%  List 4.2.3 : einfach verkettete Liste
%    Verwaltungsfunktionen
%
classdef List < handle 

  properties
    front = Node.empty;   % Kopf der Liste
    back  = Node.empty;   % Ende der Liste
  end   % properties
  
  methods 
    % Konstruktor mit leerer Liste 
    function obj = List()
      obj.front = Node.empty;
      obj.back  = Node.empty;      
    end
        
    % Knoten node hinten anhängen  
    function pushBack( obj, node )
      pre = obj.back;    % bisheriges Ende
      obj.back = node;   % neues Ende 
      % Check, ob Liste leer ist  
      if( isempty( obj.front ) )
        obj.front = node;   % neuer Kopf der Liste 
      else 
        pre.next = node;    % als Nachfolger von pre
      end
    end
    
    % Knoten node vorne anhängen  
    function pushFront( obj, node )
      succ = obj.front;     % bisheriger Start 
      obj.front = node;     % neuer Start 
      if( isempty( obj.back ) )
      obj.back  = node;
      else
      node.next = succ;
      end
    end 

    % Knoten node nach pre anhängen
    function insert( obj, pre, node )
      nxt = pre.next;     % nxt = bisheriger Nachfolger von pre
      pre.next = node;    % node als neuer Nachfolger von pre
      node.next = nxt;    % nxt wird Nachfolger von node 
      if( pre == obj.back )   % falls pre das Ende der Liste war  
        obj.back = node;      % node wird neues Ende der Liste  
      end
    end 

    % Kopf der Liste löschen 
    function popFront( obj )
      fr = obj.front;
      obj.front = fr.next;     % neuer Kopf der Liste 
      delete( fr );            % Destruktor von Node 
    end  
    
    % Ende der Liste löschen 
    function popBack( obj )
      bk = obj.back;
      % Vorletzten Knoten suchen, darf auch leer sein  
      pre = getPre( obj, bk );
      if( ~isempty( pre ) )
        pre.next = Node.empty;  % kein Nachfolger mehr 
      end  
      obj.back = pre;    % neues Ende 
      delete( bk );
    end
    
    % Suche nach data-Wert val
    function s = findobj( obj, val )
      act = obj.front;    % Kopf 
      s = Node.empty;     % Vorbelegung 
      % Ende erreicht oder Knoten gefunden
      while( ~isempty( act ) )
        if( act.data == val )
        s = act;
          return;
        end
        act = act.next; 
      end
    end

  end   % methods

  % Private Methoden  
  methods (Access = private)
    
    % Vorgänger suchen
    function pre = getPre( obj, node )
      act = obj.front;    % Kopf 
      pre = Node.empty;   % Vorbelegung 
      % kein Ende erreicht oder node gefunden bzw. leer 
      while( ~isempty( act ) && (act ~= node) )
        pre = act;        % Vorgänger 
        act = act.next; 
      end      
    end     
    
  end % private methods       
end
