unit ChecksumList;

{ Martin Harvey 29/5/2000 }

interface

uses SimpleSync, Classes, SysUtils;

type
  TChecksumList = class
  private
    FCheckList: TList;
    FSync: TSimpleSynchronizer;
  protected
    { Find function returns -1 if not found }
    function FindFileIndex(FileName: string): integer;
    function NoLockGetFileList: TStringList;
    function NoLockGetChecksum(FileName: string): integer;
  public
    constructor Create;
    destructor Destroy; override;
    procedure SetChecksum(FileName: string; Checksum: integer);
    procedure RemoveChecksum(FileName: string);
    function GetChecksum(FileName: string): integer;
    function GetFileList: TStringList;
    function GetChecksumList: TStringList;
  end;

implementation

type
  TCheckSum = record
    FileName: string;
    Checksum: integer;
  end;

  PCheckSum = ^TCheckSum;

constructor TChecksumList.Create;
begin
  inherited Create;
  FCheckList := TList.Create;
  FSync := TSimpleSynchronizer.Create;
end;

destructor TCheckSumList.Destroy;

var
  iter: integer;
  CurSum: PCheckSum;

begin
  if FCheckList.Count > 0 then
  begin
    for iter := 0 to FCheckList.Count - 1 do
    begin
      CurSum := PCheckSum(FCheckList.Items[iter]);
      if Assigned(CurSum) then Dispose(CurSum);
    end;
  end;
  FCheckList.Free;
  FSync.Free;
  inherited Destroy;
end;

function TCheckSumList.FindFileIndex(FileName: string): integer;

var
  iter: integer;
  CurSum: PCheckSum;

begin
  result := -1;
  if FCheckList.Count > 0 then
  begin
    for iter := 0 to FCheckList.Count - 1 do
    begin
      CurSum := PCheckSum(FCheckList.Items[iter]);
      Assert(Assigned(CurSum));
      if AnsiCompareText(FileName, CurSum.FileName) = 0 then
      begin
        result := iter;
        exit;
      end;
    end;
  end;
end;

procedure TCheckSumList.SetChecksum(FileName: string; Checksum: integer);

var
  CurSum: PCheckSum;
  CurIndex: integer;

begin
  FSync.StartWrite;
  CurIndex := FindFileIndex(FileName);
  if CurIndex >= 0 then
    CurSum := PCheckSum(FCheckList.Items[CurIndex])
  else
  begin
    New(CurSum);
    FCheckList.Add(CurSum);
  end;
  CurSum.FileName := FileName;
  CurSum.Checksum := Checksum;
  FSync.EndWrite;
end;

procedure TCheckSumList.RemoveChecksum(FileName: string);

var
  CurIndex: integer;

begin
  FSync.StartWrite;
  CurIndex := FindFileIndex(FileName);
  if CurIndex >= 0 then
  begin
    FCheckList.Delete(CurIndex);
    FCheckList.Pack;
  end;
  FSync.EndWrite;
end;

function TCheckSumList.NoLockGetChecksum(FileName: string): integer;

var
  CurIndex: integer;
  CurSum: PCheckSum;

begin
  result := 0;
  CurIndex := FindFileIndex(FileName);
  if CurIndex >= 0 then
  begin
    CurSum := PCheckSum(FCheckList.Items[CurIndex]);
    Assert(Assigned(CurSum));
    result := CurSum.Checksum;
  end;
end;

function TCheckSumList.GetChecksum(FileName: string): integer;
begin
  FSync.StartRead;
  result := NoLockGetChecksum(FileName);
  FSync.EndRead;
end;

function TCheckSumList.NoLockGetFileList: TStringList;

var
  iter: integer;
  CurSum: PCheckSum;

begin
  result := TStringList.Create;
  if FCheckList.Count > 0 then
  begin
    for iter := 0 to FCheckList.Count - 1 do
    begin
      CurSum := PCheckSum(FCheckList.Items[iter]);
      Assert(Assigned(CurSum));
      result.Add(CurSum.FileName);
    end;
  end;
  result.Sort;
end;

function TCheckSumList.GetFileList: TStringList;
begin
  FSync.StartRead;
  result := NoLockGetFileList;
  FSync.EndRead;
end;

function TCheckSumList.GetChecksumList: TStringList;

var
  iter: integer;

begin
  FSync.StartRead;
  result := NoLockGetFileList;
  if result.Count > 0 then
  begin
    for iter := 0 to result.Count - 1 do
    begin
      result.strings[iter] := result.strings[iter]
        + ' ' + IntToStr(NoLockGetChecksum(result.strings[iter]));
    end;
  end;
  FSync.EndRead;
end;

end.