unit _DataTypes;

interface

uses
  Classes, _TreeElement;

type
  TDataField = class(TTreeElement)
      function GetChildCount: Integer; override;
      function GetChild(ID: Integer): TTreeElement; override;
      function GetCaption: String; override;
    protected
      FOffset: Integer;
      FName:   String;
      FDescription: String;
      FDataLength: Integer;
      FParentFile: TObject;
      FParentField: TDataField;
      FChanged: Boolean;
      function GetValueAsString: String; virtual; abstract;
    public
      constructor Create(ParentFile: TObject; ParentField: TDataField;
          Offset: Integer; Name, Description: String; ExtraArgs: Pointer); virtual;

      procedure Update(Offset, Length: Integer); virtual; abstract;

      property Offset: Integer read FOffset;
      property Name: String read FName;
      property Description: String read FDescription;
      property DataLength: Integer read FDataLength;
      property ValueAsString: String read GetValueAsString;
  end;

  TFieldType = class of TDataField;


  TBlock = class(TDataField)
    private
      FDataFields: array of TDataField;
      FBlockLength: Integer;
      function GetChildCount: Integer; override;
      function GetChild(ID: Integer): TTreeElement; override;
      function GetFieldByOffset(Offset: Integer): TDataField;
    public
      // ExtraArgs: Pointer auf Integer: BlockLength
      constructor Create(ParentFile: TObject; ParentField: TDataField;
          Offset: Integer; Name, Description: String; ExtraArgs: Pointer); override;
      procedure Update(Offset, Length: Integer); override;
      property FieldByOffset[Offset: Integer]: TDataField read GetFieldByOffset;

      function AddField(fieldtype: TFieldType; Offset: Integer;
          Name, Description: String; ExtraArgs: Pointer): TDataField;
  end;


  TInt = class(TDataField)
    private
      FInt: Integer;
      function GetValueAsString: String; override;
    public
      // ExtraArgs: Pointer auf Integer: Bytes of TInt
      constructor Create(ParentFile: TObject; ParentField: TDataField;
          Offset: Integer; Name, Description: String; ExtraArgs: Pointer); override;
      procedure Update(Offset, Length: Integer); override;
  end;


  TBitSet = class(TDataField)
    private
      FBits: Byte;
      FNames: TStringList;
      function GetValueAsString: String; override;
    public
      // ExtraArgs: Pointer auf TStringList
      constructor Create(ParentFile: TObject; ParentField: TDataField;
          Offset: Integer; Name, Description: String; ExtraArgs: Pointer); override;
      procedure Update(Offset, Length: Integer); override;
  end;


  TLevelID = class(TDataField)
    private
      FLevelID: Integer;
      function GetValueAsString: String; override;
    public
      // ExtraArgs: keine
      constructor Create(ParentFile: TObject; ParentField: TDataField;
          Offset: Integer; Name, Description: String; ExtraArgs: Pointer); override;
      procedure Update(Offset, Length: Integer); override;
  end;


  TFileID = class(TDataField)
    private
      FFileID: Integer;
      function GetValueAsString: String; override;
    public
      // ExtraArgs: keine
      constructor Create(ParentFile: TObject; ParentField: TDataField;
          Offset: Integer; Name, Description: String; ExtraArgs: Pointer); override;
      procedure Update(Offset, Length: Integer); override;
  end;


  TLinkByID = class(TDataField)
      function GetChildCount: Integer; override;
      function GetChild(ID: Integer): TTreeElement; override;
    private
      FFileID: Integer;
      FPosExts: String;
      function GetValueAsString: String; override;
    public
      // ExtraArgs: Pointer auf String: Possible Exts
      constructor Create(ParentFile: TObject; ParentField: TDataField;
          Offset: Integer; Name, Description: String; ExtraArgs: Pointer); override;
      procedure Update(Offset, Length: Integer); override;
  end;


  TString = class(TDataField)
    private
      FString: String;
      function GetValueAsString: String; override;
    public
      // ExtraArgs: Pointer auf Integer: Length
      constructor Create(ParentFile: TObject; ParentField: TDataField;
          Offset: Integer; Name, Description: String; ExtraArgs: Pointer); override;
      procedure Update(Offset, Length: Integer); override;
  end;


  TArrayArgs = packed record
    CounterSize: Integer;
    BlockLength: Integer;
    BlockCount:  Integer;
  end;
  TArray = class(TDataField)
    private
      FDataFields: array of TBlock;
      function GetChildCount: Integer; override;
      function GetChild(ID: Integer): TTreeElement; override;
      function GetFieldByOffset(Offset: Integer): TDataField;
    public
      // ExtraArgs: Pointer auf 3 Integer: CounterSize+Length+Count (packed record...)
      constructor Create(ParentFile: TObject; ParentField: TDataField;
          Offset: Integer; Name, Description: String; ExtraArgs: Pointer); override;
      procedure Update(Offset, Length: Integer); override;

      function AddField(fieldtype: TFieldType; Offset: Integer;
          Name, Description: String; ExtraArgs: Pointer): TDataField;
  end;


  TRawLink = class(TDataField)
    private
      FRawAddress: Integer;
      function GetValueAsString: String; override;
    public
      // ExtraArgs: keine
      constructor Create(ParentFile: TObject; ParentField: TDataField;
          Offset: Integer; Name, Description: String; ExtraArgs: Pointer); override;
      procedure Update(Offset, Length: Integer); override;
  end;


  TUnused = class(TDataField)
    private
      function GetValueAsString: String; override;
    public
      // ExtraArgs: Pointer auf Integer: Length
      constructor Create(ParentFile: TObject; ParentField: TDataField;
          Offset: Integer; Name, Description: String; ExtraArgs: Pointer); override;
      procedure Update(Offset, Length: Integer); override;
  end;




implementation

uses
  SysUtils, Dialogs, _FileTypes, ConnectionManager;


  

{ TDataType }

constructor TDataField.Create(ParentFile: TObject; ParentField: TDataField;
    Offset: Integer; Name, Description: String; ExtraArgs: Pointer);
begin
  FOffset := Offset;
  FName := Name;
  FDescription := Description;
  FParentFile := ParentFile;
  FParentField := ParentField;
  FConnectionID := TFile(ParentFile).ConnectionID;
end;

function TDataField.GetCaption: String;
begin
  Result := FName;
end;

function TDataField.GetChild(ID: Integer): TTreeElement;
begin
  Result := nil;
end;

function TDataField.GetChildCount: Integer;
begin
  Result := 0;
end;



{ TString }

constructor TString.Create(ParentFile: TObject; ParentField: TDataField;
    Offset: Integer; Name, Description: String; ExtraArgs: Pointer);
var
  fstream: TMemoryStream;
  i: Integer;
begin
  inherited Create(ParentFile, ParentField, Offset, Name, Description, ExtraArgs);
  FDataLength := Integer(ExtraArgs^);
  fstream := TFile(ParentFile).FileStream;
  fstream.Seek(Offset, soFromBeginning);
  SetLength(FString, FDataLength); 
  fstream.Read(FString[1], FDataLength);
  for i := 1 to FDataLength do
    if FString[i] = Chr(0) then
    begin
      SetLength(FString, i - 1);
      Break;
    end;
end;

function TString.GetValueAsString: String;
begin
  Result := FString;
end;

procedure TString.Update(Offset, Length: Integer);
begin
  Exit;
end;



{ TInt }

constructor TInt.Create(ParentFile: TObject; ParentField: TDataField;
    Offset: Integer; Name, Description: String; ExtraArgs: Pointer);
var
  fstream: TMemoryStream;
begin
  inherited Create(ParentFile, ParentField, Offset, Name, Description, ExtraArgs);
  FDataLength := Integer(ExtraArgs^);
  FInt := 0;
  fstream := TFile(ParentFile).FileStream;
  fstream.Seek(Offset, soFromBeginning);
  fstream.Read(FInt, FDataLength);
end;

function TInt.GetValueAsString: String;
begin
  Result := IntToStr(FInt);
end;

procedure TInt.Update(Offset, Length: Integer);
begin
  Exit;
end;



{ TArray }

function TArray.AddField(fieldtype: TFieldType; Offset: Integer;
    Name, Description: String; ExtraArgs: Pointer): TDataField;
var
  i: Integer;
begin
(*
  if Length(FDataFields) > 0 then
  begin
    for i := 0 to High(FDataFields) do
      if FDataFields[i].FOffset = Offset then
        Break;
    if i < Length(FDataFields) then
    begin
      ShowMessage('Field already exists');
      Exit;
    end;
  end;
  SetLength(FDataFields, Length(FDataFields) + 1);
  FDataFields[High(FDataFields)] := TFieldType(fieldtype).Create(
      FParentFile, Self, Offset, Name, Description, ExtraArgs);
  Result := FDataFields[High(FDataFields)];
*)
end;

constructor TArray.Create(ParentFile: TObject; ParentField: TDataField;
    Offset: Integer; Name, Description: String; ExtraArgs: Pointer);
var
  i: Integer;
  args: TArrayArgs;
  fstream: TMemoryStream;
begin
  inherited Create(ParentFile, ParentField, Offset, Name, Description, ExtraArgs);
  args := TArrayArgs(ExtraArgs^);
  if args.CounterSize > 0 then
  begin
    fstream := TFile(ParentFile).FileStream;
    fstream.Seek(Offset, soFromBeginning);
    args.BlockCount := 0;
    fstream.Read(args.BlockCount, args.CounterSize);
  end;
  SetLength(FDataFields, args.BlockCount);
  if Length(FDataFields) > 0 then
  begin
    for i := 0 to High(FDataFields) do
    begin
      FDataFields[i] := TBlock.Create(ParentFile, Self,
          Offset + args.CounterSize + i * args.BlockLength, Name+'['+IntToStr(i)+']', '', @args.BlockLength);
    end;
  end;
end;

function TArray.GetChildCount: Integer;
begin
  Result := Length(FDataFields);
end;

function TArray.GetChild(ID: Integer): TTreeElement;
begin
  Result := FDataFields[ID];
end;

function TArray.GetFieldByOffset(Offset: Integer): TDataField;
begin
  Exit;
end;

procedure TArray.Update(Offset, Length: Integer);
begin
  Exit;
end;



{ TBlock }

function TBlock.AddField(fieldtype: TFieldType; Offset: Integer; Name,
    Description: String; ExtraArgs: Pointer): TDataField;
var
  i: Integer;
begin
  if Length(FDataFields) > 0 then
  begin
    for i := 0 to High(FDataFields) do
      if FDataFields[i].FOffset = Offset then
        Break;
    if i < Length(FDataFields) then
    begin
      ShowMessage('Field already exists');
      Exit;
    end;
  end;
  SetLength(FDataFields, Length(FDataFields) + 1);
  FDataFields[High(FDataFields)] := TFieldType(fieldtype).Create(
      FParentFile, Self, Offset, Name, Description, ExtraArgs);
  Result := FDataFields[High(FDataFields)];
end;

constructor TBlock.Create(ParentFile: TObject; ParentField: TDataField;
    Offset: Integer; Name, Description: String; ExtraArgs: Pointer);
begin
  inherited Create(ParentFile, ParentField, Offset, Name, Description, ExtraArgs);
  if ExtraArgs <> nil then
    FBlockLength := Integer(ExtraArgs^)
  else
    FBlockLength := -1;
end;

function TBlock.GetChild(ID: Integer): TTreeElement;
begin
  Result := FDataFields[ID];
end;

function TBlock.GetChildCount: Integer;
begin
  Result := Length(FDataFields);
end;

function TBlock.GetFieldByOffset(Offset: Integer): TDataField;
begin
  Exit;
end;

procedure TBlock.Update(Offset, Length: Integer);
begin
  Exit;
end;



{ TLevelID }

constructor TLevelID.Create(ParentFile: TObject; ParentField: TDataField;
    Offset: Integer; Name, Description: String; ExtraArgs: Pointer);
var
  fstream: TMemoryStream;
begin
  inherited Create(ParentFile, ParentField, Offset, Name, Description, ExtraArgs);
  FDataLength := 4;
  fstream := TFile(ParentFile).FileStream;
  fstream.Seek(Offset, soFromBeginning);
  fstream.Read(FLevelID, 4);
  FLevelID := FLevelID div 256 div 256 div 256 div 2;
end;

function TLevelID.GetValueAsString: String;
begin
  Result := IntToStr(FLevelID);
end;

procedure TLevelID.Update(Offset, Length: Integer);
begin
  Exit;
end;



{ TFileID }

constructor TFileID.Create(ParentFile: TObject; ParentField: TDataField;
    Offset: Integer; Name, Description: String; ExtraArgs: Pointer);
var
  fstream: TMemoryStream;
begin
  inherited Create(ParentFile, ParentField, Offset, Name, Description, ExtraArgs);
  FDataLength := 4;
  fstream := TFile(ParentFile).FileStream;
  fstream.Seek(Offset, soFromBeginning);
  fstream.Read(FFileID, 4);
  if FFileID > 0 then
    FFileID := FFileID div 256
  else
    FFileID := -1;
end;

function TFileID.GetValueAsString: String;
begin
  Result := IntToStr(FFileID);
end;

procedure TFileID.Update(Offset, Length: Integer);
begin
  Exit;
end;



{ TLinkByID }

constructor TLinkByID.Create(ParentFile: TObject; ParentField: TDataField;
    Offset: Integer; Name, Description: String; ExtraArgs: Pointer);
var
  fstream: TMemoryStream;
begin
  inherited Create(ParentFile, ParentField, Offset, Name, Description, ExtraArgs);
  FDataLength := 4;
  FPosExts := String(ExtraArgs^);
  fstream := TFile(ParentFile).FileStream;
  fstream.Seek(Offset, soFromBeginning);
  fstream.Read(FFileID, 4);
  if FFileID > 0 then
    FFileID := FFileID div 256
  else
    FFileID := -1;
end;

function TLinkByID.GetChild(ID: Integer): TTreeElement;
begin
  if FFileID > 0 then
    Result := ConManager.Connection[FConnectionID].MetaData.FileById[FFileID].Child[ID]
  else
    Result := nil;
end;

function TLinkByID.GetChildCount: Integer;
begin
  if FFileID > 0 then
    Result := ConManager.Connection[FConnectionID].MetaData.FileById[FFileID].ChildCount
  else
    Result := 0;
end;

function TLinkByID.GetValueAsString: String;
begin
  Result := IntToStr(FFileID);
end;

procedure TLinkByID.Update(Offset, Length: Integer);
begin
  Exit;
end;



{ TRawLink }

constructor TRawLink.Create(ParentFile: TObject; ParentField: TDataField;
    Offset: Integer; Name, Description: String; ExtraArgs: Pointer);
var
  fstream: TMemoryStream;
begin
  inherited Create(ParentFile, ParentField, Offset, Name, Description, ExtraArgs);
  FDataLength := 4;
  fstream := TFile(ParentFile).FileStream;
  fstream.Seek(Offset, soFromBeginning);
  fstream.Read(FRawAddress, 4);
end;

function TRawLink.GetValueAsString: String;
begin
  Result := IntToStr(FRawAddress);
end;

procedure TRawLink.Update(Offset, Length: Integer);
begin
  Exit;
end;



{ TUnused }

constructor TUnused.Create(ParentFile: TObject; ParentField: TDataField;
    Offset: Integer; Name, Description: String; ExtraArgs: Pointer);
begin
  inherited Create(ParentFile, ParentField, Offset, Name, Description, ExtraArgs);
  FDataLength := Integer(ExtraArgs^);
end;

function TUnused.GetValueAsString: String;
begin
  Result := '';
end;

procedure TUnused.Update(Offset, Length: Integer);
begin
  Exit;
end;



{ TBitSet }

constructor TBitSet.Create(ParentFile: TObject; ParentField: TDataField;
    Offset: Integer; Name, Description: String; ExtraArgs: Pointer);
var
  fstream: TMemoryStream;
begin
  inherited Create(ParentFile, ParentField, Offset, Name, Description, ExtraArgs);
  FNames := TStringList.Create;
  FNames.AddStrings(TStringList(ExtraArgs^));
  FDataLength := 1;
  FBits := 0;
  fstream := TFile(ParentFile).FileStream;
  fstream.Seek(Offset, soFromBeginning);
  fstream.Read(FBits, FDataLength);
end;

function TBitSet.GetValueAsString: String;
begin
  Result := IntToStr(FBits);
end;

procedure TBitSet.Update(Offset, Length: Integer);
begin
  Exit;
end;

end.
