unit _DataTypes;

interface

uses
  Classes;

type
  TDataField = class
    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;
      function GetFieldByOffset(Offset: Integer): TDataField;
      function GetFieldByIndex(ID: Integer): TDataField;
      function GetFieldCount: Integer;
    public
      // ExtraArgs: keine
      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;
      property FieldByIndex[ID: Integer]: TDataField read GetFieldByIndex;
      property FieldCount: Integer read GetFieldCount;

      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)
    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;


  TArray = class(TDataField)
    private
      FDataFields: array of TDataField;
      function GetFieldByOffset(Offset: Integer): TDataField;
      function GetFieldByIndex(ID: Integer): TDataField;
      function GetFieldCount: Integer;
    public
      // ExtraArgs: Pointer auf 2 Integer: Length+Count (packed record...)
      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;
      property FieldByIndex[ID: Integer]: TDataField read GetFieldByIndex;
      property FieldCount: Integer read GetFieldCount;

      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;
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;
begin
  Exit;
end;

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

function TArray.GetFieldByIndex(ID: Integer): TDataField;
begin
  if ID < Length(FDataFields) then
    Result := FDataFields[ID]
  else
    Result := nil;
end;

function TArray.GetFieldByOffset(Offset: Integer): TDataField;
var
  i: Integer;
begin
  Result := nil;

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

function TArray.GetFieldCount: Integer;
begin
  Result := Length(FDataFields);
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);
end;

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

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

function TBlock.GetFieldCount: Integer;
begin
  Result := Length(FDataFields);
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.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.
