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, Unit4_exporters;

TYPE
  TForm8 = Class(TForm)
    Splitter1: TSplitter;
    panel_data: TPanel;
    hex: TMPHexEditor;
    Splitter2: TSplitter;
    structs: TWrapGrid;
    panel_files: TPanel;
    list: TListBox;
    panel_extension: TPanel;
    Label1: TLabel;
    combo_extension: TComboBox;
    Bevel1: TBevel;
    panel_imexport: TPanel;
    btn_export: TButton;
    btn_import: TButton;
    opend: TOpenDialog;
    saved: TSaveDialog;
    PROCEDURE btn_importClick(Sender: TObject);
    PROCEDURE btn_exportClick(Sender: TObject);
    PROCEDURE panel_imexportResize(Sender: TObject);
    FUNCTION Save:Boolean;
    PROCEDURE FormClose(Sender: TObject; var Action: TCloseAction);
    PROCEDURE combo_extensionClick(Sender: TObject);
    PROCEDURE panel_extensionResize(Sender: TObject);
    FUNCTION GetValue(datatype:Byte; offset:LongWord):String;
    PROCEDURE WriteStructureInfos(structinfoid:Integer);
    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}
USES Unit1_main;
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 TForm8.GetValue(datatype:Byte; offset:LongWord):String;
  VAR
    data:Tdata;
  BEGIN
    CASE datatype OF
      1: Result:=IntToStr(Self.hex.data[offset]);
      2: Result:=IntToStr(Self.hex.data[offset]+Self.hex.data[offset+1]*256);
      3: Result:=IntToStr(Self.hex.data[offset]+Self.hex.data[offset+1]*256+Self.hex.data[offset+2]*256*256);
      4: Result:=IntToStr(Self.hex.data[offset]+Self.hex.data[offset+1]*256+Self.hex.data[offset+2]*256*256+Self.hex.data[offset+3]*256*256*256);
      5: Result:='0x'+IntToHex(Self.hex.data[offset],2);
      6: Result:='0x'+IntToHex(Self.hex.data[offset]+Self.hex.data[offset+1]*256,4);
      7: Result:='0x'+IntToHex(Self.hex.data[offset]+Self.hex.data[offset+1]*256+Self.hex.data[offset+2]*256*256,6);
      8: Result:='0x'+IntToHex(Self.hex.data[offset]+Self.hex.data[offset+1]*256+Self.hex.data[offset+2]*256*256+Self.hex.data[offset+3]*256*256*256,8);
      9: BEGIN
          SetLength(data,4);
          data[0]:=Self.hex.data[offset];
          data[1]:=Self.hex.data[offset+1];
          data[2]:=Self.hex.data[offset+2];
          data[3]:=Self.hex.data[offset+3];
          Result:=FloatToStr(Decode_Float(data));
        END;
      10: Result:=IntToBin(Self.hex.data[offset]);
    END;
  END;

PROCEDURE TForm8.WriteStructureInfos(structinfoid:Integer);
  VAR
    i:Byte;
  BEGIN
    IF structinfoid>=0 THEN BEGIN
      WITH structure_infos[structinfoid] DO BEGIN
        Self.structs.RowCount:=Length(entries)+1;
        FOR i:=1 TO Length(entries) DO BEGIN
          Self.structs.Cells[0,i]:=entries[i-1].name;
          Self.structs.Cells[1,i]:='0x'+IntToHex(entries[i-1].offset,6);
          Self.structs.Cells[2,i]:=GetDataType(entries[i-1].datatype);
          Self.structs.Cells[3,i]:=Self.GetValue(entries[i-1].datatype,entries[i-1].offset);
          Self.structs.Cells[4,i]:=entries[i-1].description;
        END;
      END;
    END;
  END;

PROCEDURE TForm8.Recreatelist;
  VAR
    i:LongWord;
  BEGIN
    combo_extension.Items.Clear;
    combo_extension.Items.Add('_All files_ ('+IntToStr(dat_header.Files)+')');
    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
      WITH dat_extensionsmap[i] DO BEGIN
        combo_extension.Items.Add(
          Extension[3]+Extension[2]+Extension[1]+Extension[0]+' ('+
          IntToStr(ExtCount)+')');
      END;
    END;
    combo_extension.ItemIndex:=0;
    combo_extensionClick(Self);
  END;

PROCEDURE TForm8.FormCreate(Sender: TObject);
  BEGIN
    Self.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;
    Self.panel_dataResize(Self);
  END;

FUNCTION TForm8.Save:Boolean;
  VAR
    mem:TMemoryStream;
    data:Tdata;
  BEGIN
    CASE MessageBox(Self.Handle,PChar('Save changes to file '+dat_files[fileid].FileName+'?'),PChar('Data changed...'),MB_YESNOCANCEL) OF
      IDYES: 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);
          Result:=True;
        END;
      IDNO: Result:=True;
      IDCANCEL: BEGIN
          Result:=False;
        END;
    END;
  END;

PROCEDURE TForm8.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  BEGIN
    IF hex.Modified THEN BEGIN
      IF NOT Save THEN CanClose:=False;
    END;
  END;

PROCEDURE TForm8.listClick(Sender: TObject);
  VAR
    mem:TMemoryStream;
    data:Tdata;
    i:LongWord;
  BEGIN
    IF hex.Modified THEN BEGIN
      IF NOT Save THEN BEGIN
        FOR i:=0 TO list.Count-1 DO BEGIN
          IF StrToInt(MidStr(list.Items.Strings[i],1,5))=fileid THEN BEGIN
            list.ItemIndex:=i;
            Exit;
          END;
        END;
      END;
    END;
    Self.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 Self.Width>=650 THEN BEGIN
    END ELSE Self.Width:=650;
    IF Self.Height>=450 THEN BEGIN
    END ELSE Self.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]-28;
  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: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;
      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;

PROCEDURE TForm8.panel_extensionResize(Sender: TObject);
  BEGIN
    combo_extension.Width:=panel_extension.Width-5;
  END;

PROCEDURE TForm8.combo_extensionClick(Sender: TObject);
  VAR
    Extension:String[4];
    i:LongWord;
  BEGIN
    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
    list.Items.Clear;
    IF Extension='_All' THEN BEGIN
      FOR i:=0 TO dat_header.Files-1 DO
        IF (dat_files[i].FileType AND $02)=0 THEN
          list.Items.Add(dat_files[i].FileName);
    END ELSE BEGIN
      FOR i:=0 TO dat_header.Files-1 DO
        IF dat_files[i].Extension=Extension THEN
          IF (dat_files[i].FileType AND $02)=0 THEN
            list.Items.Add(dat_files[i].FileName);
    END;
    IF list.Count>0 THEN BEGIN
      list.ItemIndex:=0;
      listClick(Self);
    END;
  END;

PROCEDURE TForm8.FormClose(Sender: TObject; var Action: TCloseAction);
  VAR
    i:Byte;
  BEGIN
    FOR i:=0 TO Form1.menu_windows.Count-1 DO BEGIN
      IF Form1.menu_windows.Items[i].Name='menu_window_'+Self.Name THEN BEGIN
        Form1.menu_windows.Items[i].Free;
        Break;
      END;
    END;
    Form1.menu_tools.Enabled:=True;
    Action:=caFree;
  END;

PROCEDURE TForm8.panel_imexportResize(Sender: TObject);
  BEGIN
    btn_import.Width:=panel_imexport.Width-8;
    btn_export.Width:=panel_imexport.Width-8;
  END;

PROCEDURE TForm8.btn_exportClick(Sender: TObject);
  BEGIN
    saved.Filter:='Files of matching extension (*.'+dat_files[fileid].Extension+')|*.'+dat_files[fileid].Extension+'|All files|*.*';
    saved.DefaultExt:=dat_files[fileid].Extension;
    IF saved.Execute THEN BEGIN
      ExportDatFile(fileid,saved.FileName);
    END;
  END;

PROCEDURE TForm8.btn_importClick(Sender: TObject);
  VAR
    data:Tdata;
    fs:TFileStream;
  BEGIN
    opend.Filter:='Files of matching extension (*.'+dat_files[fileid].Extension+')|*.'+dat_files[fileid].Extension+'|All files|*.*';
    IF opend.Execute THEN BEGIN
      fs:=TFileStream.Create(opend.FileName,fmOpenRead);
      IF fs.Size<>dat_files[fileid].size THEN BEGIN
        ShowMessage('Can''t import '+ExtractFilename(opend.FileName)+
                    ', file has to have same size as file in .dat.'+CrLf+
                    'Size of file in .dat: '+FormatFileSize(dat_files[fileid].size)+CrLf+
                    'Size of chosen file: '+FormatFileSize(fs.Size));
      END ELSE BEGIN
        SetLength(data,fs.Size);
        fs.Read(data[0],fs.Size);
        fs.Free;
        fs:=TFileStream.Create(dat_filename,fmOpenReadWrite);
        fs.Seek(dat_files[fileid].dataddr,soFromBeginning);
        fs.Write(data[0],Length(data));  
      END;
      fs.Free;
      listClick(Self);
    END;
  END;

END.
