unit bufcol;
interface
{$I define.pas}
{$IFNDEF DEBBUFCOL}
{$I nodebug.pas}
{$ENDIF}
uses tvtype, objects, stru, mcollect, mytype, mylib
{$IFNDEF WINDOWS}
 ,dos
{$ENDIF}
;

type
  PRecordCollection = ^TRecordCollection;
  TRecordCollection = object(TMCollection)
    RecordSize:Word;
    constructor Init(ARecordSize:Word; ALimit, ADelta:Integer);
    procedure FreeItem(Item:Pointer);virtual;
    function AddRecord(var Rec):boolean;
    function GetRecordAt(Index:integer; var Rec):boolean;
    function PutRecordAt(Index:integer; var Rec):boolean;
  end;

  PFileRecordCollection = ^TFileRecordCollection;
  TFileRecordCollection = object(TRecordCollection)
    function SaveToFile(const AFileName:PathStr):boolean;
    function ReadFromFile(const AFileName:PathStr):boolean;
  end;

(*
{not finished:}
  TFileBufferCollection = object(TRecordCollection)
    procedure GetRecord(Index:LongInt; Item:Pointer);
    procedure PutRecord(Index:LongInt; Item:Pointer);
    procedure AppendRecord(Item:Pointer);
    procedure AtInsertRecord(Index:LongInt; Item:Pointer);
    procedure ClearBuffer;
    procedure ReadBuffer(Index:Longint);
    procedure WriteBufferChange;
    procedure WriteBuffer;
    constructor Init(AFileName:PathStr; AOffset: Word; ARecordSize:Word);
    destructor Done;virtual;
  public
    FileName, TmpFileName:PathStr;
    Offset:Word;
    StartRecord, {from which record from the file the ReadCount of records was
                  read in collection}
    ReadCount: LongInt;
    Status:Integer;
    Modified:boolean;
  end;
*)
implementation
{uses streams;}
constructor TRecordCollection.Init(ARecordSize:Word; ALimit, ADelta:Integer);
begin
  if not inherited Init(ALimit, ADelta) then
    Fail;
  RecordSize := ARecordSize;
end;

procedure TRecordCollection.FreeItem(Item:Pointer);
begin
  if (RecordSize > sizeof(Pointer)) and (Item <> nil) then
    FreeMem(Item, RecordSize);
end;

function TRecordCollection.AddRecord(var Rec):boolean;
var
  buf:pointer;
  cnt:integer;
begin
  AddRecord := false;
  if RecordSize > sizeof(Pointer) then begin
    GetMem(buf, RecordSize);
    if buf = nil then
      exit;
    move(Rec, buf^, RecordSize);
  end else begin
    move(Rec, buf, RecordSize);
  end;
  cnt := Count;
  Insert(buf);
  if Count = cnt then
    exit;{was not inserted}
  AddRecord := true;
end;

function TRecordCollection.GetRecordAt(Index:integer; var Rec):boolean;
var buf:pointer;
begin
  GetRecordAt := false;
  if Count = 0 then
    exit;
  if (Index < 0) or (Index >= Count) then
    exit;
  buf := At(Index);
  if RecordSize > sizeof(Pointer) then begin
    if buf = nil then
      exit;
    move(buf^, Rec, RecordSize)
  end else
    move(buf, Rec, RecordSize);
  GetRecordAt := true;
end;

function TRecordCollection.PutRecordAt(Index:integer; var Rec):boolean;
var obuf, buf:pointer;
begin
  PutRecordAt := false;
  if (Index < 0) or (Index >= Count) then
    exit;
  buf := nil;
  if RecordSize > sizeof(Pointer) then begin
    obuf := at(Index);

    GetMem(buf, RecordSize);
    if buf = nil then
      exit;
    move(Rec, buf^, RecordSize);
    FreeItem(obuf);
  end else begin
    move(Rec, buf, RecordSize);
  end;
  AtPut(Index, buf);
  PutRecordAt := true;
end;

{*************************************}

function TFileRecordCollection.SaveToFile(const AFileName:PathStr):boolean;
var
  S:TBufStream;
  i:integer;
begin
  SaveToFile := false;
  if not S.Init(ConvStreamName(AFileName), stCreate, 1024) then
    exit;
  for i := 0 to pred(Count) do begin
    S.Write(PByteBuffer(At(i))^, RecordSize);
  end;
  S.Flush;
  if S.Status = stOK then
    SaveToFile := true;
  S.Done;
end;

function TFileRecordCollection.ReadFromFile(const AFileName:PathStr):boolean;
var
  S:TBufStream;
  i:integer;
begin
  ReadFromFile := false;
  if not S.Init(ConvStreamName(AFileName), stOpenRead, 1024) then
    exit;
  for i := 0 to pred(Count) do begin
    S.Read(PByteBuffer(At(i))^, RecordSize);
  end;
  if S.Status = stOK then
    ReadFromFile := true;
  S.Done;
end;
{********************************************************************}
(*
procedure TFileBufferCollection.GetRecord(Index:LongInt; Item:Pointer);
begin
  Item := nil;
  if (Index < StartRecord) or (Index >= StartRecord + Count) then begin
    ClearBuffer;
    ReadBuffer(Index);
  end;
  Item := At(Index - StartRecord);
end;

procedure TFileBufferCollection.ClearBuffer;
begin
  if Modified then begin
    if (Count <> ReadCount) then
      WriteBufferChange
    else
      WriteBuffer;
  end;
  FreeAll;
end;

procedure TFileBufferCollection.WriteBufferChange;
var
  s,t:PBufStream;
  r,o:Pointer;
label er, ermem;

begin
  r := nil;
  o := nil;
  ioError := 0;
  TmpFileName := '';
  GetMem(r,RecordSize);
  if r = nil then
    exit;
  if Offset > 0 then begin
    GetMem(o,Offset);
    if o = nil then
      goto er;
  end;

  s := New(PBufStream, Init(FileName, stOpenRead, StreamBufferSize));
  if (s = nil) or (s^.Status <> stOK) then
    goto er;
  TmpFileName := GetTempFileName;
  t := New(PBufStream, Init(TmpFileName, stCreate, StreamBufferSize));
  if (t = nil) or (t^.Status <> stOK) then
    goto ermem;
ermem:
  Status := stError;

er:
  if r <> nil then
    FreeMem(r, RecordSize);
  if o <> nil then
    FreeMem(o, Offset);
  if s <> nil then
    Dispose(s,done);
  if t <> nil then
    Dispose(t,done);
  if TmpFileName <> '' then
    EraseFile(TmpFileName);
  Status := stError;
end;


{
    else if Count = ReadCount then
      WriteBuffer
    else
      WriteBufferDelete;
  end;
  FreeAll;
end;
}
procedure TFileBufferCollection.PutRecord(Index:LongInt; Item:Pointer);
var
  p:Pointer;
begin
  if item = nil then
    exit;
  if (Index < StartRecord) or (Index >= StartRecord + Count) then begin
    ClearBuffer;
    ReadBuffer(Index);
  end;
  AtFree(Index - StartRecord);
  AtInsert(Index - StartRecord, Item);
  Modified := true;
end;

procedure TFileBufferCollection.AppendRecord(Item:Pointer);
begin
end;

procedure TFileBufferCollection.AtInsertRecord(Index:LongInt; Item:Pointer);
begin
end;
procedure TFileBufferCollection.ReadBuffer;
begin
end;
procedure TFileBufferCollection.WriteBuffer;
begin
end;
constructor TFileBufferCollection.Init(AFileName:PathStr; AOffset: Word; ARecordSize:Word);
begin
end;

destructor TFileBufferCollection.Done;
begin
end;

*)
end.