//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "MainForm.h"
#include <ctime>

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TfrmMain *frmMain;

__fastcall TfrmMain::TfrmMain(TComponent* Owner) : TForm(Owner)
{
  Abort = false;
}
//---------------------------------------------------------------------------

/*
  Finds all files in the directory "Directory" of the type "FileSpec" and
  adds them to "List". Example:

    CatalogFiles("C:\Windows\System32", "*.exe", SomeList);

*/
int TfrmMain::CatalogFiles(const AnsiString& Directory, const AnsiString& FileSpec, TStringList& List)
{
  TSearchRec finfo;
  int done, count = 0;
  AnsiString dir;

    //Make sure there is a trailing "/"
  dir = IncludeTrailingPathDelimiter(Directory);

    // Display the current directory in the status bar
  if (chkDisplayInStatusBar->Checked)
    barStatus->SimpleText = Directory;


    // Prime the search (See help on FindFirst/FindNext)
  done = FindFirst(dir + FileSpec, faAnyFile, finfo);

    // Until no more files match (or the user stopped it)
  while ((done == 0) && (!Abort))
  {
    //if not ((finfo.Attr and faDirectory) <> 0) and (finfo.Name <> '.') and (finfo.Name <> '..') then begin

      // Ignore current directory and parent directory
    if ((finfo.Name != ".") && (finfo.Name != ".."))
    {
        // Add the filename to the list
      List.Add(finfo.Name);

        // Inserting at the front of the list or adding to the back?
      if (chkInsertAtFront->Checked)
        lstFiles->Items->Insert(0, Directory + finfo.Name);
      else
        lstFiles->Items->Add(Directory + finfo.Name);

        // Update the UI (After every file)
      if (grpUpdateFrequency->ItemIndex == 0)
        lblCount->Caption = IntToStr(lstFiles->Count);

      count++;
    }
      // Next match?
    done = FindNext(finfo);

      // Yield
    Application->ProcessMessages();
  }
    // Done searching
  FindClose(finfo);
  return count;
}

/*
  Finds all files in the directory "Directory" of the type "FileSpec" and
  adds them to "List". If "IncludeSubdirectories" is true, it will call
  itself recursively. Example:

    FindFiles("C:\Windows\System32", "*.exe", SomeList, true);

  The real work is done by the CatalogFiles above.

*/
int TfrmMain::FindFiles(const AnsiString& Directory, TStringList& FileSpecs, TStringList& List, bool IncludeSubdirectories)
{
  TSearchRec finfo;
  int done, count = 0;
  AnsiString filespec, dir, subdir, dirspec;

    //Make sure there is a trailing "/"
  dir = IncludeTrailingPathDelimiter(Directory);

    // Always search for all when looking for directories
  dirspec = dir + "*.*";

    // Get all files for each spec
  for (int i = 0; i < FileSpecs.Count; i++)
  {
      // Get the next filespec
    filespec = FileSpecs[i];
      // Find matching files
    count += CatalogFiles(dir, filespec, List);
  }

    // Always search for *.* when looking for directories
  if (IncludeSubdirectories)
  {
      // Find the first one that matches
    done = FindFirst(dirspec, faAnyFile, finfo);

      // While there are more files that match (and the user doesn't abort)
    while ((done == 0) && (!Abort))
    {
        // If it's a directory (not current or parent), traverse it
      if (((finfo.Attr & faDirectory) != 0) && (finfo.Name != ".") && (finfo.Name != ".."))
      {
        subdir = Format("%s%s", ARRAYOFCONST((dir, finfo.Name)));
        count += FindFiles(subdir, FileSpecs, List, IncludeSubdirectories);
      }

        // Update the UI (After every directory)
      if (grpUpdateFrequency->ItemIndex == 1)
        lblCount->Caption = IntToStr(lstFiles->Count);

      Application->ProcessMessages();

        // Next file
      done = FindNext(finfo);
    }
    FindClose(finfo);
  }
  return count;
}

void __fastcall TfrmMain::btnFindClick(TObject *Sender)
{
  TStringList *list = new TStringList();
  TStringList *filespecs = new TStringList();
  filespecs->Add(lstFileSpecs->Text);
  Abort = false;
  lstFiles->Clear();
  lblCount->Caption = "";

  lblTime->Caption = "Working...";
  barStatus->SimpleText = "Searching...";

  std::clock_t start = std::clock();
  
    if (chkUseUpdate->Checked)
      lstFiles->Items->BeginUpdate();

      int count = FindFiles(lstDirectory->Text, *filespecs, *list, chkIncludeSubdirectories->Checked);

    if (chkUseUpdate->Checked)
      lstFiles->Items->EndUpdate();

  std::clock_t end = std::clock();

  barStatus->SimpleText = "Done.";
  lblTime->Caption = Format("%d ms", ARRAYOFCONST((end - start)));

    // Update UI (After complete)
  lblCount->Caption = IntToStr(count);

  delete list;
  delete filespecs;
}
//---------------------------------------------------------------------------
void __fastcall TfrmMain::btnStopClick(TObject *Sender)
{
  Abort = true;
}
//---------------------------------------------------------------------------

/*
  When an item in the tree is double-clicked, open it with the appropriate
  application. See MSDN for more information on ShellExecute and associated
  functions, e.g. ShellExecuteEx, and the ShellAPI in shellapi.h.
*/
void __fastcall TfrmMain::lstFilesDblClick(TObject *Sender)
{
    // If something is double-clicked, it will be the selected item
  int index = lstFiles->ItemIndex;
  if (index == -1)
    return; // shouldn't happen

  AnsiString str = lstFiles->Items->Strings[index];
  ShellExecute(Handle, "open", str.c_str(), NULL, NULL, SW_SHOWNORMAL);
}
//---------------------------------------------------------------------------