unit OrdLists;

{--------------------------------------------------------------------------}
{ Abstract Data Type for a key ordered list.                               }
{ By Michael Dales 30th May 1996                                           }
{                                                                          }
{ A simple ordered list ADT. All you need to use are the decalred          }
{ methods below, you don't even need to know how the type works either.    }
{ To use the list just assign the list variable the type TOrdList, and     }
{ rember to use CreateList before you try and do any operations on it. The }
{ data in each node is stored as a pointer, and each node has a key by     }
{ which the list is ordered which is a 32 character array, type called     }
{ TKey. The type of each node is called PListNode.                         }
{                                                                          }
{ I've designed this as an abstract data type, which means that although   }
{ you can look at the code and see how I've implemented it, you can (and   }
{ should) use just the methods I've declared in the interface of this      }
{ unit. Hence the word abstract in abstract data type. So there.           }
{                                                                          }
{ If you have any comments the email me at: 9402198d@udcf.gla.ac.uk        }
{ URL: http://www.gla.ac.uk/Clubs/WebSoc/~9402198d/index.html              }
{--------------------------------------------------------------------------}

interface

uses Strings;

const null = nil;        {Non specific terminator}

type TKey      = array[0..32] of char;

     PListNode = ^TListNode;             {Pointer to node}
     TListNode = record                  {Node record}
               Key       : TKey;         {Key for node}
               Item      : Pointer;      {Pointer to node data}
               Next      : PListNode;    {Next node}
               Previous  : PListNode;    {Previous node}
     end;

     TOrdList = record                {Holder for list}
           First : PListNode;         {Pointer to start of list}
           Rear  : PListNode;         {Pointer to end of list}
           Size  : integer;           {Size of list}
     end;

{CreateList - Initiates a new list}
procedure CreateList(var L : TOrdList);

{DestroyList - Frees up all memory used by list and sets list to nil}
procedure DestroyList(var L : TOrdList);

{AddNewNode - Adds new node to list L, filling it with the data
              supplied. Returns true is new node sucessfully
              added, otherwise returns false.}
procedure AddNewNode(var L : TOrdList; AKey : PChar; Data : Pointer);

{DeleteNode - Deletes an element passed.}
procedure DeleteNode(var L : TOrdList; ANode : PListNode);

{GetFirstNode - Returns the first node in a given list}
function GetFirstNode(L : TOrdList) : PListNode;

{FindFirstNode - Finds the first node with a matching key}
function FindFirstNode(L : TOrdList; AKey : TKey) : PListNode;

{GetNextNode - Returns the successor of the given node}
function GetNextNode(Node : PListNode) : PListNode;

{GetNodeData - Returns the data in a specific node}
procedure GetNodeData(Node : PListNode; var Data : Pointer);

{GetNodeKey - Returns the key for a given node}
procedure GetNodeKey(Node : PListNode; var AKey : TKey);

{UpdateNode - Replaces a nodes details with new ones}
procedure UpdateNode(Node : PListNode; Data : Pointer);

{--------------------------------------------------------------------------}
implementation
{--------------------------------------------------------------------------}

    {CreateList - Initiates a new list}

procedure CreateList(var L : TOrdList);
begin
     L.First := nil;      {No list yet}
     L.Rear := nil;
     L.Size := 0;         {No length yet}
end;


    {RemoveLastNode - Deletes last node on the list}

procedure RemoveLastNode(var L : TOrdList);
begin
     with L do                                  {With the list}
     begin
          if Size > 0 then                        {If nodes in list}
          begin
               if Size = 1 then                   {If just one node}
               begin
                    if First^.Item <> nil then  {If data in node then}
                       Dispose(First^.Item);        {Dispose of it}
                    Dispose(First);             {Dispose of first node}
                    First := nil;
                    Rear := nil;                  {Set rear to nil}
               end else
               begin                            {If more than one node}
                    if Rear^.Item <> nil then
                       Dispose(Rear^.Item);
                    Rear := Rear^.Previous;       {Set rear to second last}
                    Dispose(Rear^.Next);        {Remove last node}
               end;
               Size := Size-1;                    {Decrement list size}
          end;
     end;
end;


    {DestroyList - Frees up all memory used by list and sets list to nil}

procedure DestroyList(var L : TOrdList);
begin
     while L.First <> nil do              {While still nodes left}
           RemoveLastNode(L);             {Remove last node}
     CreateList(L);
end;


    {GetFirstNode - Returns the first node in a given list}

function GetFirstNode(L : TOrdList) : PListNode;
begin
     GetFirstNode := L.First;
end;


    {FindFirstNode - Finds the first node with a matching key}

function FindFirstNode(L : TOrdList; AKey : TKey) : PListNode;
var temp  : PListNode;
    found : boolean;
begin
     found := false;
     temp := L.First;
     while (temp <> nil) and not found do
     begin
          found := temp^.Key = AKey;
          if not found then temp := temp^.Next;
     end;
     FIndFirstNode := temp;
end;


    {GetNextNode - Returns the successor of the given node}

function GetNextNode(Node : PListNode) : PListNode;
begin
     if Node <> nil then
        GetNextNode := Node^.Next
     else
         GetNextNode := nil;
end;


    {GetNodeData - Returns the data in a specific node}

procedure GetNodeData(Node : PListNode; var Data : Pointer);
begin
     if Node <> nil then
        Data := Node^.Item
     else
         Data := nil;
end;


    {GetNodeKey - Returns the key for a given node}

procedure GetNodeKey(Node : PListNode; var AKey : TKey);
begin
     if node <> nil then
        AKey := Node^.Key;
end;


    {AddNewNode - Adds new node to list L, filling it with the data
                  supplied. Returns true is new node sucessfully
                  added, otherwise returns false.}

procedure AddNewNode(var L : TOrdList; AKey : PChar; Data : Pointer);
var temp    : PListNode;
    CurNode : PListNode;
    Match   : boolean;
begin
     new(temp);                 {Create new node}
     with temp^ do              {Fill node}
     begin
          StrCopy(Key, AKey);
          Item := Data;
          Next := nil;
          Previous := nil;
     end;
     if L.Size = 0 then
     begin
          L.First := temp;
          L.Rear := temp;
     end else
     begin
          CurNode := L.First;
          Match := false;
          while (CurNode <> nil) and not Match do
          begin
               if StrComp(CurNode^.Key, AKey) >= 0 then
                  Match := true
               else
                   CurNode := CurNode^.Next;
          end;
          if not Match then
          begin
               temp^.Previous := L.Rear;
               L.Rear^.Next := temp;
               L.Rear := temp;
          end else
          begin
               temp^.Next := CurNode;
               temp^.Previous := CurNode^.Previous;
               if (CurNode^.Previous <> nil) then
                  CurNode^.Previous^.Next := temp
               else
                   L.First := temp;
               CurNode^.Previous := temp;
          end;
     end;
     L.Size := L.Size + 1;          {Increment list length}
end;


    {UpdateNode - Replaces a nodes details with new ones}

procedure UpdateNode(Node : PListNode; Data : Pointer);
begin
     if Node <> nil then
     begin
          Node^.Item := Data;
     end;
end;


    {DeleteNode - Deletes an element passed.}

procedure DeleteNode(var L : TOrdList; ANode : PListNode);
begin
     if (L.Size = 1) or (ANode^.Next = nil) then
        RemoveLastNode(L)
     else
     begin
          if (ANode = L.First) then
          begin
               L.First := L.First^.Next;
               L.First^.Previous := nil;
               Dispose(ANode);
          end else
          begin
               ANode^.Previous^.Next := ANode^.next;
               ANode^.Next^.Previous := ANode^.Previous;
               Dispose(ANode);
          end;
          L.Size := L.Size-1;
     end;
end;

end.
