unit _FileTypes;

interface

uses
  TypeDefs, _DataTypes, Classes, Forms;


type
  TFile = class
    protected
      FConnectionID: Integer;
      FFileID: Integer;
      FFileName: String;
      FFileExt: String;
      FFileSize: Integer;
      FFileStream: TMemoryStream;

      FCached: Boolean;
      FChanged: Boolean;

      FDatLinks: TDatLinkList;
      FDataFields: TBlock;
      FRawParts: TRawDataList;

      FEditor: TFrame;
      FOpened: Boolean;

      procedure InitDatLinks;
      procedure InitRawList;

      function GetDatLinkByOffset(Offset: Integer): TDatLink;
      function GetDatLinkByIndex(ID: Integer): TDatLink;
      function GetFieldByOffset(Offset: Integer): TDataField;
      function GetFieldByIndex(ID: Integer): TDataField;
      function GetRawPartByOffset(Offset: Integer): TRawDataInfo;
      function GetRawPartByIndex(ID: Integer): TRawDataInfo;
      function GetChildCount: Integer;
    public
      constructor Create(ConnectionID, FileID: Integer); virtual;
      procedure Free;

      procedure InitDataFields; virtual;
      procedure InitEditor; virtual;

      property FileStream: TMemoryStream read FFileStream;
      property FileID: Integer read FFileID;
      property FileName: String read FFileName;
      property FileExt: String read FFileExt;
      property FileSize: Integer read FFileSize;
      property ConnectionID: Integer read FConnectionID;

      property Cached: Boolean read FCached;
      property Changed: Boolean read FChanged write FChanged;

      property Editor: TFrame read FEditor;
      property Opened: Boolean read FOpened write FOpened;

      property ChildCount: Integer read GetChildCount;
      property LinkByOffset[Offset: Integer]: TDatLink read GetDatLinkByOffset;
      property LinkByIndex[ID: Integer]: TDatLink read GetDatLinkByIndex;

      property FieldByOffset[Offset: Integer]: TDataField read GetFieldByOffset;
      property FieldByIndex[ID: Integer]: TDataField read GetFieldByIndex;

      property RawPartByOffset[Offset: Integer]: TRawDataInfo read GetRawPartByOffset;
      property RawPartByIndex[ID: Integer]: TRawDataInfo read GetRawPartByIndex;
  end;


  TFileType = class of TFile;


function GetDatLinkValue(stream: TStream; offset: Integer): Integer;



implementation

uses
  DatLinks, RawList, ConnectionManager, Dialogs, _EmptyFile;

{ TFileType }

constructor TFile.Create(ConnectionID, FileID: Integer);
var
  fileinfo: TFileInfo;
begin
  FConnectionID := ConnectionID;
  FFileID := FileID;
  fileinfo := ConManager.Connection[ConnectionID].GetFileInfo(FileID);
  FFileName := fileinfo.Name;
  FFileExt := fileinfo.Extension;
  FFileSize := fileinfo.Size;

  FCached := False;
  FChanged := False;

  if not (Self is TFile_Empty) then
  begin
    FFileStream := TMemoryStream.Create;
    ConManager.Connection[ConnectionID].LoadDatFile(FileID, TStream(FFileStream));

    InitDatLinks();
    InitRawList();
    FDataFields := nil;
    FEditor := nil;

    FFileStream.Free;
    FFileStream := nil;
  end
  else
  begin
    SetLength(FDatLinks, 0);
    SetLength(FRawParts, 0);
    FEditor := nil;
  end;
end;


procedure TFile.Free;
begin
  FDataFields.Free;
end;

function TFile.GetDatLinkByIndex(ID: Integer): TDatLink;
var
  i: Integer;
  valids: Integer;
begin
  if ID < GetChildCount then
  begin
    valids := 0;
    i := 0;
    repeat
      if FDatLinks[i].DestID >= 0 then
      begin
        Inc(valids);
      end;
      Inc(i);
    until valids > ID;
    Result := FDatLinks[i - 1];
  end
  else
    with Result do
    begin
      SrcOffset := -1;
      DestID := -1;
      PosDestExts := '';
    end;
end;

function TFile.GetDatLinkByOffset(Offset: Integer): TDatLink;
var
  i: Integer;
begin
  Result.SrcOffset := -1;
  Result.DestID := -1;
  Result.PosDestExts := '';
  
  if Length(FDatLinks) > 0 then
  begin
    for i := 0 to High(FDatLinks) do
      if FDatLinks[i].SrcOffset = Offset then
        break;
    if i < Length(FDatLinks) then
      Result := FDatLinks[i];
  end;
end;


function TFile.GetFieldByIndex(ID: Integer): TDataField;
begin
  Result := FDataFields.FieldByIndex[ID];
end;

function TFile.GetFieldByOffset(Offset: Integer): TDataField;
begin
  Result := FDataFields.FieldByOffset[Offset];
end;


function TFile.GetChildCount: Integer;
var
  i: Integer;
begin
  Result := Length(FDatLinks);
  if Result > 0 then
  begin
    Result := 0;
    for i := 0 to High(FDatLinks) do
      if FDatLinks[i].DestID >= 0 then
        Inc(Result);
  end;
end;

function TFile.GetRawPartByIndex(ID: Integer): TRawDataInfo;
begin
  if ID < Length(FRawParts) then
    Result := FRawParts[ID]
  else
    with Result do
    begin
      SrcID := -1;
      SrcOffset := -1;
      RawAddr := -1;
      RawSize := -1;
    end;
end;

function TFile.GetRawPartByOffset(Offset: Integer): TRawDataInfo;
var
  i: Integer;
begin
  with Result do
  begin
    SrcID := -1;
    SrcOffset := -1;
    RawAddr := -1;
    RawSize := -1;
  end;

  if Length(FRawParts) > 0 then
  begin
    for i := 0 to High(FRawParts) do
      if FRawParts[i].SrcOffset = Offset then
        break;
    if i < Length(FRawParts) then
      Result := FRawParts[i];
  end;
end;



procedure TFile.InitDataFields;
begin
  if Assigned(FDataFields) then
    Exit;
end;

procedure TFile.InitDatLinks;
begin
  FDatLinks := ConManager.Connection[FConnectionID].GetDatLinks(FFileID);
end;

procedure TFile.InitEditor;
begin
  Exit;
end;

procedure TFile.InitRawList;
begin
  FRawParts := ConManager.Connection[FConnectionID].GetRawList(FFileID);
end;

function GetDatLinkValue(stream: TStream; offset: Integer): Integer;
begin
  stream.Seek(Offset, soFromBeginning);
  stream.Read(Result, 4);
  if Result > 0 then
    Result := Result div 256
  else
    Result := -1;
end;

end.
