// $VER: FindFile.c -- AmigaDOS V1 (17.3.95); ©CM 95 
// komplettes FindFile mit EasyObjects, startbar von WB und Shell
// Shell-Syntax: FindFile [Pattern] [Strt-Dir]

#include <dos/dos.h>
#include <dos/dosextens.h>
#include <classes/dos/arguments.h>
#include <classes/dos/files.h>
#include <classes/libraries/gadtools.h>
#include <classes/intuition/screen.h>
#include <classes/intuition/gadgets.h>
#include <classes/layouter/windows.h>
#include <classes/layouter/boopsigadgets.h>
#include <classes/layouter/decorgadgets.h>
#include <classes/exec/libraries.h>
#include <stream.h>
#include <time.h>
#include <wbstartup.h>
#include "DirTree.h"

// Hier folgt erstmal die FindFile-Klasse unter DOS
   
class FindFileDOS : public DirTree  {
   BOOL dirout; 
   int dircnt, filecnt;
public:
   FindFileDOS(char*dir, char*pat) : DirTree(dir, pat),
      dirout(FALSE), dircnt(0), filecnt(0)  {}
   void Error(const char*error) {
      cout << "Fehler: "<< error << "\n";
   }
   void FileFound(const ExAllData*ead) { // Namen ausgeben
      if(dirout) { cout << "\n"; dirout=0;   } // nur zur
      cout<<" fnd: "<<(char*)(ead->ed_Name)<<'\n'; // Formatierung
      filecnt++;
   }
   void DirChanged(const char*dir) {
      cout<<dir<<"\x9b\x4b\r";
      dirout=1;   // zur richtigen Formatierung
      dircnt++;   // für die Statistik
   }

   void Finish() { 
      if(dirout) { cout << "\x9b\x4b"; }
      cout << "\nVerzeichnisse:    "<<dircnt<<"\n"
                "Dateien gefunden: "<<filecnt<<"\n";
   }
};

// der Rest bezieht sich auf die GUI-Version

class FindFileGUI;
class FFGUIWindow;

// Event-Handler

class startEventC : public GadgetEventC {
public:
   startEventC() : GadgetEventC(), _exit(FALSE) { };
   VOID up(WindowC *, GadgetC *, IntuiMessageC *);
   VOID down(WindowC *, GadgetC *, IntuiMessageC *);
   VOID keyUp(WindowC *, GadgetC *, IntuiMessageC *);
   BOOL exit() { return _exit; };
protected:
   BOOL _exit;
};

class exitEventC : public GadgetEventC {
public:
   exitEventC() : GadgetEventC(), _exit(FALSE) { };
   VOID up(WindowC *, GadgetC *, IntuiMessageC * );
   VOID down(WindowC *, GadgetC *, IntuiMessageC *);
   VOID keyUp(WindowC *, GadgetC *, IntuiMessageC *);
   BOOL exit() { return _exit; };
protected:
   BOOL _exit;
};

class SelectWindowCloseC : public WindowCloseHandlerC {
public:
   SelectWindowCloseC(class FFGUIWindow &);
   VOID close();
private:
   class FFGUIWindow &ffwin;
};

// Hauptfenster

class FFGUIWindow : public StandardWindowC {
   LBStringC   STpattern;        GeometryC      GESTpattern;
   LBStringC   STpath;           GeometryC      GESTpath;
   LBListviewC LVfoundfiles;     GeometryC      GELVfoundfiles;
                        TransparentGroupLayoutC TGcontrolbuttons;
                                 GeometryGroupC GGcontrolbuttons;
   LBIButtonC  BUstart;          GeometryC      GEBUstart;
   LBIButtonC  BUexit;           GeometryC      GEBUexit;
   EListC *LSfoundfiles;
   GadgetKeyHandlerC GKEhandler;
   LBTextC TXremark;             GeometryC      GETXremark;               

   FindFileGUI *ffg;
   startEventC EVstart;
   exitEventC  EVexit;
   EListC filelist;
   BOOL started, stopped, exited;
   SelectWindowCloseC swc;
   friend class FindFileGUI;
   char *dir;
public:
   FFGUIWindow(GTIDCMPortC&, ScreenC&);
   ~FFGUIWindow();
   BOOL start(), exit();
   void SetRemark(char*);  
};

class FindFileGUI : public DirTree  {
   int dircnt, filecnt; // Statistik
   FFGUIWindow &ffwin;  // zur Bildschirmausgabe (friend)
   PathStringC path;    // zur Ausgabe
   time_t stime;        // Statistik
public:
   FindFileGUI(char*dir, char*pat, FFGUIWindow&w) : 
      DirTree(dir, pat),
              dircnt(0), filecnt(0), ffwin(w), path(256)  {}
   void Error(const char*error);
   void Init();
   void FileFound(const ExAllData*ead);
   void DirChanged(const char*dir);
   void Finish();
};

// Window-Routinen

FFGUIWindow::FFGUIWindow(GTIDCMPortC&g, ScreenC&s) : 
   StandardWindowC(g,s, &BUstart, 
      WA_MaxWidth, ~0,           WA_MaxHeight, ~0, 
      WA_Width, 640,             WA_Height, 200, 
      WA_SizeBBottom, FALSE,     WA_SizeBRight, TRUE, 
      WA_Title, "FindFile 1.0 - © Clemens Marschner 1995", 
      WA_Activate, TRUE, TAG_END), 
   filelist(),
   STpattern(NULL, *this,LAYOUT_AUTOSIZE,LAYOUT_AUTOSIZE, 
                        GA_Text, "Pattern:", 
                        STRINGA_MaxChars, 256,
                        STRINGA_ActivePens, ((3 << 16) | 1), 
                        GA_TabCycle, TRUE, TAG_END),           
   STpath(NULL, *this, LAYOUT_AUTOSIZE, LAYOUT_AUTOSIZE,
                        GA_Text, "   Pfad:",
                        STRINGA_MaxChars, 256, 
                        STRINGA_ActivePens, ((3 << 16) | 1), 
                        GA_TabCycle, TRUE, TAG_END),
   LVfoundfiles(NULL, *this, LAYOUT_AUTOSIZE, LAYOUT_AUTOSIZE,
                        LVA_VertScroller, TRUE,
                        LVA_HorizScroller, TRUE, TAG_END),
   TGcontrolbuttons(),
   EVstart(), 
   BUstart(&EVstart, *this, LAYOUT_AUTOSIZE,  LAYOUT_AUTOSIZE,
                        GA_Text, "_Start", 
                        GA_RelVerify,TRUE,   TAG_END),
   EVexit(), 
   BUexit(&EVexit, *this, LAYOUT_AUTOSIZE, LAYOUT_AUTOSIZE,
                        GA_Text, "_Beenden", 
                        GA_RelVerify,TRUE,   TAG_END),
   TXremark(NULL, *this, LAYOUT_AUTOSIZE, LAYOUT_AUTOSIZE,
               TAG_END),
   GESTpattern(STpattern, 
      LAYOUT_GROUP,  0,3,                 LAYOUT_SIZE, 0, 0,
      LAYOUT_GROUP,  0,4,                 LAYOUT_GROUP, 0, -4),
   GESTpath(STpath, 
      LAYOUT_OPPBORDER, &GESTpattern, 3,  LAYOUT_SIZE, 0, 0,
      LAYOUT_GROUP,  0,4,                 LAYOUT_GROUP, 0,-4),
   GELVfoundfiles(LVfoundfiles, 
      LAYOUT_OPPBORDER, &GESTpath, 4,     
      LAYOUT_OPPBORDER, &GGcontrolbuttons, -4,
      LAYOUT_GROUP,  0,0,                 LAYOUT_GROUP, 0,0),
   GGcontrolbuttons(TGcontrolbuttons, 
      LAYOUT_SIZE,   0,4,      LAYOUT_OPPBORDER, &GETXremark,-4,
      LAYOUT_GROUP,  0,0,                 LAYOUT_GROUP, 0,0),
   GEBUstart(BUstart, 
      LAYOUT_SIZE,   0,0,                 LAYOUT_GROUP, 0, 0, 
      LAYOUT_PROCENTCENTER, 0, 33,        LAYOUT_MAXSIZE, 0, 0),
   GEBUexit(BUexit, 
      LAYOUT_SIZE,   0,0,                 LAYOUT_GROUP, 0,0,   
      LAYOUT_PROCENTCENTER, 0, 66,        LAYOUT_MAXSIZE, 0,0),
   GETXremark(TXremark, 
      LAYOUT_SIZE,   0,0,                 LAYOUT_GROUP, 0,0,
      LAYOUT_GROUP,  0,0,                 LAYOUT_GROUP, 0,0) ,
   swc(*this), started(FALSE), stopped(FALSE), GKEhandler(*this)
{
      dir = new char[256];
      gadgets.add(STpattern); // Gadgets in die Hauptliste
      gadgets.add(STpath);      gadgets.add(LVfoundfiles);
      gadgets.add(BUstart);     gadgets.add(BUexit);
      gadgets.add(TXremark);
      innerGeo.add(GESTpattern);    // Geometrien in die Liste
      innerGeo.add(GESTpath);   innerGeo.add(GELVfoundfiles);
      innerGeo.add(GETXremark);
      innerGeo.add(GGcontrolbuttons);  // das ist eine Gruppe...
      GGcontrolbuttons.add(GEBUstart); // in die ebenfalls Gad-
      GGcontrolbuttons.add(GEBUexit);  // gets eingehängt werden

      LVfoundfiles.setList(&filelist);       // Liste für Listview
      GKEhandler.add("rcommand s", BUstart); // Tastatur-Shortcut
      GKEhandler.add("rcommand b", BUexit);  
}

FFGUIWindow::~FFGUIWindow()
{  close();  delete dir; }

BOOL FFGUIWindow::start() {
   if(!started) { // Nur beginnen, falls noch nicht gestartet:
      started=TRUE;   stopped=FALSE;
      char *path    = STpath.get();       // Strings einlesen
      char *pattern = STpattern.get(); //
      LVfoundfiles.detachList();         // Liste leeren
      while (!filelist.isEmpty())
      {  delete filelist.remTail();  }
      LVfoundfiles.attachList();
      FindFileGUI ffg(path, pattern, *this); // Klasse init.
      ffg.ReadRecursively();                 // und benutzen
   }
   return FALSE;
}
   
BOOL FFGUIWindow::exit()
{  stopped = TRUE; return TRUE; }

void FFGUIWindow::SetRemark(char*rem)
{   TXremark.set(rem); }

void FindFileGUI::Init()
{  ffwin.LVfoundfiles.detachList(); stime = time(0); }

void FindFileGUI::Error(const char*error)
{   ffwin.SetRemark((char*)error); }

void FindFileGUI::FileFound(const ExAllData*ead) {
   ENodeC *node = new ENodeC();
   char *file = new char[128];
   char date[LEN_DATSTRING],time[LEN_DATSTRING],prot[8]; 
   struct DateTime dt = {
         ead->ed_Days,ead->ed_Mins,ead->ed_Ticks,
         FORMAT_DOS, 0, NULL, date, time
   };
   path.addPart(ead->ed_Name); // pathstringc
   DateToStr(&dt);
   prot[7]='\0';
   prot[0]= ead->ed_Prot & FIBF_SCRIPT       ? 's' : '-';
   prot[1]= ead->ed_Prot & FIBF_PURE         ? 'p' : '-';
   prot[2]= ead->ed_Prot & FIBF_ARCHIVE      ? 'a' : '-';
   prot[3]= (!(ead->ed_Prot & FIBF_READ))    ? 'r' : '-';
   prot[4]= (!(ead->ed_Prot & FIBF_WRITE))   ? 'w' : '-';
   prot[5]= (!(ead->ed_Prot & FIBF_EXECUTE)) ? 'e' : '-';
   prot[6]= (!(ead->ed_Prot & FIBF_DELETE))  ? 'd' : '-';
   sprintf(file, "%9s %9s %7s %10d %-32s", date, time, prot,
                 ead->ed_Size,path.path());
   // höchstens 70 Zeichen
   node->setName(file); 
   // und ausgeben
   ffwin.filelist.addTail(*node);
   filecnt++;
   path.cutBehindPathPart(); 
   if(ffwin.stopped) running=FALSE;
}

void FindFileGUI::DirChanged(const char*dir) {
   path.setPath((char*)dir);
   ffwin.SetRemark((char*)dir);
   if(ffwin.idcmPort().forMe(0)) 
      (ffwin.idcmPort()).handle(0);
   if(ffwin.stopped) running = FALSE;
   dircnt++;
}

void FindFileGUI::Finish() {
   char buf[128];
   time_t etime = time(0);
   sprintf(buf, "Verzeichnisse: %d; Gefundene Dateien: %d; "
    "Zeit: %d s", dircnt, filecnt, (int)difftime(etime, stime));
   ffwin.SetRemark(buf);
   ffwin.LVfoundfiles.attachList();
   ffwin.started=FALSE;
}
 
// Event-Routinen

VOID startEventC::up(WindowC *w, GadgetC *, IntuiMessageC *)
{   _exit = ((FFGUIWindow*)w)->start(); }

VOID startEventC::down(WindowC *w, GadgetC *g, IntuiMessageC *i)
{   up(w,g,i); }

VOID startEventC::keyUp(WindowC *w, GadgetC *g, IntuiMessageC *i)
{   up(w,g,i); }

VOID exitEventC::up(WindowC *w, GadgetC *, IntuiMessageC *)
{   _exit = ((FFGUIWindow*)w)->exit(); }

VOID exitEventC::down(WindowC *w, GadgetC *g, IntuiMessageC *i)
{   up(w,g,i); }

VOID exitEventC::keyUp(WindowC *w, GadgetC *g, IntuiMessageC *i)
{   up(w,g,i); }

SelectWindowCloseC::SelectWindowCloseC(class FFGUIWindow &f) :
   ffwin(f), WindowCloseHandlerC(f) {}
VOID SelectWindowCloseC::close() { _exit = ffwin.exit(); }

// Hauptprogramm

LibraryBaseErrC IntuitionBase ("intuition.library",   37l);
LibraryBaseErrC UtilityBase   ("utility.library",     37l);
LibraryBaseErrC GadToolsBase  ("gadtools.library",    37l);
LibraryBaseErrC CxBase        ("commodities.library", 37l);
LibraryBaseErrC WorkbenchBase ("workbench.library",   37l);
LibraryBaseErrC LayersBase    ("layers.library",      37l);

void main()  {
   PutStr("FindFile 1.0 - © C. Marschner 1995\n\n");
   try {
      ArgsC ac("PATTERN,DIRECTORY");
      char *pat = ac.getStr("PATTERN", "");
      char *dir = ac.getStr("DIRECTORY", "");
      if(pat[0] == 0 || _wbflag == TRUE) {
         // hier folgt die standardmäßig vorgesehene Behandlung
            SignalsC sc;
            GTIDCMPortC gtport;
            sc.add(gtport);
            CtrlCHandlerC ctrlchandler;
            sc.add(ctrlchandler);
            GadgetUpHandlerC gtuphandler;
            gtport.add(gtuphandler);
            PublicScreenC screen();
            screen.lock(NULL);
            FFGUIWindow win(gtport, screen); 
            win.open();
            sc.loop();
      } else {    
         FindFileDOS(dir, pat).ReadRecursively();
      }
   } catch(...) {
      cout << "Fehler aufgetreten\n";
   }
}
