unit Template;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, StrUtils,
  Data, TypeDefs, Menus, Buttons;

type
  TNewFileSelectedEvent = procedure(FileInfo: TFileInfo) of object;
  TNewConnectionEvent = procedure(Connection: Integer) of object;
  TCheckCloseableEvent = function: Boolean of object;

  TForm_ToolTemplate = class(TForm)
    panel_files: TPanel;
    filelist: TListBox;
    panel_extension: TPanel;
    label_ext: TLabel;
    combo_extension: TComboBox;
    check_zerobyte: TCheckBox;
    edit_filtername: TEdit;
    check_filtername: TCheckBox;
    Splitter1: TSplitter;
    content: TPanel;
    filepopup: TPopupMenu;
    popup_import: TMenuItem;
    popup_export: TMenuItem;
    popup_separator: TMenuItem;
    importd: TOpenDialog;
    exportd: TSaveDialog;
    btn_sort_id_asc: TSpeedButton;
    btn_sort_id_desc: TSpeedButton;
    btn_sort_name_asc: TSpeedButton;
    btn_sort_name_desc: TSpeedButton;
    btn_sort_ext_asc: TSpeedButton;
    btn_sort_ext_desc: TSpeedButton;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    combo_connection: TComboBox;
    Bevel1: TBevel;
    popup_linkshere: TMenuItem;
    popup_separator2: TMenuItem;
    procedure RecreateExtList;
    procedure UpdateConList;
    procedure LoadFileNames;
    procedure SelectFileName(ConnectionID: Integer; FileName: String);
    procedure SelectFileID(ConnectionID, FileID: Integer);
    procedure SelectConnection(ConnectionID: Integer);
    procedure check_filternameClick(Sender: TObject);
    procedure check_zerobyteClick(Sender: TObject);
    procedure combo_extensionClick(Sender: TObject);
    procedure listClick(Sender: TObject);
    procedure listMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);

    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure popup_importClick(Sender: TObject);
    procedure popup_exportClick(Sender: TObject);
    procedure popup_opentool(Sender: TObject);
    procedure filepopupPopup(Sender: TObject);
    procedure btn_sortClick(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure combo_connectionChange(Sender: TObject);
    procedure popup_linkshereClick(Sender: TObject);
  private
    FSortBy: TSortType;
    FOnNewFileSelected: TNewFileSelectedEvent;
    FOnNewConnection: TNewConnectionEvent;
    FOnCheckCloseable: TCheckCloseableEvent;
    FAllowedExts: String;
    FAllowMultiSelect: Boolean;
    FSelectedFile: TFileInfo;
    FConnectionID: Integer;
    procedure SetAllowedExts(exts: String);
    procedure SetMultiSelect(allow: Boolean);
    function GetToolCloseable: Boolean;
  public
    constructor Create(AOwner: TComponent); override;
    procedure SetFileFilters(pattern, extension: String; zerobytes: Boolean);
  published
    property OnNewFileSelected: TNewFileSelectedEvent read FOnNewFileSelected write FOnNewFileSelected;
    property OnNewConnection: TNewConnectionEvent read FOnNewConnection write FOnNewConnection;
    property OnCheckCloseable: TCheckCloseableEvent read FOnCheckCloseable write FOnCheckCloseable;
    property AllowedExts: String read FAllowedExts write SetAllowedExts;
    property AllowMultiSelect: Boolean read FAllowMultiSelect write SetMultiSelect;
    property SelectedFile: TFileInfo read FSelectedFile;
    property ConnectionID: Integer read FConnectionID;
    property Closeable: Boolean read GetToolCloseable;
  end;

var
  ToolList: TToolList;
procedure AddToolListEntry(context, name, exts: String);

implementation
{$R *.dfm}
uses Main, ConnectionManager, Exporters, Functions, WhatLinksHere;


procedure TForm_ToolTemplate.UpdateConList;
var
  i: Integer;
  fn, datatype, boxstring: String;
  level: Integer;
begin
  combo_connection.ItemIndex := -1;
  combo_connection.Items.Clear;
  if ConManager.Count > 0 then
  begin
    for i := 0 to ConManager.Count - 1 do
    begin
      level := ConManager.ConnectionByIndex[i].LevelNumber;
      fn := ExtractFileName(ConManager.ConnectionByIndex[i].FileName);
      if ConManager.ConnectionByIndex[i].Backend = DB_ONI then
        datatype := 'ONI-.dat: '
      else if ConManager.ConnectionByIndex[i].Backend = DB_ADB then
        datatype := 'OUP-DB: '
      else
        datatype := 'Unknown: ';
      boxstring := datatype + fn + ' (Level: ' + IntToStr(level) + ') [' + IntToStr(ConManager.ConnectionByIndex[i].ConnectionID) + ']';
      combo_connection.Items.Add(boxstring);
      if ConManager.ConnectionByIndex[i].ConnectionID = FConnectionID then
        combo_connection.ItemIndex := combo_connection.Items.Count - 1;
    end;
    if combo_connection.ItemIndex = -1 then
    begin
      combo_connection.ItemIndex := 0;
      combo_connectionChange(Self);
    end;
  end
  else
  begin
    FConnectionID := 0;
    filelist.Items.Clear;
    combo_extension.Items.Clear;
    combo_connectionChange(Self);
    FSelectedFile.ID := -1;
    if Assigned(FOnNewFileSelected) then
      FOnNewFileSelected(FSelectedFile);
  end;
end;

procedure TForm_ToolTemplate.RecreateExtList;
var
  i:    Integer;
  exts: TStrings;
begin
  combo_extension.Items.Clear;
  if FConnectionID > -1 then
  begin
    combo_extension.Items.Add('_All files_ (' +
      IntToStr(ConManager.Connection[FConnectionID].GetFileCount) + ')');
    exts := nil;
    exts := ConManager.Connection[FConnectionID].GetExtensionsList(EF_ExtCount);
    for i := 0 to exts.Count - 1 do
      if Length(FAllowedExts) > 0 then
      begin
        if Pos(MidStr(exts.Strings[i],1,4), FAllowedExts) > 0 then
          combo_extension.Items.Add(exts.Strings[i]);
      end
      else
        combo_extension.Items.Add(exts.Strings[i]);
    combo_extension.ItemIndex := 0;
    combo_extensionClick(Self);
    exts.Free;
  end;
end;




procedure TForm_ToolTemplate.LoadFileNames;
var
  Extension: String;
  no_zero_bytes: Boolean;
  pattern: String;
  files: TStrings;
begin
  if FConnectionID > -1 then
  begin
    Extension := MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex], 1, 4);
    no_zero_bytes := not check_zerobyte.Checked;
    pattern := '';
    if check_filtername.Checked then
      pattern := edit_filtername.Text;
    if Extension = '_All' then
      if Length(FAllowedExts) > 0 then
        Extension := FAllowedExts
      else
        Extension := '';

    files := nil;
    files := ConManager.Connection[FConnectionID].GetFilesList(extension, pattern, no_zero_bytes, FSortBy);

    filelist.Visible := False;
    filelist.Items.Clear;
    if files.Count > 0 then
      filelist.Items.AddStrings(files);
    filelist.Visible := True;
  end;
end;


procedure TForm_ToolTemplate.popup_exportClick(Sender: TObject);
var
  id: Integer;
  ext: String;
begin
  id := ConManager.Connection[FConnectionID].ExtractFileIDOfName(filelist.Items.Strings[filelist.ItemIndex]);
  ext := RightStr(filelist.Items.Strings[filelist.ItemIndex], 4);
  exportd.Filter := 'Files of matching extension (*.' + ext + ')|*.' + ext + '|All files|*.*';
  exportd.DefaultExt := ext;
  if exportd.Execute then
    ExportDatFile(FConnectionID, id, exportd.FileName);
end;

procedure TForm_ToolTemplate.popup_importClick(Sender: TObject);
var
  id: Integer;
  finfo: TFileInfo;
  fs: TFileStream;
begin
  if CR_EditDat in ConManager.Connection[FConnectionID].ChangeRights then
  begin
    id := ConManager.Connection[FConnectionID].ExtractFileIDOfName(filelist.Items.Strings[filelist.ItemIndex]);
    finfo := ConManager.Connection[FConnectionID].GetFileInfo(id);

    importd.Filter := 'Files of matching extension (*.' + finfo.Extension + ')|*.' +
          finfo.Extension + '|All files|*.*';
    if importd.Execute then
    begin
      fs := TFileStream.Create(importd.FileName, fmOpenRead);
      if fs.Size <> finfo.Size then
      begin
        if not (CR_ResizeDat in ConManager.Connection[FConnectionID].ChangeRights) then
        begin
          ShowMessage('Can''t import ' + ExtractFilename(importd.FileName) +
            ', file has to have same size as file in .dat with this backend.' + CrLf +
            'Size of file in .dat: ' + FormatFileSize(finfo.Size) + CrLf +
            'Size of chosen file: ' + FormatFileSize(fs.Size));
          Exit;
        end else begin
          if MessageBox(Self.Handle,
              PChar('File has different size from the file in the .dat.' + CrLf +
                    'Size of file in .dat: ' + FormatFileSize(finfo.Size) + CrLf +
                    'Size of chosen file: ' + FormatFileSize(fs.Size) + CrLf +
                    'Replace anyway?'), PChar('Different size'), MB_YESNO + MB_ICONWARNING) = ID_NO then
          begin
            Exit;
          end;
        end;
      end;
      ConManager.Connection[FConnectionID].UpdateDatFile(id, fs);
      Self.listClick(Self);
      fs.Free;
    end;
  end else begin
    ShowMessage('Editing .dat-contents not allowed with this backend.');
  end;
end;

procedure TForm_ToolTemplate.popup_linkshereClick(Sender: TObject);
begin
  Form_WhatLinksHere.ConID := FConnectionID;
  Form_WhatLinksHere.FileID := FSelectedFile.ID;
//  Form_WhatLinksHere.SenderForm := Self;
  Form_WhatLinksHere.Show;
end;

procedure TForm_ToolTemplate.popup_opentool(Sender: TObject);
var
  sender_name, context: String;
  id: Integer;
begin
  sender_name := TComponent(Sender).Name;
  id := ConManager.Connection[FConnectionID].ExtractFileIDOfName(filelist.Items.Strings[filelist.ItemIndex]);
  context := MidStr(sender_name, Pos('_', sender_name) + 1, Length(sender_name) - Pos('_', sender_name));
  Form_Main.open_child(context, FConnectionID, id);
end;

procedure TForm_ToolTemplate.combo_connectionChange(Sender: TObject);
var
  name: String;
begin
  if combo_connection.ItemIndex >= 0 then
  begin
    name := combo_connection.Items.Strings[combo_connection.ItemIndex];
    FConnectionID := StrToInt(MidStr(name, Pos('[', name) + 1, Pos(']', name) - Pos('[', name)  - 1));
  end
  else
    FConnectionID := -1;
  RecreateExtList;
  if Assigned(FOnNewConnection) then
    FOnNewConnection(FConnectionID);
end;

procedure TForm_ToolTemplate.combo_extensionClick(Sender: TObject);
begin
  LoadFileNames;
end;


constructor TForm_ToolTemplate.Create(AOwner: TComponent);
var
  i: Integer;
  item: TMenuItem;
begin
  inherited;
  Self.Width  := 260;
  Self.Height := 300;
  FAllowedExts := '';
  FAllowMultiSelect := False;
  FOnNewFileSelected := nil;
  FOnNewConnection := nil;
  FOnCheckCloseable := nil;
  FConnectionID := -1;
  FSelectedFile.ID := -1;
  UpdateConList;
  if Length(ToolList) > 0 then
  begin
    for i := 0 to High(ToolList) do
    begin
      item := TMenuItem.Create(filepopup);
      item.Name := 'popup_' + ToolList[i].context;
      item.Caption := 'Open with ' + ToolList[i].name;
      item.OnClick := Self.popup_opentool;
      filepopup.Items.Insert(i, item);
    end;
  end;
end;

procedure TForm_ToolTemplate.filepopupPopup(Sender: TObject);
var
  ext: String;
  i: Integer;
begin
  ext := RightStr(filelist.Items.Strings[filelist.ItemIndex], 4);
  for i := 0 to High(ToolList) do
  begin
    filepopup.Items.Items[i].Enabled := True;
    if Length(ToolList[i].exts) > 0 then
      if Pos(ext, ToolList[i].exts) = 0 then
        filepopup.Items.Items[i].Enabled := False;
  end;
end;

procedure TForm_ToolTemplate.check_zerobyteClick(Sender: TObject);
begin
  LoadFileNames;
end;

procedure TForm_ToolTemplate.btn_sortClick(Sender: TObject);
begin
  if btn_sort_id_asc.Down then
    FSortBy := ST_IDAsc
  else if btn_sort_id_desc.Down then
    FSortBy := ST_IDDesc
  else if btn_sort_name_asc.Down then
    FSortBy := ST_NameAsc
  else if btn_sort_name_desc.Down then
    FSortBy := ST_NameDesc
  else if btn_sort_ext_asc.Down then
    FSortBy := ST_ExtAsc
  else if btn_sort_ext_desc.Down then
    FSortBy := ST_ExtDesc;
  LoadFileNames;
end;

procedure TForm_ToolTemplate.check_filternameClick(Sender: TObject);
begin
  edit_filtername.Enabled := not check_filtername.Checked;
  LoadFileNames;
end;

procedure TForm_ToolTemplate.listClick(Sender: TObject);
var
  fileid: Integer;
begin
  if filelist.ItemIndex > -1 then
  begin
    fileid := ConManager.Connection[FConnectionID].ExtractFileIDOfName(
          filelist.Items.Strings[filelist.ItemIndex]);
    FSelectedFile := ConManager.Connection[FConnectionID].GetFileInfo(fileid);
    if Assigned(FOnNewFileSelected) then
      FOnNewFileSelected(FSelectedFile);
  end;
end;

procedure TForm_ToolTemplate.listMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  pt: TPoint;
begin
  pt.X := x;
  pt.Y := y;
  if Shift = [ssRight] then
  begin
    filelist.ItemIndex := filelist.ItemAtPos(pt, true);
    Self.listClick(Self);
  end;
end;



procedure TForm_ToolTemplate.SelectConnection(ConnectionID: Integer);
begin
  if FConnectionID <> ConnectionID then
  begin
    combo_connection.ItemIndex := ConManager.ConnectionIndexByID[ConnectionID];
    combo_connectionChange(Self);
  end;
end;

procedure TForm_ToolTemplate.SelectFileID(ConnectionID, FileID: Integer);
var
  i: Integer;
begin
  if FConnectionID <> ConnectionID then
    SelectConnection(ConnectionID);

  filelist.ItemIndex := -1;
  if filelist.Items.Count > 0 then
    for i := 0 to filelist.Items.Count - 1 do
      if ConManager.Connection[FConnectionID].ExtractFileIDOfName(filelist.Items.Strings[i]) = FileID then
      begin
        filelist.ItemIndex := i;
        Break;
      end;
  Self.listClick(Self);
end;

procedure TForm_ToolTemplate.SelectFileName(ConnectionID: Integer; filename: String);
var
  i: Integer;
begin
  if FConnectionID <> ConnectionID then
    SelectConnection(ConnectionID);

  filelist.ItemIndex := -1;
  if filelist.Items.Count > 0 then
    for i := 0 to filelist.Items.Count - 1 do
      if filelist.Items.Strings[i] = filename then
        filelist.ItemIndex := i;
  Self.listClick(Self);
end;

procedure TForm_ToolTemplate.SetAllowedExts(exts: String);
begin
  FAllowedExts := exts;
  RecreateExtList;
end;

procedure TForm_ToolTemplate.SetFileFilters(pattern, extension: String;
  zerobytes: Boolean);
var
  i: Integer;
begin
  if Length(pattern) > 0 then
    Self.edit_filtername.Text := pattern;
  Self.check_filtername.Checked := Length(pattern) > 0;
  if Length(extension) > 0 then
  begin
    for i := 0 to Self.combo_extension.Items.Count - 1 do
      if Pos(extension, Self.combo_extension.Items.Strings[i]) > 0 then
        Break;
    if i < Self.combo_extension.Items.Count then
      Self.combo_extension.ItemIndex := i
    else
      Self.combo_extension.ItemIndex := -1;
  end;
  Self.check_zerobyte.Checked := zerobytes;
  Self.LoadFileNames;
end;

procedure TForm_ToolTemplate.SetMultiSelect(allow: Boolean);
begin
  FAllowMultiSelect := allow;
  filelist.MultiSelect := allow;
end;


function TForm_ToolTemplate.GetToolCloseable: Boolean;
begin
  if Assigned(FOnCheckCloseable) then
    Result := FOnCheckCloseable
  else
    Result := True;
end;

procedure TForm_ToolTemplate.FormActivate(Sender: TObject);
begin
  if edit_filtername.CanFocus then
    edit_filtername.SetFocus
  else
    if content.CanFocus then
      content.SetFocus;
end;

procedure TForm_ToolTemplate.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;


procedure AddToolListEntryExt(context, ext: String);
var
  i: Integer;
begin
  for i := 0 to High(ToolList) do
    if ToolList[i].context = context then
    begin
      if Pos(ext, ToolList[i].exts) = 0 then
      begin
        if Length(ToolList[i].exts) = 0 then
          ToolList[i].exts := ext
        else
          ToolList[i].exts := ToolList[i].exts + ',' + ext;
      end;
      Exit;
    end;
end;

procedure AddToolListEntry(context, name, exts: String);
var
  i: Integer;
begin
  if Length(ToolList) > 0 then
  begin
    for i := 0 to High(ToolList) do
      if ToolList[i].context = context then
      begin
        if (Length(ToolList[i].name) = 0) and (Length(name) > 0) then
          ToolList[i].name := name;
        if Length(exts) > 0 then
          AddToolListEntryExt(context, exts);
        Exit;
      end;
  end;
  SetLength(ToolList, Length(ToolList) + 1);
  for i := High(ToolList) downto 1 do
    if ToolList[i - 1].name > name then
      ToolList[i] := ToolList[i - 1]
    else
      Break;
  ToolList[i].context := context;
  ToolList[i].name := name;
  ToolList[i].exts := exts;
end;

end.