{**************************************************}
{  This unit defines the dictionary types used in  }
{  the Windows charting program PCHART.PAS.        }
{                  Zack Urlocker                   }
{                    05/02/91                      }
{                                                  }
{  Two types are defined:                          }
{       TAssoc: a key value pair of a C style      }
{               string and an Integer value        }
{       TDict : a dictionary of TAssocs            }
{  both types include methods for stream storage   }
{**************************************************}

unit Dicts;

{$IFDEF Final}        { Remove debug code for final version}
{$D-,I-,L-,R-,S-}
{$ELSE}
{$D+,I+,L+,R+,S+}
{$ENDIF}

interface

uses WObjects, Strings;

type
  PAssoc = ^TAssoc;
  TAssoc = Object(TObject)
    key : PChar;
    value : Integer;
    constructor Init(NewKey : PChar; NewValue : Integer);
    destructor Done; virtual;
    constructor Load(var S: TStream);
    procedure Store(var S: TStream);
  end;

  PDict = ^TDict;
  TDict = Object(TCollection)
   current : PAssoc;
{ Functions and procedures }
   function Size : Integer;
   function MaxValue : Integer;
   procedure Add(key : PChar; value : Integer);
   function Find(key : PChar): Boolean;
   procedure Remove(key : PChar);
   procedure Update(key : PChar; value : Integer);
end;


implementation


{ *********   TAssoc  ********* }

{ Initialize a new association, allocating memory }
constructor TAssoc.Init(NewKey : PChar; NewValue : Integer);
begin
  Key := StrNew(NewKey);
  Value := NewValue;
end;

{ Dispose of the association by deallocating memory}
destructor TAssoc.Done;
begin
  StrDispose(Key);
end;

{ Load the key, value from the stream, and allocate memory }
constructor TAssoc.Load(var S: TStream);
begin
{ Allocate, and read C style string}
  Key := S.StrRead;
  S.Read(Value, sizeOf(Value));
end;

{ Store the key, value on the stream }
procedure TAssoc.Store(var S: TStream);
begin
  S.StrWrite(Key);
  S.write(Value, sizeOf(Value));
end;


{ *********   TDict  ********* }

{ Return the size of the dictionary }
function TDict.Size : Integer;
begin
  Size := count;
end;

{ Find the maximum value in the dictionary }
function TDict.MaxValue : Integer;
var Max : Integer;

{ Is its value bigger than current maximum? }
procedure GetMax(Item: PAssoc); far;
begin
  if Item^.value > Max then
    Max := Item^.Value;
end;

begin { MaxValue }
  Max := 0;
  ForEach(@GetMax);
  MaxValue := Max;
end;

{ Add a key value pair to the dictionary }
procedure TDict.Add(key : PChar; value : Integer);
begin
  Insert(New(PAssoc, Init(key, value)));
end;

{ Search the Dictionary for a key }
function TDict.Find(key : PChar) : Boolean;
var Found : Boolean;

{ Does the item match the key? }
function Match(Item:PAssoc) : Boolean; far;
begin
  Match := (StrComp(Item^.key, Key)=0);
end;

begin {Find}
  Current := FirstThat(@Match);
  If Current <> nil then
    Found := True
  else
    Found := False;
  Find := Found;
end;

{ Find the item and then remove it }
procedure TDict.Remove(key : PChar);
begin
  if Find(key) then
    Delete(Current);
end;

{ If it exists, then update it, otherwise add it. }
procedure TDict.Update(key : PChar; value : Integer);
begin
  if Find(Key) then
    Current^.Value := value
  else
    Add(Key, Value);
end;


{ Stream registration records }

const

  RAssoc : TStreamRec = (
    ObjType : 1000;
    VmtLink : Ofs(TypeOf(TAssoc)^);
    Load : @TAssoc.Load;
    Store: @TAssoc.Store
  );

  RDict : TStreamRec = (
    ObjType : 1001;
    VmtLink : Ofs(TypeOf(TDict)^);
    Load : @TCollection.Load;
    Store: @TCollection.Store
  );


{ Initialization }
begin
  RegisterType(RAssoc);
  RegisterType(RDict);
end.
