unit DataAccess;
interface

uses TypeDefs, Classes, StrUtils, SysUtils;

type
  TDataAccess = class
  private
  protected
    FConnectionID:  Integer;
    FFileName:      String;
    FBackend:       TDataBackend;
    FDataOS:        TDataOS;
    FLevelNumber:   Integer;
    FChangeRights:  TChangeRights;
    procedure SetDataOS(DataOS: TDataOS);
  public
    property ConnectionID: Integer      read FConnectionID;
    property FileName:     String       read FFileName;
    property Backend:      TDataBackend read FBackend;
    property DataOS:       TDataOS      read FDataOS write SetDataOS;
    property LevelNumber:  Integer      read FLevelNumber;
    property ChangeRights: TChangeRights read FChangeRights;

    constructor Create(FileName: String; ConnectionID: Integer; var Msg: TStatusMessages); virtual; abstract;
    procedure Close; virtual; abstract;

    function ExtractFileIDOfName(Name: String): Integer; virtual;
    function GetFileInfo(FileID: Integer): TFileInfo; virtual;
    function GetFileInfoByName(Name: String): TFileInfo; virtual;
    function GetFilesList(Ext: String; Pattern: String;
      NoEmptyFiles: Boolean; SortType: TSortType): TStrings; virtual; abstract;
    function GetFileCount: Integer; virtual; abstract;
    function GetExtensionsList(ExtListFormat: TExtensionFormat): TStrings; virtual; abstract;

    procedure LoadDatFile(FileID: Integer; var Target: TStream); overload; virtual; abstract;
    procedure LoadDatFile(FileID: Integer; var Target: TByteData); overload;
    procedure UpdateDatFile(FileID: Integer; Src: TStream); overload; virtual; abstract;
    procedure UpdateDatFile(FileID: Integer; Src: TByteData); overload;
    procedure LoadDatFilePart(FileID, Offset, Size: Integer; var Target: TStream); overload; virtual; abstract;
    procedure LoadDatFilePart(FileID, Offset, Size: Integer; var Target: TByteData); overload;
    procedure LoadDatFilePart(FileID, Offset, Size: Integer; Target: Pointer); overload;
    procedure UpdateDatFilePart(FileID, Offset, Size: Integer; Src: TStream); overload; virtual; abstract;
    procedure UpdateDatFilePart(FileID, Offset, Size: Integer; Src: Pointer); overload;

    function GetDatLinks(FileID: Integer): TDatLinkList; virtual; abstract;
    function GetRawList(FileID: Integer): TRawDataList; virtual; abstract;
    function GetRawInfo(FileID, DatOffset: Integer): TRawDataInfo; virtual; abstract;

    procedure LoadRawFile(FileID, DatOffset: Integer; var Target: TStream); overload; virtual; abstract;
    procedure LoadRawFile(FileID, DatOffset: Integer; var Target: TByteData); overload;
    procedure UpdateRawFile(FileID, DatOffset: Integer; Src: TStream); overload; virtual; abstract;
    procedure UpdateRawFile(FileID, DatOffset: Integer; Src: TByteData); overload;
    procedure LoadRawFilePart(FileID, DatOffset, Offset, Size: Integer; var Target: TStream); overload; virtual; abstract;
    procedure LoadRawFilePart(FileID, DatOffset, Offset, Size: Integer; var Target: TByteData); overload;
    procedure LoadRawFilePart(FileID, DatOffset, Offset, Size: Integer; Target: Pointer); overload;
    procedure UpdateRawFilePart(FileID, DatOffset, Offset, Size: Integer; Src: TStream); overload; virtual; abstract;
    procedure UpdateRawFilePart(FileID, DatOffset, Offset, Size: Integer; Src: Pointer); overload;

    function AppendRawFile(LocSep: Boolean; Src: TStream): Integer; overload; virtual;
    function AppendRawFile(LocSep: Boolean; Src: TByteData): Integer; overload;
    function AppendRawFile(LocSep: Boolean; Size: Integer; Src: Pointer): Integer; overload;
  published
  end;



implementation


(*
 Implementation of TDataAccess
*)

function TDataAccess.ExtractFileIDOfName(Name: String): Integer;
begin
  if Name[5] = '-' then
    Result := StrToInt(MidStr(Name, 1, 4))
  else
    Result := StrToInt(MidStr(Name, 1, 5));
end;


function TDataAccess.GetFileInfo(FileID: Integer): TFileInfo;
begin
  Result.ID := -1;
  Result.Name := '';
  Result.Extension := '';
  Result.Size := -1;
  Result.FileType := 0;
  Result.DatAddr := -1;
end;


function TDataAccess.GetFileInfoByName(Name: String): TFileInfo;
var
  i:     Integer;
  files: TStrings;
begin
  Result := GetFileInfo(-1);
  files  := GetFilesList('', Name, False, ST_IDAsc);
  if files.Count = 0 then
  else
  begin
    for i := 0 to files.Count - 1 do
    begin
      if MidStr(files.Strings[i], Pos('-', files.Strings[i]) + 1,
            Length(files.Strings[i]) - Pos('-', files.Strings[i]) - 5) = name then
      begin
        Result := GetFileInfo(ExtractFileIDOfName(files.Strings[i]));
        Break;
      end;
    end;
  end;
  files.Free;
end;


procedure TDataAccess.LoadDatFile(FileID: Integer; var Target: TByteData);
var
  data: TStream;
begin
  if fileid < GetFileCount then
  begin
    data := nil;
    LoadDatFile(FileID, data);
    SetLength(Target, data.Size);
    data.Read(Target[0], data.Size);
    data.Free;
  end;
end;

procedure TDataAccess.UpdateDatFile(FileID: Integer; Src: TByteData);
var
  data: TStream;
begin
  if fileid < GetFileCount then
  begin
    data := TMemoryStream.Create;
    data.Write(Src[0], Length(Src));
    data.Seek(0, soFromBeginning);
    UpdateDatFile(FileID, data);
    data.Free;
  end;
end;

procedure TDataAccess.LoadDatFilePart(FileID, Offset, Size: Integer; var Target: TByteData);
var
  data: TStream;
begin
  if fileid < GetFileCount then
  begin
    data := nil;
    LoadDatFilePart(FileID, offset, size, data);
    SetLength(Target, data.Size);
    data.Read(Target[0], data.Size);
    data.Free;
  end;
end;

procedure TDataAccess.LoadDatFilePart(FileID, Offset, Size: Integer; Target: Pointer);
var
  data: TStream;
begin
  if fileid < GetFileCount then
  begin
    data := nil;
    LoadDatFilePart(FileID, offset, size, data);
    data.Read(Target^, data.Size);
    data.Free;
  end;
end;

procedure TDataAccess.UpdateDatFilePart(FileID, Offset, Size: Integer; Src: Pointer);
var
  data: TStream;
begin
  if fileid < GetFileCount then
  begin
    data := TMemoryStream.Create;
    data.Write(Src^, Size);
    data.Seek(0, soFromBeginning);
    UpdateDatFilePart(FileID, offset, size, data);
    data.Free;
  end;
end;



procedure TDataAccess.LoadRawFile(FileID, DatOffset: Integer; var Target: TByteData);
var
  data: TStream;
begin
  if fileid < GetFileCount then
  begin
    data := nil;
    LoadRawFile(FileID, DatOffset, data);
    SetLength(Target, data.Size);
    data.Read(Target[0], data.Size);
    data.Free;
  end;
end;

procedure TDataAccess.UpdateRawFile(FileID, DatOffset: Integer; Src: TByteData);
var
  data: TStream;
begin
  if fileid < GetFileCount then
  begin
    data := TMemoryStream.Create;
    data.Write(Src[0], Length(Src));
    data.Seek(0, soFromBeginning);
    UpdateRawFile(FileID, DatOffset, data);
    data.Free;
  end;
end;

procedure TDataAccess.LoadRawFilePart(FileID, DatOffset, Offset, Size: Integer; var Target: TByteData);
var
  data: TStream;
begin
  if fileid < GetFileCount then
  begin
    data := nil;
    SetLength(Target, Size);
    LoadRawFile(FileID, DatOffset, Data);
    Data.Seek(Offset, soFromBeginning);
    Data.Read(Target[0], Size);
    Data.Free;
  end;
end;

procedure TDataAccess.LoadRawFilePart(FileID, DatOffset, Offset, Size: Integer; Target: Pointer);
var
  data: TStream;
begin
  if fileid < GetFileCount then
  begin
    data := nil;
    LoadRawFile(FileID, DatOffset, Data);
    Data.Seek(Offset, soFromBeginning);
    Data.Read(Target^, Size);
    Data.Free;
  end;
end;

procedure TDataAccess.UpdateRawFilePart(FileID, DatOffset, Offset, Size: Integer; Src: Pointer);
var
  data: TStream;
begin
  if fileid < GetFileCount then
  begin
    data := TMemoryStream.Create;
    data.Write(Src^, Size);
    data.Seek(0, soFromBeginning);
    UpdateRawFilePart(FileID, DatOffset, Offset, Size, data);
    data.Free;
  end;
end;


function TDataAccess.AppendRawFile(LocSep: Boolean; Src: TStream): Integer;
begin
  raise ENotImplemented.Create('ERROR: AppendRawFile not implemented here!!!');
end;


function TDataAccess.AppendRawFile(LocSep: Boolean; Src: TByteData): Integer;
var
  data: TStream;
begin
  data := TMemoryStream.Create;
  data.Write(Src[0], Length(Src));
  data.Seek(0, soFromBeginning);
  Result := AppendRawFile(LocSep, data);
  data.Free;
end;

function TDataAccess.AppendRawFile(LocSep: Boolean; Size: Integer; Src: Pointer): Integer;
var
  data: TStream;
begin
  data := TMemoryStream.Create;
  data.Write(Src^, Size);
  data.Seek(0, soFromBeginning);
  Result := AppendRawFile(LocSep, data);
  data.Free;
end;



procedure TDataAccess.SetDataOS(DataOS: TDataOS);
begin
  raise ENotImplemented.Create('TDataAccess.SetDataOS: TBD!');
end;

end.
