UNIT DList;

{$i platform.inc}

{ Dijk-List                                                            }
{                                                                      }
{ Deze unit implementeerd een manier om een enkele lijst bij te houden }
{ zonder dat je voor elke lijst opnieuw alle code hoeft te schrijven   }
{ om deze te initialiseren, veranderen, items toevoegen etc.           }

INTERFACE

TYPE ItemPtr = ^Item;
     Item  = RECORD
                   PointerToItem : POINTER;
                   NextItem      : ItemPtr;
             END;

     DListFreeProc = PROCEDURE (VAR P : POINTER);

     List = OBJECT
                  CurrentItem,
                  FirstItem,
                  LastItem   : ItemPtr;
                  ItemSize   : WORD;
                  FreeProc   : DListFreeProc;

                  PROCEDURE  Init (Size : WORD; Proc : DListFreeProc);
                  DESTRUCTOR Done;
                  PROCEDURE  Add (Item : POINTER);
                  FUNCTION   Create : POINTER;
                  PROCEDURE  Clear;
                  FUNCTION   GetFirstItem : POINTER;
                  FUNCTION   GetNextItem : POINTER;
                  PROCEDURE  Replace (NewPtr : POINTER);
                  FUNCTION   GetNextItem2 (LastPtr : POINTER) : POINTER;
                  FUNCTION   ItemCount : WORD;
            END;


IMPLEMENTATION

USES Globals,
     Logs;

{--------------------------------------------------------------------------}
{ Init                                                                     }
{                                                                          }
{ Initialiseerd de lijst.                                                  }
{                                                                          }
PROCEDURE List.Init (Size : WORD; Proc : DListFreeProc);
BEGIN
     ItemSize:=Size;
     CurrentItem:=NIL;
     FirstItem:=NIL;
     LastItem:=NIL;
     FreeProc:=Proc;
END;


{--------------------------------------------------------------------------}
{ Exit                                                                     }
{                                                                          }
{ Maakt alles schoon, en schopt zichzelf dan uit het geheugen.             }
{                                                                          }
DESTRUCTOR List.Done;
BEGIN
     Clear;
END;


{---------------------------------------------------------------------------}
{ Clear                                                                     }
{                                                                           }
{ Verwijdert de lijst uit het geheugen.                                     }
{                                                                           }
PROCEDURE List.Clear;

VAR NextItem : ItemPtr;

BEGIN
     CurrentItem:=FirstItem;
     WHILE (CurrentItem <> NIL) DO
     BEGIN
          IF (@FreeProc <> NIL) THEN
             FreeProc (CurrentItem^.PointerToItem);

          IF (ItemSize <> 0) THEN
          BEGIN
               {$IFDEF LogGetMem} LogGetMem (CurrentItem^.PointerToItem,ItemSize,'FreeMem DList Item'); {$ENDIF}
               FreeMem (CurrentItem^.PointerToItem,ItemSize);
          END;

          NextItem:=CurrentItem^.NextItem;
          Dispose (CurrentItem);
          CurrentItem:=NextItem;
     END;

     FirstItem:=NIL;
     LastItem:=NIL;
END;


{---------------------------------------------------------------------------}
{ Add                                                                       }
{                                                                           }
{ Voegt een item toe aan de lijst.                                          }
{                                                                           }
PROCEDURE List.Add (Item : POINTER);

VAR TempItem : ItemPtr;

BEGIN
     New (TempItem);        { Vraag geheugen voor een controle blokje }

     TempItem^.PointerToItem:=Item;
     TempItem^.NextItem:=NIL;

     IF (FirstItem = NIL) THEN
        FirstItem:=TempItem;

     IF (LastItem <> NIL) THEN
        LastItem^.NextItem:=TempItem;  { Link in de list }

     LastItem:=TempItem;  { Plaats einde op dit element }
END;


{--------------------------------------------------------------------------}
{ Create                                                                   }
{                                                                          }
{ Vraag de juiste hoeveelheid geheugen aan, voeg het record aan de lijst   }
{ toe en geef de pointer terug.                                            }
{                                                                          }
FUNCTION List.Create : POINTER;

VAR Tmp : POINTER;

BEGIN
     GetMem (Tmp,ItemSize);
     {$IFDEF LogGetMem} LogGetMem (Tmp,ItemSize,'GetMem DList Create'); {$ENDIF}
     Add (Tmp);
     Create:=Tmp;
END;


{--------------------------------------------------------------------------}
{ GetFirstItem                                                             }
{                                                                          }
{ Initialiseerd de Item pointer, dus als er door een list gelopen gaat     }
{ worden, moet dit item als eerste worden aangeroepen (!) Geeft het eerste }
{ item terug. Geeft NIL terug als de lijst leeg is.                        }
{                                                                          }
FUNCTION List.GetFirstItem : POINTER;
BEGIN
     CurrentItem:=FirstItem;
     IF (CurrentItem <> NIL) THEN
        GetFirstItem:=FirstItem^.PointerToItem
     ELSE
         GetFirstItem:=NIL;
END;


{--------------------------------------------------------------------------}
{ GetNextItem                                                              }
{                                                                          }
{ Zoekt het volgende element in de lijst, en geeft er een pointer naar     }
{ terug. Als we het einde van de lijst bereikt hebben geeft de routine NIL }
{ terug.                                                                   }
{                                                                          }
FUNCTION List.GetNextItem : POINTER;
BEGIN
     IF (CurrentItem^.NextItem <> NIL) THEN
     BEGIN
          CurrentItem:=CurrentItem^.NextItem;
          GetNextItem:=CurrentItem^.PointerToItem;
     END ELSE
         GetNextItem:=NIL;
END;


{--------------------------------------------------------------------------}
{ Replace                                                                  }
{                                                                          }
{ Vervangt de pointer naar de user data.                                   }
{                                                                          }
PROCEDURE List.Replace (NewPtr : POINTER);
BEGIN
     CurrentItem^.PointerToItem:=NewPtr;
END;


{--------------------------------------------------------------------------}
{ GetNextItem2                                                             }
{                                                                          }
{ This function must be used when a GetFirst/GetNext sequence is           }
{ interrupted by another GetFirst/GetNext sequence, which re-uses the      }
{ CurrentItem.                                                             }
{                                                                          }
FUNCTION List.GetNextItem2 (LastPtr : POINTER) : POINTER;
BEGIN
     { zoek naar het item dat ook naar LastPtr staat }
     CurrentItem:=FirstItem;
     WHILE (CurrentItem <> NIL) AND (CurrentItem^.PointerToItem <> LastPtr) DO
           CurrentItem:=CurrentItem^.NextItem;

     GetNextItem2:=GetNextItem;
END;


{--------------------------------------------------------------------------}
{ ItemCount                                                                }
{                                                                          }
{ Deze routine geeft het aantal items dat in de lijst zit terug.           }
{                                                                          }
FUNCTION List.ItemCount : WORD;

VAR Count   : WORD;
    TelItem : ItemPtr;

BEGIN
     Count:=0;

     TelItem:=FirstItem;
     WHILE (TelItem <> NIL) DO
     BEGIN
          Inc (Count);
          TelItem:=TelItem^.NextItem;
     END;

     ItemCount:=Count;
END;


END.
