unit uDeleteMultipleGamesFiles;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, VirtualTrees, StdCtrls, GR32_Image, IniFiles, uCommon;

type
  pGameInfo_del = ^TGameInfo_del;
  TGameInfo_del = record
    delImageIndex: Integer;
    delDescription,
    delName,
    delClone: String;
    delMerged: Boolean;
    delSystem: Integer;
    delFileName: String;
  end;

type
  TFormDeleteMultipleGamesFiles = class(TForm)
    TopImage: TImage32;
    LabelSystemDescription: TLabel;
    ButtonDelete: TButton;
    ButtonClose: TButton;
    GamesFilesToDelete: TVirtualStringTree;
    ButtonClearSelected: TButton;
    ButtonReload: TButton;
    LabelTotalGames: TLabel;
    procedure GamesFilesToDeleteCompareNodes(Sender: TBaseVirtualTree; Node1,
      Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
    procedure GamesFilesToDeleteFreeNode(Sender: TBaseVirtualTree;
      Node: PVirtualNode);
    procedure GamesFilesToDeleteGetHint(Sender: TBaseVirtualTree;
      Node: PVirtualNode; Column: TColumnIndex;
      var LineBreakStyle: TVTTooltipLineBreakStyle;
      var HintText: WideString);
    procedure GamesFilesToDeleteGetText(Sender: TBaseVirtualTree;
      Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
      var CellText: WideString);
    procedure GamesFilesToDeleteGetImageIndex(Sender: TBaseVirtualTree;
      Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
      var Ghosted: Boolean; var ImageIndex: Integer);
    procedure GamesFilesToDeleteHeaderClick(Sender: TVTHeader;
      Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
      Y: Integer);
    procedure GamesFilesToDeleteIncrementalSearch(Sender: TBaseVirtualTree;
      Node: PVirtualNode; const SearchText: WideString;
      var Result: Integer);
    procedure GamesFilesToDeleteKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure ButtonReloadClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure ButtonCloseClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure GamesFilesToDeletePaintText(Sender: TBaseVirtualTree;
      const TargetCanvas: TCanvas; Node: PVirtualNode;
      Column: TColumnIndex; TextType: TVSTTextType);
    procedure ButtonDeleteClick(Sender: TObject);
    procedure GamesFilesToDeleteChange(Sender: TBaseVirtualTree;
      Node: PVirtualNode);
    procedure ButtonClearSelectedClick(Sender: TObject);
    procedure FormKeyPress(Sender: TObject; var Key: Char);
  private
    { Private declarations }
    delSelectedNode: PVirtualNode;
    SystemAffected: array[1..MaxArcadeSystems] of Boolean;
    procedure UpdateTotalGames;
    procedure AddGamesToList;
    procedure DeleteGamesFiles;
  public
    { Public declarations }
  end;

var
  FormDeleteMultipleGamesFiles: TFormDeleteMultipleGamesFiles;

implementation

uses uMain, uStatus, uFilesUtil;

{$R *.dfm}

procedure TFormDeleteMultipleGamesFiles.UpdateTotalGames;
begin
  LabelTotalGames.Caption:= Format('%.6u Games', [GamesFilesToDelete.TotalCount]);
end;

procedure TFormDeleteMultipleGamesFiles.AddGamesToList;
var
  sel_Node, Node: PVirtualNode;
  Data: pGameInfo_del;
  sel_Data: pGameInfo;
  FileToSearch, FullPath: String;
begin
  FormStatus.LabelStatusType.Caption:= 'Load Games';
  FormStatus.LabelMessage.Caption:= 'Scanning selected games to be deleted.';
  FormStatus.Show;
  FormStatus.Refresh;
  Screen.Cursor:= crHourGlass;
  FormMain.ClearTreeView(GamesFilesToDelete);
  GamesFilesToDelete.NodeDataSize:= SizeOf(TGameInfo_del);
  GamesFilesToDelete.RootNodeCount:= 0;
  GamesFilesToDelete.BeginUpdate;
  FormMain.LoadFoldersAllSystems;
  if FormMain.SelectedFilterName = 'favorites' then
     sel_Node:= FormMain.GamesTreeView.GetFirstVisible
  else
     sel_Node:= FormMain.GamesTreeView.GetFirstSelected;
  repeat
    sel_Data:= FormMain.GamesTreeView.GetNodeData(sel_Node);
    if not FormMain.IsSystemEntry(sel_Data.eDriverName) then
       begin
         // check if game is set as available
         // check if game is clone and is merged
         // yes ? get filename of parent set and add to the list
         // no ? skip to the next selected game
         if sel_Data.eROMIdentification in [00..02, // MAME
                                            06, 07, // ZiNc
                                            10, 11, // Daphne
                                            14..16, // AGEMAME
                                            20..22, // PinMAME
                                            26, 27] then // HazeMD
            begin
              Node:= GamesFilesToDelete.AddChild(nil);
              Data:= GamesFilesToDelete.GetNodeData(Node);
              Data.delDescription:= sel_Data.eDescription;
              Data.delName:= sel_Data.eName;
              Data.delClone:= sel_Data.eClone;
              Data.delMerged:= False;
              Data.delSystem:= FormMain.GetSystemID(sel_Data.eROMIdentification);
              Data.delImageIndex:= sel_Data.eImageIndex;
              SystemAffected[Data.delSystem]:= True;
              FileToSearch:= Data.delName;
              if Data.delSystem in [1, 4, 5, 6] then
                 begin
                   if Data.delClone <> '' then
                      begin
                        if sel_Data.eMerged <> '' then
                           begin
                             FileToSearch:= Data.delClone;
                             Data.delMerged:= True;
                           end;
                      end;
                 end;
              FullPath:= FormMain.SearchZIPFolder(FileToSearch, Data.delSystem);
              Data.delFileName:= FullPath;
            end;
       end;
    if FormMain.SelectedFilterName = 'favorites' then
       sel_Node:= FormMain.GamesTreeView.GetNextVisible(sel_Node)
    else
       sel_Node:= FormMain.GamesTreeView.GetNextSelected(sel_Node);
  until sel_Node = nil;
  GamesFilesToDelete.SortTree(0, sdAscending);
  GamesFilesToDelete.EndUpdate;
  FormStatus.Close;
  Screen.Cursor:= crDefault;
  UpdateTotalGames;
end;

procedure TFormDeleteMultipleGamesFiles.DeleteGamesFiles;
var
  Node: PVirtualNode;
  Data: pGameInfo_del;
  Count: Integer;
  ListNotDeleted: TStringList;
begin
  FormStatus.LabelStatusType.Caption:= 'Delete Files';
  FormStatus.LabelMessage.Caption:= '';
  FormStatus.ProgressBar.MaxValue:= GamesFilesToDelete.TotalCount-1;
  FormStatus.ProgressBar.Progress:= 0;
  FormStatus.Show;
  FormStatus.Refresh;
  Screen.Cursor:= crHourGlass;
  Count:= 0;
  GamesFilesToDelete.BeginUpdate;
  ListNotDeleted:= TStringList.Create;
  ListNotDeleted.BeginUpdate;
  repeat
    Data:= GamesFilesToDelete.GetNodeData(Node);
    FormStatus.LabelMessage.Caption:= Data.delFileName;
    if FileExists(Data.delFileName) then
       begin
         if not DeleteFile(Data.delFileName) then
            ListNotDeleted.Add(Data.delFileName)
       end;
    Node:= GamesFilesToDelete.GetNext(Node);
    Inc(Count);
    FormStatus.ProgressBar.Progress:= Count;
  until Node = nil;
  ListNotDeleted.EndUpdate;
  FormStatus.Close;
  Screen.Cursor:= crDefault;
  ClearList;
  UpdateTotalGames;
  if ListNotDeleted.Count > 0 then
     GenerateMessage('Failed to Delete', 'The following files could not be deleted:'+#13#10+#13#10+
                     ListNotDeleted.Text, 2);
  FreeAndNil(ListNotDeleted);
end;

procedure TFormDeleteMultipleGamesFiles.GamesFilesToDeleteCompareNodes(
  Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode;
  Column: TColumnIndex; var Result: Integer);
var
  Data1, Data2: pGameInfo_del;
begin
  Data1:= Sender.GetNodeData(Node1);
  Data2:= Sender.GetNodeData(Node2);
  case Column of
    0: Result:= CompareText(Data1.delDescription, Data2.delDescription);
    1: Result:= CompareText(Data1.delName, Data2.delName);
    2: Result:= CompareText(Data1.delClone, Data2.delClone);
    3: Result:= CompareText(Data1.delFileName, Data2.delFileName);
  end;
end;

procedure TFormDeleteMultipleGamesFiles.GamesFilesToDeleteFreeNode(
  Sender: TBaseVirtualTree; Node: PVirtualNode);
var
  Data: pGameInfo_del;
begin
  Data:= Sender.GetNodeData(Node);
  Finalize(Data^);
end;

procedure TFormDeleteMultipleGamesFiles.GamesFilesToDeleteGetHint(
  Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
  var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: WideString);
var
  Data: pGameInfo_del;
begin
  Data:= Sender.GetNodeData(Node);
  case Column of
    0: HintText:= Data.delDescription;
    1: HintText:= Data.delName;
    2: HintText:= Data.delClone;
    3: HintText:= Data.delFileName;
  end;
end;

procedure TFormDeleteMultipleGamesFiles.GamesFilesToDeleteGetText(
  Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
  TextType: TVSTTextType; var CellText: WideString);
var
  Data: pGameInfo_del;
begin
  Data:= Sender.GetNodeData(Node);
  case Column of
    0: CellText:= Data.delDescription;
    1: CellText:= Data.delName;
    2: CellText:= Data.delClone;
    3: CellText:= Data.delFileName;
  end;
end;

procedure TFormDeleteMultipleGamesFiles.GamesFilesToDeleteGetImageIndex(
  Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind;
  Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer);
var
  Data: pGameInfo_del;
begin
  if Kind in [ikNormal, ikSelected] then
     begin
       Data:= Sender.GetNodeData(Node);
       case Column of
         0: ImageIndex:= Data.delImageIndex;
         3: ImageIndex:= Data.delSystem+MaxGameID;
       end;
     end;
end;

procedure TFormDeleteMultipleGamesFiles.GamesFilesToDeleteHeaderClick(
  Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbLeft then
     begin
       with Sender, Treeview do
       begin
         if SortColumn > NoColumn then
            Columns[SortColumn].Options:= Columns[SortColumn].Options + [coParentColor];

         if (SortColumn = NoColumn) or (SortColumn <> Column) then
            begin
              SortColumn:= Column;
              SortDirection:= sdAscending;
            end
         else
            if SortDirection = sdAscending then
              SortDirection:= sdDescending
            else
              SortDirection:= sdAscending;

         Columns[SortColumn].Color:= $F7F7F7;
         SortTree(SortColumn, SortDirection, False);
         ScrollIntoView(delSelectedNode, True);
       end;
     end;
end;

procedure TFormDeleteMultipleGamesFiles.GamesFilesToDeleteIncrementalSearch(
  Sender: TBaseVirtualTree; Node: PVirtualNode;
  const SearchText: WideString; var Result: Integer);
var
  StringsText,
  EntryText: String;
  Data: pGameInfo_del;
begin
  StringsText:= SearchText;
  Data:= Sender.GetNodeData(Node);
  EntryText:= Data.delDescription;
  Result := AnsiStrLIComp(PChar(StringsText), PChar(EntryText), Length(StringsText));
end;

procedure TFormDeleteMultipleGamesFiles.GamesFilesToDeleteKeyDown(
  Sender: TObject; var Key: Word; Shift: TShiftState);
begin
  if Key = VK_DELETE then
     ButtonClearSelected.Click;
end;

procedure TFormDeleteMultipleGamesFiles.ButtonReloadClick(Sender: TObject);
begin
  AddGamesToList;
end;

procedure TFormDeleteMultipleGamesFiles.FormCreate(Sender: TObject);
var
  Loop: ShortInt;
begin
  FormMain.SetAlphaBlendTreeView(GamesFilesToDelete);
  for Loop:= 1 to MaxArcadeSystems do
      SystemAffected[Loop]:= False;
end;

procedure TFormDeleteMultipleGamesFiles.ButtonCloseClick(Sender: TObject);
begin
  Close;
end;

procedure TFormDeleteMultipleGamesFiles.FormShow(Sender: TObject);
begin
  AddGamesToList;
end;

procedure TFormDeleteMultipleGamesFiles.GamesFilesToDeletePaintText(
  Sender: TBaseVirtualTree; const TargetCanvas: TCanvas;
  Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType);
var
  Data: pGameInfo_del;
begin
  Data:= Sender.GetNodeData(Node);
  if Data.delMerged then
     begin
       if Column = 3 then
          TargetCanvas.Font.Color:= clRed;
     end;
  if Sender.Selected[Node] then
     begin
       TargetCanvas.Font.Color:= clWhite;
       //if FormPreferences.SelectedGameBoldFont.Checked then
       //   if not IsSystemEntry(Data.eDriverName) then
       //      TargetCanvas.Font.Style:= TargetCanvas.Font.Style+[fsBold];
     end;

end;

procedure TFormDeleteMultipleGamesFiles.ButtonDeleteClick(Sender: TObject);
var
  Loop: ShortInt;
begin
  if GamesFilesToDelete.TotalCount = 0 then
     Exit;

  if GenerateMessage('Delete Files', 'All files on the list will be deleted. '+
                  'Files that fail to be deleted will be listed on a message box.'+#13#10+
                  'Continue ?', 1) = mrNo then
     Exit;
  DeleteGamesFiles;
  if GenerateMessage('Update Games List', 'Would you like to refresh the games list now ? '+
                     'Only the affected systems will be updated', 1) = mrYes then
     begin
       for Loop:= 1 to MaxArcadeSystems do
       begin
         if SystemAffected[Loop] then
            FormMain.CallRefreshGames(1, False, Loop);
       end;
     end;
  Close; 
end;

procedure TFormDeleteMultipleGamesFiles.GamesFilesToDeleteChange(
  Sender: TBaseVirtualTree; Node: PVirtualNode);
begin
 if (Sender.SelectedCount = 1) and (Sender.Visible) then
     begin
       if delSelectedNode <> Node then
          delSelectedNode:= Node;
     end;
end;

procedure TFormDeleteMultipleGamesFiles.ButtonClearSelectedClick(
  Sender: TObject);
begin
  ButtonClearSelected.Click;
  UpdateTotalGames;
end;

procedure TFormDeleteMultipleGamesFiles.FormKeyPress(Sender: TObject;
  var Key: Char);
begin
  if Key = #27 then
     Close;
end;

end.
