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;
    lbl_filter: TLabel;
    combo_extension: TComboBox;
    Bevel1: TBevel;
    panel_imexport: TPanel;
    btn_export: TButton;
    btn_import: TButton;
    opend: TOpenDialog;
    saved: TSaveDialog;
{    PROCEDURE structsGetEditText(Sender: TObject; ACol, ARow: Integer; var Value: string);
    PROCEDURE structsSetEditText(Sender: TObject; ACol, ARow: Integer; const Value: string);
    PROCEDURE structsKeyPress(Sender: TObject; var Key: Char);
}    PROCEDURE FormActivate(Sender: TObject);
    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:Word; 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:Word; offset:LongWord):String;
  VAR
    data:Tdata;
    i:Word;
  BEGIN
    CASE datatype OF
      1: Result:=IntToStr(hex.data[offset]);
      2: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256);
      3: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256);
      4: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256+hex.data[offset+3]*256*256*256);
      5: Result:='0x'+IntToHex(hex.data[offset],2);
      6: Result:='0x'+IntToHex(hex.data[offset]+hex.data[offset+1]*256,4);
      7: Result:='0x'+IntToHex(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256,6);
      8: Result:='0x'+IntToHex(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256+hex.data[offset+3]*256*256*256,8);
      9: BEGIN
          SetLength(data,4);
          data[0]:=hex.data[offset];
          data[1]:=hex.data[offset+1];
          data[2]:=hex.data[offset+2];
          data[3]:=hex.data[offset+3];
          Result:=FloatToStr(Decode_Float(data));
        END;
      10: Result:=IntToBin(hex.data[offset]);
      10000..65535: BEGIN
          Result:='';
          FOR i:=1 TO datatype-10000 DO BEGIN
            IF hex.Data[offset+i-1]>=32 THEN
              Result:=Result+Chr(hex.Data[offset+i-1])
            ELSE
              Result:=Result+'.';
          END;
        END;
    END;
  END;

PROCEDURE TForm8.WriteStructureInfos(structinfoid:Integer);
  VAR
    i:Byte;
  BEGIN
    IF structinfoid>=0 THEN BEGIN
      structs.Enabled:=True;
      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);
          IF entries[i-1].datatype>10000 THEN
            Self.structs.Cells[3,i]:='*String*#HINT:'+GetValue(entries[i-1].datatype,entries[i-1].offset)+'#'
          ELSE
            Self.structs.Cells[3,i]:=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;
    exts:TStringList;
  BEGIN
    combo_extension.Items.Clear;
    combo_extension.Items.Add('_All files_ ('{+IntToStr(dat_header.Files)}+')');
    exts:=GetExtensionsList;
    FOR i:=0 TO High(exts) DO
      combo_extension.Items.Add(exts[i]);
    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;
          UpdateDatFile(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);
    IF Length(data)>0 THEN BEGIN
      mem:=TMemoryStream.Create;
      mem.Write(data[0],Length(data));
      mem.Seek(0,soFromBeginning);
      hex.LoadFromStream(mem);
      mem.Free;
      WriteStructureInfos(GetStructureInfoId(dat_files[fileid].Extension));
    END;
  END;

PROCEDURE TForm8.ClearStructViewer;
  VAR
    x:Word;
  BEGIN
    structs.RowCount:=2;
    FOR x:=0 TO structs.ColCount-1 DO structs.Cells[x,1]:='';
    structs.Enabled:=False;
  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;
{      IF structs.Cells[structs.Col,0]='Value' THEN
        IF structure_infos[GetStructureInfoId(dat_files[fileid].Extension)].entries[structs.Row-1].datatype<=10 THEN
          structs.Options:=structs.Options+[goEditing]
      ELSE
        structs.Options:=structs.Options-[goEditing];
}    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];
    files:TStringList;
    i:LongWord;
  BEGIN
    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
    list.Items.Clear;
    IF Extension='_All' THEN
      files:=GetFilesList('','',True)
    ELSE
      files:=GetFilesList(extension,'',True);
    IF Length(files)>0 THEN
      FOR i:=0 TO High(files) DO
        list.Items.Add(files[i]);
  END;

PROCEDURE TForm8.FormClose(Sender: TObject; var Action: TCloseAction);
  BEGIN
    Action:=caFree;
    Form1.close_window(Self.Name);
  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;

PROCEDURE TForm8.FormActivate(Sender: TObject);
  BEGIN
    Form1.SetActiveWindow(Self.Name);
  END;
{
PROCEDURE TForm8.structsKeyPress(Sender: TObject; VAR Key: Char);
  VAR
    dt:Byte;
  BEGIN
    IF structs.EditorMode THEN BEGIN
      dt:=structure_infos[GetStructureInfoId(dat_files[fileid].Extension)].entries[structs.Row-1].datatype;
      CASE dt OF
        1..4: BEGIN
                IF NOT (Key IN [#8,#13,#27,'0'..'9']) THEN Key:=#0;
              END;
        5..8: BEGIN
                IF NOT (Key IN [#8,#13,#27,'0'..'9','A'..'F','a'..'f']) THEN Key:=#0;
                IF Key IN ['a'..'f'] THEN Key:=UpCase(Key);
                IF NOT (Key IN [#8,#13,#27]) AND ( Length(structs.Cells[structs.Col,structs.Row])>=2*(dt-4) ) THEN Key:=#0;
              END;
        9:    BEGIN
                IF (Key IN ['.']) AND (Pos('.',structs.Cells[structs.Col,structs.Row])>0) THEN Key:=#0;
                IF NOT (Key IN [#8,#13,#27,'0'..'9','.','-']) THEN Key:=#0;
              END;
        10:   BEGIN
                IF NOT (Key IN [#8,#13,#27,'0'..'1']) THEN Key:=#0;
                IF NOT (Key IN [#8,#13,#27]) AND ( Length(structs.Cells[structs.Col,structs.Row])>=8 ) THEN Key:=#0;
              END;
      END;
    END;
  END;

PROCEDURE TForm8.structsSetEditText(Sender: TObject; ACol, ARow: Integer; CONST Value: string);
  BEGIN
    IF NOT TWrapGrid(Sender).EditorMode THEN
      ShowMessage('['+IntToStr(ACol)+'|'+IntToStr(ARow)+']='+Value);
  END;

PROCEDURE TForm8.structsGetEditText(Sender: TObject; ACol, ARow: Integer; var Value: string);
  BEGIN
    IF structs.EditorMode THEN
      ShowMessage('EditorMode - '+Value)
    ELSE
      ShowMessage('NOT EditorMode - '+Value);
  END;
}
END.
