UNIT Unit8_binedit;
INTERFACE
USES
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Wrapgrid, StdCtrls, Grids, StrUtils, MPHexEditor, ExtCtrls,
  Unit3_data, Unit2_functions, Unit9_data_structures;

TYPE
  TForm8 = Class(TForm)
    list: TListBox;
    Splitter1: TSplitter;
    panel_data: TPanel;
    hex: TMPHexEditor;
    Splitter2: TSplitter;
    structs: TWrapGrid;
    PROCEDURE hexSelectionChanged(Sender: TObject);
    PROCEDURE hexChange(Sender: TObject);
    PROCEDURE panel_dataResize(Sender: TObject);
    PROCEDURE structsClick(Sender: TObject);
    PROCEDURE FormResize(Sender: TObject);
    PROCEDURE ClearStructViewer;
    PROCEDURE listClick(Sender: TObject);
    PROCEDURE FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    PROCEDURE FormCreate(Sender: TObject);
    PROCEDURE Recreatelist;
  PRIVATE
  PUBLIC
  END;

VAR
  Form8: TForm8;

IMPLEMENTATION
{$R *.dfm}
VAR
  fileid:LongWord;

FUNCTION IntToBin(value:Byte):String;
  VAR i:Byte;
  BEGIN
    Result:='';
    FOR i:=7 DOWNTO 0 DO BEGIN
      Result:=Result+IntToStr((value SHR i) AND $01);
    END;
  END;

FUNCTION GetTypeDataLength(datatype:Byte):Byte;
  BEGIN
    CASE datatype OF
      1..4: Result:=datatype;
      5..8: Result:=datatype-4;
      9: Result:=4;
      10: Result:=1;
      11..255: Result:=datatype-10;
    END;
  END;

FUNCTION GetValue(datatype:Byte; offset:LongWord):String;
  VAR
    data:Tdata;
  BEGIN
    CASE datatype OF
      1: Result:=IntToStr(Form8.hex.data[offset]);
      2: Result:=IntToStr(Form8.hex.data[offset]+Form8.hex.data[offset+1]*256);
      3: Result:=IntToStr(Form8.hex.data[offset]+Form8.hex.data[offset+1]*256+Form8.hex.data[offset+2]*256*256);
      4: Result:=IntToStr(Form8.hex.data[offset]+Form8.hex.data[offset+1]*256+Form8.hex.data[offset+2]*256*256+Form8.hex.data[offset+3]*256*256*256);
      5: Result:='0x'+IntToHex(Form8.hex.data[offset],2);
      6: Result:='0x'+IntToHex(Form8.hex.data[offset]+Form8.hex.data[offset+1]*256,4);
      7: Result:='0x'+IntToHex(Form8.hex.data[offset]+Form8.hex.data[offset+1]*256+Form8.hex.data[offset+2]*256*256,6);
      8: Result:='0x'+IntToHex(Form8.hex.data[offset]+Form8.hex.data[offset+1]*256+Form8.hex.data[offset+2]*256*256+Form8.hex.data[offset+3]*256*256*256,8);
      9: BEGIN
          SetLength(data,4);
          data[0]:=Form8.hex.data[offset];
          data[1]:=Form8.hex.data[offset+1];
          data[2]:=Form8.hex.data[offset+2];
          data[3]:=Form8.hex.data[offset+3];
          Result:=FloatToStr(Decode_Float(data));
        END;
      10: Result:=IntToBin(Form8.hex.data[offset]);
    END;
  END;

PROCEDURE WriteStructureInfos(structinfoid:Integer);
  VAR
    i:Byte;
  BEGIN
    IF structinfoid>=0 THEN BEGIN
      WITH structure_infos[structinfoid] DO BEGIN
        Form8.structs.RowCount:=Length(entries)+1;
        FOR i:=1 TO Length(entries) DO BEGIN
          Form8.structs.Cells[0,i]:=entries[i-1].name;
          Form8.structs.Cells[1,i]:='0x'+IntToHex(entries[i-1].offset,6);
          Form8.structs.Cells[2,i]:=GetDataType(entries[i-1].datatype);
          Form8.structs.Cells[3,i]:=GetValue(entries[i-1].datatype,entries[i-1].offset);
          Form8.structs.Cells[4,i]:=entries[i-1].description;
        END;
      END;
    END;
  END;

PROCEDURE TForm8.Recreatelist;
  VAR
    i:LongWord;
  BEGIN
    Form8.list.Items.Clear;
    FOR i:=0 TO dat_header.Files-1 DO BEGIN
      IF (dat_files[i].FileType AND $02)=0 THEN
        Form8.list.Items.Add(dat_files[i].FileName);
    END;
  END;

PROCEDURE TForm8.FormCreate(Sender: TObject);
  BEGIN
    Form8.Caption:='';
    fileid:=0;
    structs.ColCount:=5;
    structs.RowCount:=2;
    structs.FixedRows:=1;
    structs.Cells[0,0]:='Name';
    structs.Cells[1,0]:='Offset';
    structs.Cells[2,0]:='Type';
    structs.Cells[3,0]:='Value';
    structs.Cells[4,0]:='Description';
    structs.ColWidths[0]:=75;
    structs.ColWidths[1]:=60;
    structs.ColWidths[2]:=75;
    structs.ColWidths[3]:=75;
    Form8.panel_dataResize(Form8);
  END;

PROCEDURE TForm8.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  BEGIN
    CanClose:=False;
    Form8.Visible:=False;
  END;

PROCEDURE TForm8.listClick(Sender: TObject);
  VAR
    mem:TMemoryStream;
    data:Tdata;
  BEGIN
    IF hex.Modified THEN BEGIN
      IF MessageBox(Form8.Handle,PChar('Save changes to file '+dat_files[fileid].FileName+'?'),PChar('Data changed...'),MB_YESNO)=IDYES THEN BEGIN
        mem:=TMemoryStream.Create;
        hex.SaveToStream(mem);
        mem.Seek(0,soFromBeginning);
        SetLength(data,mem.Size);
        mem.Read(data[0],mem.Size); 
        mem.Free;
        SaveDatFile(fileid,data);
        ShowMessage('Changes saved...');
      END;
    END;
    Form8.ClearStructViewer;
    fileid:=StrToInt(MidStr(list.Items.Strings[list.ItemIndex],1,5));
    data:=LoadDatFile(fileid);
    mem:=TMemoryStream.Create;
    mem.Write(data[0],Length(data));
    hex.LoadFromStream(mem);
    mem.Free;
    WriteStructureInfos(GetStructureInfoId(dat_files[fileid].Extension));
  END;

PROCEDURE TForm8.ClearStructViewer;
  VAR
    x:Word;
  BEGIN
    structs.RowCount:=2;
    FOR x:=0 TO structs.ColCount-1 DO structs.Cells[x,1]:='';
  END;

PROCEDURE TForm8.FormResize(Sender: TObject);
  BEGIN
    IF Form8.Width>=650 THEN BEGIN
    END ELSE Form8.Width:=650;
    IF Form8.Height>=450 THEN BEGIN
    END ELSE Form8.Height:=450;
  END;

PROCEDURE TForm8.structsClick(Sender: TObject);
  VAR
    offset:LongWord;
    length:Byte;
  BEGIN
    IF structs.Row>0 THEN BEGIN
      offset:=structure_infos[GetStructureInfoId(dat_files[fileid].extension)].entries[structs.Row-1].offset;
      length:=GetTypeDataLength(structure_infos[GetStructureInfoId(dat_files[fileid].extension)].entries[structs.Row-1].datatype);
      hex.SelStart:=offset;
      hex.SelEnd:=offset+length-1;
    END;
  END;

PROCEDURE TForm8.panel_dataResize(Sender: TObject);
  BEGIN
    structs.ColWidths[4]:=structs.Width-structs.ColWidths[0]-structs.ColWidths[1]-structs.ColWidths[2]-structs.ColWidths[3]-12;
  END;

PROCEDURE TForm8.hexChange(Sender: TObject);
  BEGIN
    IF hex.DataSize>0 THEN
      WriteStructureInfos(GetStructureInfoId(dat_files[fileid].Extension));
  END;

PROCEDURE TForm8.hexSelectionChanged(Sender: TObject);
  VAR
    selstart,sellength,selend:Integer;
    i,j:Word;
  BEGIN
    FOR i:=1 TO structs.RowCount-1 DO BEGIN
      FOR j:=0 TO structs.ColCount-1 DO BEGIN
        structs.CellColors[j,i]:=clWhite;
        structs.CellFontColors[j,i]:=clBlack;
      END;
    END;
    IF hex.DataSize>0 THEN BEGIN
      selstart:=hex.SelStart;
      selend:=hex.SelEnd;
      sellength:=hex.SelCount;
      IF GetStructureInfoId(dat_files[fileid].Extension)>=0 THEN BEGIN
        WITH structure_infos[GetStructureInfoId(dat_files[fileid].Extension)] DO BEGIN
          FOR i:=0 TO High(entries) DO BEGIN
            IF ((selstart-entries[i].offset)<GetTypeDataLength(entries[i].datatype)) AND ((selstart-entries[i].offset)>=0) THEN BEGIN
              FOR j:=0 TO structs.ColCount-1 DO BEGIN
                structs.CellColors[j,i+1]:=clBlue;
                structs.CellFontColors[j,i+1]:=clWhite;
              END;
              structs.Row:=i+1;
            END;
          END;
        END;
      END;
    END;
  END;

END.
