unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, StrUtils, Clipbrd, ExtCtrls, ComCtrls, Menus, Grids,
  MPHexEditor, ToolWin, ImgList, Tabs,
  MDITab, TB2Item, TB2Dock, TB2Toolbar, TB2MDI,
  Data, Functions, DataStructures, OniDataClass, Exporters,
  Helper_LevelDB, Settings, Template,
  BinEdit, Extractor, Preview, RawEdit, TxmpReplace;

type
  TForm_Main = class(TForm)
    saved:      TSaveDialog;
    opend:      TOpenDialog;
    statbar:    TStatusBar;
    MenuImages: TImageList;
    DockTop:    TTBDock;
    MainMenu:   TTBToolbar;
    menu_main:  TTBSubmenuItem;
    menu_loadfile: TTBItem;
    menu_sep1:  TTBSeparatorItem;
    menu_settings: TTBItem;
    menu_sep4:  TTBSeparatorItem;
    menu_exit:  TTBItem;
    menu_convert: TTBSubmenuItem;
    menu_createdb: TTBItem;
    menu_createlvl: TTBItem;
    menu_tools: TTBSubmenuItem;
    menu_preview: TTBItem;
    menu_binedit: TTBItem;
    menu_rawedit: TTBItem;
    menu_txmpreplace: TTBItem;
    menu_extractor: TTBItem;
    menu_filecompare: TTBItem;
    menu_levelstructedit: TTBItem;
    menu_windows: TTBSubmenuItem;
    menu_windows_cascade: TTBItem;
    menu_windows_tile: TTBItem;
    menu_windows_closeall: TTBItem;
    menu_sep3:  TTBSeparatorItem;
    menu_windows_next: TTBItem;
    menu_windows_previous: TTBItem;
    menu_sep2:  TTBSeparatorItem;
    menu_About: TTBItem;
    Toolbar:    TTBToolbar;
    tbOpen:     TTBItem;
    DockLeft:   TTBDock;
    DockRight:  TTBDock;
    DockBottom: TTBDock;
    MDIToolbar: TTBToolbar;
    TBControlItem1: TTBControlItem;
    MDITab:     TMDITab;
    menu_view:  TTBSubmenuItem;
    menu_view_mdibar: TTBItem;
    menu_view_statusbar: TTBItem;
    menu_view_toolbar: TTBItem;
    tb_separator1: TTBSeparatorItem;
    tb_preview: TTBItem;
    tb_structure: TTBItem;
    tb_compare: TTBItem;
    tb_extractor: TTBItem;
    tb_txmpreplacer: TTBItem;
    tb_rawedit: TTBItem;
    tb_datedit: TTBItem;
    menu_windows_tilevert: TTBItem;
    tb_meta: TTBItem;
    menu_meta: TTBItem;
    TBSeparatorItem1: TTBSeparatorItem;
    tb_db2dat: TTBItem;
    tb_dat2db: TTBItem;
    menu_loaddb: TTBItem;
    tb_opendb: TTBItem;
    Images_Close: TImageList;
    procedure LoadFile(typedb: Boolean);
    function TryCloseAll: Boolean;
    procedure menu_AboutClick(Sender: TObject);
    procedure menu_settingsClick(Sender: TObject);
    procedure menu_filecompareClick(Sender: TObject);
    procedure menu_raweditClick(Sender: TObject);
    procedure menu_createlvlClick(Sender: TObject);
    procedure menu_extractorClick(Sender: TObject);
    procedure menu_createdbClick(Sender: TObject);
    procedure menu_windows_previousClick(Sender: TObject);
    procedure menu_windows_nextClick(Sender: TObject);
    procedure menu_windows_tileClick(Sender: TObject);
    function open_child(window_context: String; fileid: Integer): TForm_ToolTemplate;
    procedure menu_windows_closeallClick(Sender: TObject);
    procedure menu_windows_cascadeClick(Sender: TObject);
    procedure menu_bineditClick(Sender: TObject);
    procedure menu_loadfileClick(Sender: TObject);
    procedure menu_txmpreplaceClick(Sender: TObject);
    procedure menu_exitClick(Sender: TObject);
    procedure menu_previewClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormResize(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure UpdateStatBar;
    procedure menu_view_mdibarClick(Sender: TObject);
    procedure menu_view_statusbarClick(Sender: TObject);
    procedure menu_view_toolbarClick(Sender: TObject);
    procedure MDITabDrawTab(Control: TCustomTabControl; TabIndex: Integer;
      const Rect: TRect; Active: Boolean);
    procedure ActivateTools(active: Boolean);
    procedure MDITabMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure menu_windows_tilevertClick(Sender: TObject);
    procedure menu_metaClick(Sender: TObject);
    procedure ToolbarDockChanged(Sender: TObject);
    procedure menu_loaddbClick(Sender: TObject);
    procedure MDITabMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
  private
  public
  end;

var
  Form_Main: TForm_Main;

implementation

{$R *.dfm}



procedure TForm_Main.FormCreate(Sender: TObject);
begin
  Self.Caption := 'Oni Un/Packer ' + version;
  Self.FormResize(Self);

  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';
    AppSettings.FilenumbersAsHex := False;
    AppSettings.CharSet     := DEFAULT_CHARSET;
    AppSettings.HideUnusedData := False;
  end;

  if MidStr(ParamStr(1), 1, 3) = 'opf' then
  begin
    ShowMessage('Load OPF-File: ' + ParamStr(2));
  end
  else if MidStr(ParamStr(1), 1, 4) = 'oldb' then
  begin
    if not CreateDataConnection(ParamStr(2), ODB_ADB) then
      ShowMessage('Error while loading the file:' + CrLf + ParamStr(
        2) + CrLf + 'Perhaps not an OniUnPacker-LevelDatabase-file?');
  end
  else if MidStr(ParamStr(1), 1, 3) = 'dat' then
  begin
    if not CreateDataConnection(ParamStr(2), ODB_Dat) then
      ShowMessage('Error while loading the file:' + CrLf + ParamStr(
        2) + CrLf + 'Perhaps not an Oni-.dat-file?');
  end;
  UpdateStatBar;
end;




procedure TForm_Main.FormResize(Sender: TObject);
const
  MinWidth: Integer  = 750;
  MinHeight: Integer = 500;
begin
  if Self.Width < MinWidth then
    Self.Width := MinWidth;
  if Self.Height < MinHeight then
    Self.Height := MinHeight;
  statbar.Panels.Items[0].Width := Self.Width - 200;
  MDITab.Width := Self.Width - 20;
end;




procedure TForm_Main.MDITabDrawTab(Control: TCustomTabControl;
  TabIndex: Integer; const Rect: TRect; Active: Boolean);
var
  x, y: Integer;
  iconindex: Integer;
  caption: String;
begin
  iconindex := TMDITab(Control).Glyphs[TabIndex];
  caption := TMDITab(Control).Captions[TabIndex];
  if active then
  begin
    Control.Canvas.Font.Style := Control.Canvas.Font.Style + [fsItalic];
    y := Rect.Top + 1;
  end else
    y := Rect.Top;
  if iconindex >= 0 then
  begin
    TMDITab(Control).Images.Draw(Control.Canvas, Rect.Left + 4, y, iconindex);
    x := Rect.Left + 26;
  end else
    x := Rect.Left + 4;
  Control.Canvas.TextOut(x, y + 2, caption);
  if active then
    Images_Close.Draw(Control.Canvas, Rect.Right - 18, y, 0)
  else
    Images_Close.Draw(Control.Canvas, Rect.Right - 18, y, 1);
end;


procedure TForm_Main.MDITabMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  pt: TPoint;
  tabIndex: Integer;
  hint: String;
begin
  pt.X := X;
  pt.Y := Y;
  tabIndex := MDITab.GetTabAtPos(pt);

  if tabIndex >= 0 then
  begin
    if MDITab.MDIChildren[tabIndex] is TForm_ToolTemplate then
      hint := 'Window: ' + MDITab.MDIChildren[tabIndex].Caption + #13+#10 +
            'Selected File: ' +
            TForm_ToolTemplate(MDITab.MDIChildren[tabIndex]).SelectedFile.FileName
    else
      hint := 'Window: ' + MDITab.MDIChildren[tabIndex].Caption;
    if hint <> MDITab.Hint then
    begin
      MDITab.Hint := hint;
      MDITab.ShowHint := True;
    end;
  end
  else
  begin
    MDITab.ShowHint := False;
    MDITab.Hint := '';
  end;
end;

procedure TForm_Main.MDITabMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  pt: TPoint;
  tabIndex: Integer;
  tabRect: TRect;
  tabX, tabY, tabWidth: Integer;
begin
  pt.X := X;
  pt.Y := Y;
  tabIndex := MDITab.GetTabAtPos(pt);
  if (Button = mbRight) and (tabIndex >= 0) then
    MDITab.MDIChildren[tabIndex].Close;

  if (Button = mbLeft) and (tabIndex >= 0) then
  begin
    tabrect := MDITab.TabRect(tabIndex);
    tabX := X - tabrect.Left;
    tabY := Y - tabrect.Top;
    tabwidth := tabrect.Right - tabrect.Left;
    if (tabY >= 4) and (tabY <= 17) then
      if (tabX >= tabwidth - 19) and (tabX <= tabwidth - 7) then
        MDITab.MDIChildren[tabIndex].Close;
  end;
end;




procedure TForm_Main.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);
  Action := caFree;
end;



procedure TForm_Main.ActivateTools(active: Boolean);
begin
  menu_tools.Enabled := active;
  tb_preview.Enabled := active;
  tb_datedit.Enabled := active;
  tb_rawedit.Enabled := active;
  tb_txmpreplacer.Enabled := active;
  tb_extractor.Enabled := active;
//  tb_compare.Enabled := active;
//  tb_structure.Enabled := active;
end;

procedure TForm_Main.UpdateStatBar;
begin
  if Assigned(OniDataConnection) then
  begin
    Self.Caption      := 'Oni Un/Packer ' + version + ' (' + ExtractFileName(
      OniDataConnection.FileName) + ')';
    ActivateTools(True);
    statbar.Panels.Items[1].Text := 'Files: ' + IntToStr(OniDataConnection.GetFilesCount);
    statbar.Panels.Items[2].Text :=
      'Extensions: ' + IntToStr(Length(OniDataConnection.GetExtensionsList));
    case OniDataConnection.Backend of
      ODB_Dat:
        begin
          statbar.Panels.Items[0].Text := '.dat loaded: ' + OniDataConnection.FileName;
        end;
      ODB_ADB:
        begin
          statbar.Panels.Items[0].Text := 'OLDB loaded: ' + OniDataConnection.FileName;
        end;
    else
      Self.Caption      := 'Oni Un/Packer ' + version;
      statbar.Panels.Items[0].Text := 'Nothing loaded';
      statbar.Panels.Items[1].Text := 'Files: -';
      statbar.Panels.Items[2].Text := 'Extensions: -';
      ActivateTools(False);
    end;
  end
  else
  begin
    Self.Caption      := 'Oni Un/Packer ' + version;
    statbar.Panels.Items[0].Text := 'Nothing loaded';
    statbar.Panels.Items[1].Text := 'Files: -';
    statbar.Panels.Items[2].Text := 'Extensions: -';
    ActivateTools(False);
  end;
end;




procedure TForm_Main.ToolbarDockChanged(Sender: TObject);
var
  toolbar: TTBToolbar;
  position: TTBDockPosition;
  mode: TTBItemDisplayMode;
  i: Integer;
  isEnabled: Boolean;
begin
  toolbar := TTBToolbar(Sender);
  if toolbar.Floating then
    mode := nbdmImageAndText
  else begin
    position := toolbar.CurrentDock.Position;
    if position in [dpLeft, dpRight] then
      mode := nbdmDefault
    else
      mode := nbdmImageAndText;
  end;
  for i := 0 to toolbar.Items.Count - 1 do
    toolbar.Items.Items[i].DisplayMode := mode;
end;

function TForm_Main.TryCloseAll: Boolean;
begin
  menu_windows_closeallClick(Self);
  Application.ProcessMessages;
  if MDITab.MDIChildCount = 0 then
    Result := True
  else
    Result := False;
end;



procedure TForm_Main.LoadFile(typedb: Boolean);
var
  ext: String;
begin
  if TryCloseAll then
  begin
    CloseDataConnection;
    opend.InitialDir := AppSettings.DatPath;
    opend.Filter     := 'Compatible level files|*.dat;*.oldb|Oni level (*.dat)|*.dat|OUP level database (*.oldb)|*.oldb|Any (*.*)|*';
    if typedb then
      opend.FilterIndex := 3
    else
      opend.FilterIndex := 2;
    if opend.Execute then
    begin
      ext := ExtractFileExt(opend.FileName);
      if ext = '.dat' then
      begin
        if not CreateDataConnection(opend.FileName, ODB_Dat) then
          ShowMessage('Error while loading the file:' + CrLf + opend.FileName +
            CrLf + 'Perhaps not an Oni-.dat-file?');
      end else if ext = '.oldb' then
      begin
        if not CreateDataConnection(opend.FileName, ODB_ADB) then
          ShowMessage('Error while loading the file:' + CrLf + opend.FileName +
            CrLf + 'Perhaps not an OniUnPacker-LevelDatabase-file?');
      end else
        ShowMessage('Incompatible file');
      AppSettings.DatPath := ExtractFilepath(opend.FileName);
    end;
  end;
  UpdateStatBar;
end;


 {#################################}
 {##### Main-Menu-Handlers    #####}
 {#################################}
procedure TForm_Main.menu_loaddbClick(Sender: TObject);
begin
  LoadFile(True);
end;

procedure TForm_Main.menu_loadfileClick(Sender: TObject);
begin
  LoadFile(False);
end;




procedure TForm_Main.menu_settingsClick(Sender: TObject);
begin
  Form_Settings.Visible := True;
  Self.Enabled   := False;
end;




procedure TForm_Main.menu_exitClick(Sender: TObject);
begin
  Self.Close;
end;

 {####################################}
 {##### Converters-Menu-Handlers #####}
 {####################################}
procedure TForm_Main.menu_createdbClick(Sender: TObject);
begin
  if Assigned(OniDataConnection) then
    if MessageBox(Self.Handle, PChar('You have currently opened a level-file. ' +
          'Do you want to close it to continue?'), PChar('Close file?'),
          MB_YESNO + MB_ICONQUESTION) = ID_NO then
      Exit
    else begin
      if TryCloseAll then
      begin
        CloseDataConnection;
        UpdateStatBar;
      end else
        Exit;
    end;
  opend.Filter     := 'Oni-Dat-Files|*.dat';
  saved.Filter     := 'OUP-Level-DB (*.oldb)|*.oldb';
  saved.DefaultExt := 'oldb';
  if opend.Execute then
    if saved.Execute then
      Form_LevelDB.CreateDatabase(opend.FileName, saved.FileName);
end;




procedure TForm_Main.menu_createlvlClick(Sender: TObject);
begin
  if Assigned(OniDataConnection) then
    if MessageBox(Self.Handle, PChar('You have currently opened a level-file. ' +
          'Do you want to close it to continue?'), PChar('Close file?'),
          MB_YESNO + MB_ICONQUESTION) = ID_NO then
      Exit
    else begin
      if TryCloseAll then
      begin
        CloseDataConnection;
        UpdateStatBar;
      end else
        Exit;
    end;
  opend.Filter     := 'OUP-Level-DB (*.oldb)|*.oldb';
  saved.Filter     := 'Oni-Dat-Files|*.dat';
  saved.DefaultExt := 'dat';
  if opend.Execute then
    if saved.Execute then
      Form_LevelDB.CreateLevel(opend.FileName, saved.FileName);
end;

 {#################################}
 {##### Tools-Menu-Handlers   #####}
 {#################################}
procedure TForm_Main.menu_previewClick(Sender: TObject);
begin
  open_child('preview', -1);
end;


procedure TForm_Main.menu_txmpreplaceClick(Sender: TObject);
begin
  open_child('txmpreplace', -1);
end;


procedure TForm_Main.menu_bineditClick(Sender: TObject);
begin
  open_child('binedit', -1);
end;


procedure TForm_Main.menu_raweditClick(Sender: TObject);
begin
  open_child('rawedit', -1);
end;


procedure TForm_Main.menu_extractorClick(Sender: TObject);
begin
  open_child('extractor', -1);
end;


procedure TForm_Main.menu_metaClick(Sender: TObject);
begin
  ShowMessage('TBD');
end;


procedure TForm_Main.menu_filecompareClick(Sender: TObject);
begin
  open_child('compare', -1);
end;


 {#################################}
 {#####   View-Menu-Handlers  #####}
 {#################################}
procedure TForm_Main.menu_view_mdibarClick(Sender: TObject);
begin
  menu_view_mdibar.Checked := not menu_view_mdibar.Checked;
  mditoolbar.Visible := menu_view_mdibar.Checked;
end;




procedure TForm_Main.menu_view_statusbarClick(Sender: TObject);
begin
  menu_view_statusbar.Checked := not menu_view_statusbar.Checked;
  statbar.Visible := menu_view_statusbar.Checked;
end;




procedure TForm_Main.menu_view_toolbarClick(Sender: TObject);
begin
  menu_view_toolbar.Checked := not menu_view_toolbar.Checked;
  Toolbar.Visible := menu_view_toolbar.Checked;
end;



 {#################################}
 {#####  Window-Menu-Handlers #####}
 {#################################}
procedure TForm_Main.menu_windows_cascadeClick(Sender: TObject);
begin
  Self.Cascade;
end;



procedure TForm_Main.menu_windows_tileClick(Sender: TObject);
begin
  Self.TileMode := tbHorizontal;
  Self.Tile;
end;

procedure TForm_Main.menu_windows_tilevertClick(Sender: TObject);
begin
  Self.TileMode := tbVertical;
  Self.Tile;
end;


procedure TForm_Main.menu_windows_closeallClick(Sender: TObject);
begin
  MDITab.CloseAll;
end;



procedure TForm_Main.menu_windows_nextClick(Sender: TObject);
begin
  if MDIChildCount > 1 then
    if MDITab.TabIndex = MDITab.MDIChildCount - 1 then
      MDITab.MDIChildren[0].BringToFront
    else
      MDITab.MDIChildren[MDITab.TabIndex + 1].BringToFront;
end;



procedure TForm_Main.menu_windows_previousClick(Sender: TObject);
begin
  if MDIChildCount > 1 then
    if MDITab.TabIndex = 0 then
      MDITab.MDIChildren[MDITab.MDIChildCount - 1].BringToFront
    else
      MDITab.MDIChildren[MDITab.TabIndex - 1].BringToFront;
end;






procedure TForm_Main.menu_AboutClick(Sender: TObject);
begin
  ShowMessage('Will be implemented later ;)');
end;




function TForm_Main.open_child(window_context: String; fileid: Integer): TForm_ToolTemplate;
var
  toolform:    TForm_ToolTemplate;
  i:           Integer;
  tag:         Integer;
  caption_end: String;
  iconindex:   Integer;
begin
  Result := nil;

  tag := 1;
  if MDIChildCount > 0 then
    for i := 0 to MDIChildCount - 1 do
      if MDIChildren[i].Tag >= tag then
        tag := MDIChildren[i].Tag + 1;

  iconindex := -1;
  caption_end := IntToStr(tag) + '       ';

  if window_context = 'binedit' then
  begin
    toolform         := TForm_BinEdit.Create(Self);
    toolform.Caption := 'Binary .dat-Editor ' + caption_end;
    iconindex        := 5;
  end;
  if window_context = 'extractor' then
  begin
    toolform         := TForm_Extractor.Create(Self);
    toolform.Caption := 'Extractor ' + caption_end;
    iconindex        := 8;
  end;
  if window_context = 'preview' then
  begin
    toolform         := TForm_Preview.Create(Self);
    toolform.Caption := 'Preview-Window ' + caption_end;
    iconindex        := 4;
  end;
  if window_context = 'rawedit' then
  begin
    toolform         := TForm_RawEdit.Create(Self);
    toolform.Caption := 'Binary .raw-Editor ' + caption_end;
    iconindex        := 6;
  end;
  if window_context = 'txmpreplace' then
  begin
    toolform         := TForm_TxmpReplace.Create(Application);
    toolform.Caption := 'TXMP Replacer ' + caption_end;
    iconindex        := 7;
  end;

  if Assigned(toolform) then
  begin
    toolform.Name    := window_context + IntToStr(tag);
    toolform.Tag     := tag;
    MDITab.AddTab(TForm(toolform), iconindex);
    toolform.Caption := AnsiReplaceStr(toolform.Caption, '       ', '');
    if fileid > -1 then
      toolform.SelectFileID(fileid);
    Result := toolform;
  end;
end;

end.
