UNIT Unit1_main;
INTERFACE
USES
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, StrUtils, Clipbrd, ExtCtrls, ComCtrls, Menus,
  Unit2_functions, Unit3_data, Unit5_preview, Unit7_txmpreplace, Unit8_binedit,
  Grids, MPHexEditor;

TYPE
  TForm1 = Class(TForm)
    panel_all: TPanel;
    panel_left: TPanel;
    Splitter1: TSplitter;
    panel_files: TPanel;
    btn_extractconvert: TButton;
    list_files: TListBox;
    list_extensions: TListBox;
    Splitter2: TSplitter;
    fopen: TOpenDialog;
    group_progress: TGroupBox;
    progress: TProgressBar;
    lbl_progress: TLabel;
    menu: TMainMenu;
    menu_main: TMenuItem;
    menu_exit: TMenuItem;
    menu_preview: TMenuItem;
    btn_extractcancel: TButton;
    menu_tools: TMenuItem;
    menu_txmpreplace: TMenuItem;
    menu_extract: TMenuItem;
    menu_extractfile: TMenuItem;
    menu_extractlist: TMenuItem;
    menu_extractall: TMenuItem;
    menu_loaddat: TMenuItem;
    menu_sep1: TMenuItem;
    menu_binedit: TMenuItem;
    statbar: TStatusBar;
    panel_file: TPanel;
    lbl_fileinfo: TLabel;
    hex: TMPHexEditor;
    lbl_zerobyte: TLabel;
    PROCEDURE menu_extractallClick(Sender: TObject);
    PROCEDURE menu_extractlistClick(Sender: TObject);
    PROCEDURE menu_extractfileClick(Sender: TObject);
    PROCEDURE menu_bineditClick(Sender: TObject);
    PROCEDURE menu_loaddatClick(Sender: TObject);
    PROCEDURE menu_txmpreplaceClick(Sender: TObject);
    PROCEDURE menu_exitClick(Sender: TObject);
    PROCEDURE btn_extractcancelClick(Sender: TObject);
    PROCEDURE menu_previewClick(Sender: TObject);
    PROCEDURE Splitter1Moved(Sender: TObject);
    PROCEDURE FormClose(Sender: TObject; var Action: TCloseAction);
    PROCEDURE btn_hexcopyClick(Sender: TObject);
    PROCEDURE list_extensionsClick(Sender: TObject);
    PROCEDURE FormResize(Sender: TObject);
    PROCEDURE btn_extractconvertClick(Sender: TObject);
    PROCEDURE FormCreate(Sender: TObject);
    PROCEDURE list_filesDblClick(Sender: TObject);
    PROCEDURE btn_loadClick(Sender: TObject);
  PRIVATE
  PUBLIC
  END;

VAR
  Form1: TForm1;

IMPLEMENTATION
{$R *.dfm}

PROCEDURE DoAfterLoadOfADat;
  VAR
    i:LongWord;
    txt:Text;
    temp4:LongWord;
    temp2:Word;
    temp1:Byte;
  BEGIN
    IF NOT DirectoryExists(GetExtractPath) THEN
      CreateDir(GetExtractPath);
    AssignFile(txt,GetExtractPath+'\___TXMP-FILES___.TXT');
    ReWrite(txt);
    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
      IF (dat_extensionsmap[i].Extension[3]='T') AND
          (dat_extensionsmap[i].Extension[2]='X') AND
          (dat_extensionsmap[i].Extension[1]='M') AND
          (dat_extensionsmap[i].Extension[0]='P') THEN BEGIN
        WriteLn(txt, FormatNumber(dat_extensionsmap[i].ExtCount,4,'0')+' TXMP-Files');
        Break;
      END;
    END;
    WriteLn(txt,'FileName'+#9+'MipMap'+#9+'Depth'+#9+'ImgX'+#9+'ImgY'+#9+'StoreT');
    FOR i:=0 TO dat_header.Files-1 DO BEGIN
      IF dat_files[i].Extension='TXMP' THEN BEGIN
        Write(txt,dat_files[i].FileName+#9);
        LoadDatFilePart(i,$88,1,@temp1);
        Write(txt,IntToHex(temp1,2)+#9);
        LoadDatFilePart(i,$89,1,@temp1);
        Write(txt,IntToHex(temp1,2)+#9);
        LoadDatFilePart(i,$8C,2,@temp2);
        Write(txt,IntToHex(temp2,4)+#9);
        LoadDatFilePart(i,$8E,2,@temp2);
        Write(txt,IntToHex(temp2,4)+#9);
        LoadDatFilePart(i,$90,1,@temp1);
        Write(txt,IntToHex(temp1,2)+#9);
        WriteLn(txt,'');
      END;
    END;
    CloseFile(txt);

    IF NOT DirectoryExists(GetExtractPath) THEN
      CreateDir(GetExtractPath);
    AssignFile(txt,GetExtractPath+'\___TXAN-FILES___.TXT');
    ReWrite(txt);
    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
      IF (dat_extensionsmap[i].Extension[3]='T') AND
          (dat_extensionsmap[i].Extension[2]='X') AND
          (dat_extensionsmap[i].Extension[1]='A') AND
          (dat_extensionsmap[i].Extension[0]='N') THEN BEGIN
        WriteLn(txt, FormatNumber(dat_extensionsmap[i].ExtCount,4,'0')+' TXAN-Files');
        Break;
      END;
    END;
    WriteLn(txt,'FileName'+#9+'Loopspeed'+#9+'Unknown'+#9+'Links');
    FOR i:=0 TO dat_header.Files-1 DO BEGIN
      IF dat_files[i].Extension='TXAN' THEN BEGIN
        Write(txt,dat_files[i].FileName+#9);
        LoadDatFilePart(i,$14,2,@temp2);
        Write(txt,IntToHex(temp2,4)+#9);
        LoadDatFilePart(i,$16,2,@temp2);
        Write(txt,IntToHex(temp2,4)+#9);
        LoadDatFilePart(i,$1C,4,@temp4);
        Write(txt,IntToHex(temp4,8)+#9);
        WriteLn(txt,'');
      END;
    END;
    CloseFile(txt);
  END;

PROCEDURE LoadDat;
  VAR i:LongWord;
  BEGIN
    Form1.fopen.InitialDir:=AppSettings.DatPath;
    IF Form1.fopen.Execute THEN BEGIN
      Form1.Caption:='Oni Un/Packer '+version+' ('+ExtractFileName(Form1.fopen.FileName)+')';
      AppSettings.DatPath:=ExtractFilepath(Form1.fopen.FileName);
      Form1.list_files.Items.Clear;
      Form1.list_extensions.Items.Clear;
      IF LoadDatInfos(Form1.fopen.FileName) THEN BEGIN
        Form1.list_extensions.Items.Add('_All files: '+FormatNumber(dat_header.Files,4,' '));
        FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
          WITH dat_extensionsmap[i] DO BEGIN
            Form1.list_extensions.Items.Add(
                Extension[3]+Extension[2]+Extension[1]+Extension[0]+': '+
                FormatNumber(ExtCount,4,' '));{+' (Ident: 0x'+
                IntToHex(Ident[7],2)+IntToHex(Ident[6],2)+IntToHex(Ident[5],2)+IntToHex(Ident[4],2)+IntToHex(Ident[3],2)+IntToHex(Ident[2],2)+IntToHex(Ident[1],2)+IntToHex(Ident[0],2)+')');}
          END;
        END;
        Form1.list_extensions.ItemIndex:=0;
        Form1.list_extensionsClick(Form1);
        Form1.list_files.ItemIndex:=0;
        Form1.list_filesDblClick(Form1);
        Form1.statbar.Panels.Items[0].Text:='Current .dat: '+dat_FileName;
        Form1.statbar.Panels.Items[1].Text:='Files: '+IntToStr(dat_header.Files);
        Form1.statbar.Panels.Items[2].Text:='Extensions: '+IntToStr(dat_header.Extensions);
        Form1.menu_tools.Enabled:=True;
        Form1.menu_extract.Enabled:=True;
        Form1.btn_extractconvert.Enabled:=True;

        Form7.RecreateTXMPlist;
        Form8.Recreatelist;

        DoAfterLoadOfADat;

      END ELSE BEGIN
        ShowMessage('Error while loading the file:'+CrLf+Form1.fopen.FileName+CrLf+'Perhaps not an Oni-.dat-file?');
      END;
    END;
  END;

PROCEDURE TForm1.btn_loadClick(Sender: TObject);
  BEGIN
    LoadDat;
  END;

PROCEDURE TForm1.list_filesDblClick(Sender: TObject);
  VAR
    id:LongWord;
    temp:Tdata;
    mem:TMemoryStream;
  BEGIN
    id:=StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5));
    IF (dat_files[id].FileType AND $02)=0 THEN BEGIN
      lbl_fileinfo.Caption:=
            'Filename: '+dat_files[id].FileName+CrLf+
            'Size: '+FormatFileSize(dat_files[id].Size)+' ('+IntToStr(dat_files[id].Size)+' Bytes)'+CrLf+
            'Address in .dat: 0x'+IntTohex(dat_files[id].DatAddr,8);
      temp:=LoadDatFile(id);
      mem:=TMemoryStream.Create;
      mem.Write(temp[0],Length(temp));
      hex.LoadFromStream(mem);
      mem.Free;
      Form5.ShowPreview(id);
      lbl_zerobyte.Visible:=False;
      hex.Visible:=True;
    END ELSE BEGIN
      lbl_fileinfo.Caption:=
            'Filename: '+dat_files[id].FileName;
      lbl_zerobyte.Visible:=True;
      hex.Visible:=False;
    END;
  END;

PROCEDURE TForm1.FormCreate(Sender: TObject);
  BEGIN
    Form1.Caption:='Oni Un/Packer '+version;
    Form1.FormResize(Form1);

    panel_all.Align:=alClient;

    IF FileExists(ExtractFilepath(Application.EXEname)+'\oniunpacker.ini') THEN BEGIN
      AssignFile(AppSettingsFile,ExtractFilepath(Application.EXEname)+'\oniunpacker.ini');
      Reset(AppSettingsFile);
      Read(AppSettingsFile,AppSettings);
      CloseFile(AppSettingsFile);
    END ELSE BEGIN
      AppSettings.DatPath:='D:\Spiele\Oni\GameDataFolder';
      AppSettings.ExtractPath:='C:\Dokumente und Einstellungen\Administrator\Desktop';
    END;
  END;

PROCEDURE TForm1.btn_extractconvertClick(Sender: TObject);
  BEGIN
    Form1.menu_extractfileClick(Form1);
  END;

PROCEDURE TForm1.FormResize(Sender: TObject);
  CONST
    MinWidth:Integer=750;
    MinHeight:Integer=500;
  BEGIN
    IF NOT group_progress.Visible THEN BEGIN
      IF Form1.Width<MinWidth THEN Form1.Width:=MinWidth;
      IF Form1.Height<MinHeight THEN Form1.Height:=MinHeight;
      Form1.statbar.Panels.Items[0].Width:=Form1.Width-200;
    END ELSE BEGIN
      Form1.Width:=400;
      Form1.Height:=120;
    END;
  END;

PROCEDURE TForm1.list_extensionsClick(Sender: TObject);
  VAR
    Extension:String[4];
    i:LongWord;
  BEGIN
    Extension:=MidStr(list_extensions.Items.Strings[list_extensions.ItemIndex],1,4);
    list_files.Items.Clear;
    IF Extension='_All' THEN BEGIN
      FOR i:=0 TO dat_header.Files-1 DO
        list_files.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
          list_files.Items.Add(dat_files[i].FileName);
    END;
  END;

PROCEDURE TForm1.btn_hexcopyClick(Sender: TObject);
  VAR
    temp:Tdata;
  BEGIN
    temp:=LoadDatFile(StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5)));
    Clipboard.SetTextBuf(PChar(CreateHexString(temp,True)));
  END;

PROCEDURE TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
  BEGIN
    AssignFile(AppSettingsFile,ExtractFilepath(Application.EXEname)+'\oniunpacker.ini');
    IF FileExists(ExtractFilepath(Application.EXEname)+'\oniunpacker.ini') THEN
      Reset(AppSettingsFile)
    ELSE
      Rewrite(AppSettingsFile);
    Write(AppSettingsFile,AppSettings);
    CloseFile(AppSettingsFile);
  END;

PROCEDURE TForm1.Splitter1Moved(Sender: TObject);
  BEGIN
    Form1.list_files.Height:=Form1.Splitter1.Top-23;
    Form1.btn_extractconvert.Top:=Form1.Splitter1.Top-21;
  END;

PROCEDURE TForm1.menu_previewClick(Sender: TObject);
  BEGIN
    Form5.Visible:=NOT Form5.Visible;
  END;

PROCEDURE TForm1.btn_extractcancelClick(Sender: TObject);
  BEGIN
    btn_extractcancel.Caption:='Cancel_';
  END;

PROCEDURE TForm1.menu_exitClick(Sender: TObject);
  BEGIN
    Form1.Close;
  END;

PROCEDURE TForm1.menu_txmpreplaceClick(Sender: TObject);
  BEGIN
    Form7.Visible:=NOT Form7.Visible;
  END;

PROCEDURE TForm1.menu_loaddatClick(Sender: TObject);
  BEGIN
    LoadDat;
  END;

PROCEDURE TForm1.menu_bineditClick(Sender: TObject);
  BEGIN
    Form8.Visible:=NOT Form8.Visible;
  END;

PROCEDURE TForm1.menu_extractfileClick(Sender: TObject);
  VAR
    result:Integer;
    id:LongWord;
  BEGIN
    id:=StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5));
    result:=ExportFile(id,True);
    CASE result OF
      0{export_noerror}: BEGIN END;
      1{export_nohandler}: ShowMessage('No export-handler for files with extension '+dat_files[id].Extension+'.');
      2{export_handlererror}: ShowMessage('Error while running data-handler for '+CrLf+dat_files[id].FileName);
      3{export_error}: ShowMessage('Error while exporting file '+CrLf+dat_files[id].FileName);
    ELSE
      ShowMessage('Couldn''t export file '+FormatNumber(id,5,'0')+CrLf+'(Unknown error)');
    END;
    Form1.list_files.SetFocus;
  END;

PROCEDURE TForm1.menu_extractlistClick(Sender: TObject);
  VAR
    i:LongWord;
    errors:LongWord;
    oldwidth,oldheight:Integer;
    oldstate:TWindowState;
  BEGIN
    panel_all.Visible:=False;
    group_progress.Visible:=True;
    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=False;
    oldwidth:=Form1.Width;
    oldheight:=Form1.Height;
    oldstate:=Form1.WindowState;
    Form1.WindowState:=wsNormal;
    Form1.Width:=400;
    Form1.Height:=120;
    group_progress.Left:=0;
    group_progress.Top:=0;
    group_progress.Width:=Form1.Width-8;
    progress.Width:=group_progress.Width-80;
    progress.Max:=list_files.Items.Count;
    btn_extractcancel.Left:=group_progress.Width-65;
    btn_extractcancel.Caption:='Cancel';
    btn_extractcancel.SetFocus;

    errors:=0;
    FOR i:=0 TO progress.Max-1 DO BEGIN
      IF ExportFile(StrToInt(MidStr(list_files.Items.Strings[i],1,5)),True)>0 THEN Inc(errors);
      IF (i MOD 25)=0 THEN BEGIN
        lbl_progress.Caption:=IntToStr(i)+'/'+IntToStr(progress.Max);
        progress.Position:=i;
        Application.ProcessMessages;
        IF btn_extractcancel.Caption='Cancel_' THEN BEGIN
          btn_extractcancel.Caption:='Cancel';
          Break;
        END;
      END;
    END;
    IF errors>0 THEN
      ShowMessage(IntToStr(errors)+' errors encountered.');

    group_progress.Visible:=False;
    Form1.Width:=oldwidth;
    Form1.Height:=oldheight;
    Form1.WindowState:=oldstate;
    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=True;
    panel_all.Visible:=True;
  END;

PROCEDURE TForm1.menu_extractallClick(Sender: TObject);
  VAR
    i:LongWord;
    errors:LongWord;
    oldwidth,oldheight:Integer;
    oldstate:TWindowState;
  BEGIN
    panel_all.Visible:=False;
    group_progress.Visible:=True;
    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=False;
    oldwidth:=Form1.Width;
    oldheight:=Form1.Height;
    oldstate:=Form1.WindowState;
    Form1.WindowState:=wsNormal;
    Form1.Width:=400;
    Form1.Height:=120;
    group_progress.Left:=0;
    group_progress.Top:=0;
    group_progress.Width:=Form1.Width-8;
    progress.Width:=group_progress.Width-80;
    progress.Max:=dat_header.files;
    btn_extractcancel.Left:=group_progress.Width-65;
    btn_extractcancel.Caption:='Cancel';
    btn_extractcancel.SetFocus;

    errors:=0;
    FOR i:=0 TO High(dat_files) DO BEGIN
      IF ExportFile(i,True)>0 THEN Inc(errors);
      IF (i MOD 25)=0 THEN BEGIN
        lbl_progress.Caption:=IntToStr(i)+'/'+IntToStr(dat_header.Files);
        progress.Position:=i;
        Application.ProcessMessages;
        IF btn_extractcancel.Caption='Cancel_' THEN BEGIN
          btn_extractcancel.Caption:='Cancel';
          Break;
        END;
      END;
    END;
    IF errors>0 THEN
      ShowMessage(IntToStr(errors)+' errors encountered.');

    group_progress.Visible:=False;
    Form1.Width:=oldwidth;
    Form1.Height:=oldheight;
    Form1.WindowState:=oldstate;
    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=True;
    panel_all.Visible:=True;
  END;

END.
