IMPLEMENTATION MODULE List;

FROM Linked IMPORT LinkedList, Linkable;
FROM String IMPORT String;

  CLASS ListElement(Element);
    INHERITS Linkable;
    VAR
      TheEl: Element;
      TheRefList: List(Element);
      
    METHOD Reset;
      BEGIN
      TheEl := VOID;
      END Reset;
      
    METHOD Set(El: Element);
      BEGIN
      TheEl := El;
      END Set;
      
    REDEFINE METHOD CREATE (El: Element;
                            RefList: List(Element));
      BEGIN
      TheEl := El;
      TheRefList := RefList;
      END CREATE;
      
    METHOD Value: Element;  
      BEGIN
      RESULT := TheEl;
      END Value; 
      
    REDEFINE METHOD IsGreater(Other: Comparable): BOOLEAN;    
      VAR
        OtherElement: Element;
      BEGIN         
      WHAT Other OF
        IN ListElement(Element):
          OtherElement := TAG.TheEl;
          END;
        END;
      RESULT := TheRefList.ShouldSwap (TheEl, OtherElement);
      END IsGreater;  
            
    END ListElement;
--------------------------------------------
  CLASS List(Element);
    INHERITS AbstractList(Element);

    VAR
      TheList: LinkedList;
      Recycle: ListElement(Element);
      
    REDEFINE METHOD Append (El: Element);
      VAR
        ListEl: ListElement(Element);              
      BEGIN
      IF Recycle <> VOID THEN
        Recycle.Set (El);
        TheList.Append (Recycle);
        Recycle := VOID;
       ELSE
        ListEl.CREATE (El, THIS);
        TheList.Append (ListEl);
        END;
      END Append;
           
    REDEFINE METHOD Insert (Pos: INTEGER;
                            El: Element);
      VAR
        ListEl: ListElement(Element);              
      BEGIN
      IF Recycle <> VOID THEN
        Recycle.Set (El);
        TheList.Insert (Pos, Recycle);
        Recycle := VOID;
       ELSE
        ListEl.CREATE (El, THIS);
        TheList.Insert (Pos, ListEl);
        END;
      END Insert;  
      
    REDEFINE METHOD Delete (Pos: INTEGER);
      VAR
        p: Linkable;
      BEGIN
      IF Recycle = VOID THEN
        p := TheList.Get(Pos);
        IF p <> VOID THEN
          WHAT p OF
            IN ListElement (Element):
              Recycle := TAG;
              Recycle.Reset;
              END;
            END;
          TheList.Delete(Pos);
          END;
       ELSE        
        TheList.Delete (Pos);
        END;
      END Delete;
      
    REDEFINE METHOD Get (Pos: INTEGER): Element;
      VAR
        p: Linkable;
      BEGIN
      p := TheList.Get (Pos);
      IF p <> VOID THEN
        WHAT p OF
            IN ListElement(Element):
            RESULT := TAG.Value;
            END;
          END;
        END;
      END Get;
    

    REDEFINE METHOD CREATE;
      BEGIN
      TheList.CREATE;
      END CREATE;
      
    REDEFINE METHOD Size: INTEGER;
      BEGIN
      RESULT := TheList.Size;
      END Size;  

    REDEFINE METHOD Sort;
      BEGIN    
      TheList.Sort;
      END Sort;      
      
    REDEFINE METHOD ShouldSwap (One, Two: Element): BOOLEAN;
      VAR
        OneComp, TwoComp: Comparable;
      BEGIN
      WHAT One OF
        IN Comparable:
          OneComp := TAG;
          END;
        END;
      WHAT Two OF
        IN Comparable:
          TwoComp := TAG;
          END;
        END;
      RESULT := OneComp.IsGreater (TwoComp);
      END ShouldSwap;
      
      REDEFINE METHOD CLONE(Other: List(Element));
        BEGIN
        Other.TheList := TheList.CLONE;
        Other.Recycle := VOID;
        Recycle := VOID;
        END CLONE;
        
    REDEFINE METHOD Purge;
      BEGIN
      TheList.Purge;
      TheList.CREATE;
      ASSERT Size = 0;        
      Recycle := VOID;
      END Purge;

    END List;

-------------------------
  CLASS StringElement;       
    INHERITS Comparable;
    VAR
      TheValue: ARRAY OF CHAR;

    REDEFINE METHOD CREATE (Value: ARRAY OF CHAR);
      BEGIN
      TheValue := Value;
      END CREATE;

    METHOD Set (Value: ARRAY OF CHAR);
      BEGIN
      TheValue := Value;
      END Set;
      
    METHOD Get: ARRAY OF CHAR;
      BEGIN
      RESULT := TheValue;
      END Get;          
      
    REDEFINE METHOD IsGreater(Other: Comparable): BOOLEAN;
      BEGIN         
      WHAT Other OF
        IN StringElement:    
          RESULT := String.Compare (Get, TAG.Get) = String.Greater;
          END;
        END;
      END IsGreater;
      
    REDEFINE METHOD IsEqual(Other: Comparable): BOOLEAN;
      BEGIN         
      IF THIS = Other THEN
        RESULT := TRUE;
       ELSE
        WHAT Other OF
          IN StringElement:    
            RESULT := String.Equals (Get, TAG.Get);
            END;
          END;
        END;
      END IsEqual;
      
  END StringElement;
-----------------------------
  CLASS StringList(Element IN StringElement);
    INHERITS List(Element);

    METHOD GetString (Pos: INTEGER): ARRAY OF CHAR;
      VAR
        StrEl: StringElement;
      BEGIN
      StrEl := Get(Pos);
      IF StrEl <> VOID THEN
        RESULT := StrEl.Get;
        END;
      END GetString;
      
    METHOD FindString (ToFind: ARRAY OF CHAR) : Element;
      BEGIN
      FOR i := 0 TO Size - 1 WHILE RESULT = VOID DO
        IF String.Equals (ToFind, GetString (i)) THEN
          RESULT := Get (i);
          ASSERT RESULT <> VOID;
          END;
        END;
      END FindString;    
  END StringList;  

END List;
