/************************************************************************************
				    FindFile

			An AmigaDOS Release 2 Commodity

			Code By :	 Russell R. Steffen

			Home Address :	 11551 Sherman Rd.
					 Cedarburg WI, 53012
					 USA
					 ( Stable )

			Email Address  : STEFFENR@UWSTOUT.EDU
					 ( Valid ubtil May 1993 )

			School Address : 318 Callahan Hall
					 Menomonie, WI 54751
					 USA
					 ( Valid until May 1993 )


      Purpose -- To Emulate the FindFile Desk Accessory of the Macintosh.

      Legal   -- This code is copyrighted by the author. However permission is
		 granted for private use. Commercial use is prohibited without
		 written consent of the author. This program is distrbuted
		 WITHOUT ANY WARRANTY or IMPLIED WARRANTY of MERCHANTABILTY
		 or FITNESS FOR A PARTICULAR PURPOSE.


      CopyRight © 1992 -- Russell R. Steffen. All rights reserved.

      History
      -----------------------------------------------------------------------------
      29 JUN 1992 | File Creation, Inital Version
      -----------------------------------------------------------------------------
      26 JUL 1992 | Competetion of Inital Version 1.00
		  | Implemented ToolTypes : CX_POPKEY, CX_PRIORITY, CX_POPUP,
		  |			    DEF_PATTERN, CENTERWINDOW, IGNOREICONS
      -----------------------------------------------------------------------------
      30 JUL 1992 | Optimizations and cleanups. Added SORTLIST Tooltype
		  | Version 1.00a
      -----------------------------------------------------------------------------
      31 JUL 1992 | Added key command for found-list gadget. Version 1.00b
		  | Fixed bug in ScanDir(), wasn't honoring a user quit request
		  | properly.
      -----------------------------------------------------------------------------
      04 NOV 1992 | Fixed another bug in ScanDir() with a near total rewrite.
		  | Now works properly when launched from Workbench.
		  | Fixed Window opening routine to use WA_InnerWidth and
		  | and WA_InnerHeight. Window was a bit to small when the
		  | prefs screen font was larger than 8 point.
		  | Fixed problem with 'D' key, wasn't wraping around on
		  | the device list.
		  | Version 1.00c
      -----------------------------------------------------------------------------
      26 FEB 1993 | Porting Source into the RCS environment. Version numbers
		  | and history log will appear in that format from now
		  | on.
      -----------------------------------------------------------------------------

FindFile.c 1.14 1993/04/03 14:01:27 RUSS Exp

1.14

FindFile.c
 * Revision 1.14  1993/04/03  14:01:27  RUSS
 * Added INITIAL_DIR tooltype.
 *
 * Revision 1.13  1993/04/03  13:34:06	RUSS
 * Fixed crashing problem when starting a second FindFile.
 *
 * Revision 1.12  1993/04/03  02:02:24	RUSS
 * Changed Deg cyclegadget to string gadget,
 *   added file requester gadget.
 *
 * Revision 1.11  1993/04/01  22:11:33	RUSS
 * Added date to window title and CX description
 *
 * Revision 1.10  1993/04/01  21:47:17	RUSS
 * Major. Changed window format to single list
 * gagdet for found files. Changed default value
 * for CX_POPUP tooltype.
 *
 * Revision 1.9  1993/03/28  14:44:47  RUSS
 * Added sanity checking on memory allocs
 *
 * Revision 1.8  1993/02/28  00:59:03  RUSS
 * Removed DOS interface to FFSearch.c
 *
 * Revision 1.7  1993/02/28  00:39:57  RUSS
 * Changed controlpanel to use arrays of gadgetpointers
 *
 * Revision 1.6  1993/02/27  18:48:18  RUSS
 * Removed CX code, placed it into CX.c
 *
 * Revision 1.5  1993/02/27  17:20:42  RUSS
 * Window management exported to FFWindow.c
 *
 * Revision 1.4  1993/02/27  17:06:42  RUSS
 * Fixed internal version string
 *
 * Revision 1.3  1993/02/27  17:00:41  RUSS
 * Fixed window title
 *
 * Revision 1.2  1993/02/27  16:57:02  RUSS
 * Fixed Commodites Broker init string
 *
 * Revision 1.1  1993/02/27  15:48:24  RUSS
 * Initial revision
 *


**********************************************************************************/

#include "FindFile.h"

/***************************** Global Vars ***************************************/

struct Library *IntuitionBase;
struct Library *GadToolsBase;
struct Library *CxBase;
struct Library *IconBase;
struct Library *AslBase;

extern int Enable_Abort; /* needed to disable Aztec C's ^C checking */

static const UBYTE *verTag = "\0$VER: " NAME " 1.14 " __AMIGADATE__;
const UBYTE *windowTitle = NAME " 1.14 " __AMIGADATE__;
const UBYTE *cxTitle = NAME " 1.14 "__AMIGADATE__;

/** This TextAttr should be gone in a future release. I want to
    write the window code to be Prefs font sensitive, eventually :)  **/

struct TextAttr DefaultFont = {
  (UBYTE *)"topaz.font",
  8,
  FS_NORMAL,
  FPF_ROMFONT
};

/**************************** Code Starts Here ***********************************/

struct Process;
struct WBStartup;


void
main(int argc, char **argv)
{
  struct controlPanel *cp;

  Enable_Abort = 0; /* turn off auto CTRL-C handling */

  cp = AllocVec( sizeof( struct controlPanel ) , MEMF_PUBLIC | MEMF_CLEAR );

  if( !cp )
    Shutdown( cp, 20 );

  DB("Got controlpanel")

  Init( cp );

  DB("Initialized.")
  SetUp( cp , argc , argv );

  DB("Set up compete.");

  FOREVER
  {
    ULONG mask;

    mask = GetWaitMask( cp );

    DB("Waiting..")

    mask = Wait( mask );

    if( mask & SIGBREAKF_CTRL_C )
      CMD_Quit( cp );

    if( cp->ffWindow )
      if( mask & 1 << cp->ffWindow->UserPort->mp_SigBit )
	HandleFFWindowCommand( cp );

    if( cp->cxInterface.cxPort )
      if( mask & 1 << cp->cxInterface.cxPort->mp_SigBit )
	HandleCxCommand( cp );
  }

}

void
SetUp( struct controlPanel *cp, int argc, char **argv )
{
  UBYTE    **toolTypes;
  STRPTR     strTemp;
  BOOL	     openWindow=FALSE;



  /**** Parse WB & CLI Options ***************/

  toolTypes = ArgArrayInit( argc, argv );

  cp->cxInterface.cxPriority = ArgInt( toolTypes, "CX_PRIORITY", 0 );

  strTemp = ArgString( toolTypes, "CX_POPKEY", "LCommand help" );
  strncpy( cp->cxInterface.cxHotKeyString , strTemp, MAXSTR );

  strTemp = ArgString( toolTypes, "CX_POPUP", "YES" );
  if( ! strnicmp( strTemp, "YES" , MAXSTR ) )
    openWindow = TRUE;

  strTemp = ArgString( toolTypes, "DEF_PATTERN", "#?" );
  strncpy( cp->searchString , strTemp , MAXSTR );

  strTemp = ArgString( toolTypes, "CENTERWINDOW", "YES" );
  if( ! strnicmp( strTemp, "YES", MAXSTR ) )
    cp->centerWindow = TRUE;

  strTemp = ArgString( toolTypes, "IGNOREICONS" , "NO" );
  if( ! strnicmp( strTemp, "YES", MAXSTR ) )
  {
    cp->ignoreIcons = TRUE;
    ParsePatternNoCase( "#?.info" , cp->ignoreIconsPat, MAXPAT );
  }
  else
    ParsePatternNoCase( "#?" , cp->ignoreIconsPat, MAXPAT );

  strTemp = ArgString( toolTypes, "SORTLIST", "YES" );
  if( ! stricmp( strTemp, "YES" , MAXSTR ) )
    cp->sortList = TRUE;

  strTemp = ArgString( toolTypes, "INITIAL_DIR", "SYS:" );
  strncpy( cp->searchPath, strTemp, MAXSTR );

  ArgArrayDone();
  DB("Tooltypes parsed..")


  NewList( (struct List *)&(cp->foundList) );
  DB("Found list init")

  OpenCxInterface( cp );
  DB("CXInterface Open")

  cp->lastX = cp->lastY = -1L;


  if( openWindow )
    OpenFFWindow( cp );

  DB("Opened window (I.N.)")
}

void
Init( struct controlPanel *cp )
{

  if( ! ( IntuitionBase = OpenLibrary( "intuition.library", 37L ) ) )
      Shutdown( cp , 20 );

  if( ! ( GadToolsBase = OpenLibrary( "gadtools.library", 37L ) ) )
      Shutdown( cp , 20 );

  if( ! ( CxBase = OpenLibrary( "commodities.library" , 37L ) ) )
      Shutdown( cp , 20 );

  if( ! ( IconBase = OpenLibrary( "icon.library", 37L ) ) )
      Shutdown( cp , 20 );

  if( ! ( AslBase = OpenLibrary( "asl.library", 37L ) ) )
      Shutdown( cp, 20 );
}

ULONG
GetWaitMask( struct controlPanel *cp )
{
  ULONG mask;

  mask = SIGBREAKF_CTRL_C;

  if( cp->ffWindow )
    mask |= 1 << cp->ffWindow->UserPort->mp_SigBit;

  if( cp->cxInterface.cxPort )
    mask |= 1 << cp->cxInterface.cxPort->mp_SigBit;

  return( mask );
}


struct foundNode *
NodeAddress( struct MinList *fl , UWORD ord )
{
  struct foundNode *fn;

  fn = (struct foundNode *)fl->mlh_Head;

  while( ord-- )
  {
    fn = (struct foundNode *)fn->fn_Node.ln_Succ;
  }

  return( fn );
}

BOOL
QuitCheck( struct controlPanel *cp )
{
  struct IntuiMessage *msg;
  BOOL		       quit = FALSE;

  while(  msg = GT_GetIMsg( cp->ffWindow->UserPort ) )
  {
    struct Gadget *gad;
    ULONG	   class;
    UWORD	   code;

    gad = msg->IAddress;
    class = msg->Class;
    code  = msg->Code;

    GT_ReplyIMsg( msg );

    if( class == IDCMP_GADGETUP )
    {
      if( gad->GadgetID == ID_ABORT )
      {
	quit = TRUE;
      }
    }
    else
      if( class == IDCMP_VANILLAKEY )
      {
	if( code == 'a' || code == 'A' )
	{
	  quit = TRUE;
	}
      }
      else
	if( class == IDCMP_REFRESHWINDOW )
	{
	  GT_BeginRefresh(cp->ffWindow);
	  GT_EndRefresh(cp->ffWindow , TRUE);
	}

  }

  return( quit );

}

/*********************************************************************************/

/******************************** Custom List Mgmt *******************************/

struct foundNode *
AddFoundNode( struct MinList *list , STRPTR foundName , BOOL sort )
{
  struct foundNode *fn;
  struct Node	   *node,
		   *pred;

  fn = AllocVec( sizeof( struct foundNode ) , MEMF_ANY|MEMF_CLEAR );

  fn->fn_Node.ln_Name = fn->fn_Name;

  strcpy( fn->fn_Name , foundName );

  if( sort )
  {
    pred = NULL;

    for( node = (struct Node *)list->mlh_Head ; node->ln_Succ ; node = node->ln_Succ )
    {
      if( stricmp( node->ln_Name , foundName ) > 0 )
	break;
      pred = node;
    }

  }
  else
    pred = (struct Node *)&list->mlh_Tail;

  Insert( (struct List *)list, (struct Node *)fn, pred );

  return( fn );
}

void
DeleteFoundList( struct MinList *list )
{
  while( ! IsListEmpty( (struct List *)list ))
  {
    struct foundNode *fn;

    fn = (struct foundNode *)RemHead( (struct List *)list );
    FreeVec( fn );
  }
}

void
AddFoundFile( struct controlPanel *cp, BPTR dir, STRPTR file )
{
  struct foundNode *fn;
  UBYTE  fullName[MAXSTR];

  NameFromLock( dir, fullName, MAXSTR );

  AddPart( fullName, file, MAXSTR );

  fn = AddFoundNode(&cp->foundList, fullName, cp->sortList );
  if( !fn )
    Shutdown( cp, 20 );

  ++(cp->numFound);
}

/***************  Command functions start here *****************************/

void
CMD_Show( struct controlPanel *cp )
{
  OpenFFWindow( cp );
}

void
CMD_Hide( struct controlPanel *cp )
{
  CloseFFWindow( cp );
}

void
CMD_Search( struct controlPanel *cp )
{

  GT_SetGadgetAttrs( cp->ffWinGads[ID_PATGAD],
		     cp->ffWindow, NULL,
		     GA_Disabled,  TRUE,
		     TAG_END );

  GT_SetGadgetAttrs( cp->ffWinGads[ID_DEVGAD],
		     cp->ffWindow, NULL,
		     GA_Disabled,  TRUE,
		     TAG_END );

  GT_SetGadgetAttrs( cp->ffWinGads[ID_FILEREQ],
		     cp->ffWindow, NULL,
		     GA_Disabled,  TRUE,
		     TAG_END );

  GT_SetGadgetAttrs( cp->ffWinGads[ID_SEARCH],
		     cp->ffWindow, NULL,
		     GA_Disabled,  TRUE,
		     TAG_END );

  GT_SetGadgetAttrs( cp->ffWinGads[ID_HIDE],
		     cp->ffWindow, NULL,
		     GA_Disabled,  TRUE,
		     TAG_END );

  GT_SetGadgetAttrs( cp->ffWinGads[ID_QUIT],
		     cp->ffWindow, NULL,
		     GA_Disabled,  TRUE,
		     TAG_END );

  GT_SetGadgetAttrs( cp->ffWinGads[ID_ABORT],
		     cp->ffWindow, NULL,
		     GA_Disabled,  FALSE,
		     TAG_END );

  GT_SetGadgetAttrs( cp->ffWinGads[ID_FOUNDLIST],
		     cp->ffWindow, NULL,
		     GTLV_Labels,  NULL,
		     TAG_END );

  DeleteFoundList( &cp->foundList );

  cp->numFound = 0;
  cp->currFound = ~0;

  if( ParsePatternNoCase( cp->searchString , cp->searchPattern , MAXPAT ) == -1 )
    return;

  ScanDir( cp->searchPath, cp );

  GT_SetGadgetAttrs( cp->ffWinGads[ID_FOUNDLIST],
		     cp->ffWindow, NULL,
		     GTLV_Labels,  (&cp->foundList),
		     GTLV_Selected, ~0L,
		     TAG_DONE );

  GT_SetGadgetAttrs( cp->ffWinGads[ID_PATGAD],
		     cp->ffWindow, NULL,
		     GA_Disabled,  FALSE,
		     TAG_END );

  GT_SetGadgetAttrs( cp->ffWinGads[ID_DEVGAD],
		     cp->ffWindow, NULL,
		     GA_Disabled,  FALSE,
		     TAG_END );

  GT_SetGadgetAttrs( cp->ffWinGads[ID_FILEREQ],
		     cp->ffWindow, NULL,
		     GA_Disabled,  FALSE,
		     TAG_END );

  GT_SetGadgetAttrs( cp->ffWinGads[ID_SEARCH],
		     cp->ffWindow, NULL,
		     GA_Disabled,  FALSE,
		     TAG_END );

  GT_SetGadgetAttrs( cp->ffWinGads[ID_HIDE],
		     cp->ffWindow, NULL,
		     GA_Disabled,  FALSE,
		     TAG_END );

  GT_SetGadgetAttrs( cp->ffWinGads[ID_QUIT],
		     cp->ffWindow, NULL,
		     GA_Disabled,  FALSE,
		     TAG_END );

  GT_SetGadgetAttrs( cp->ffWinGads[ID_ABORT],
		     cp->ffWindow, NULL,
		     GA_Disabled,  TRUE,
		     TAG_END );

}

void
CMD_Quit( struct controlPanel *cp )
{
  Shutdown( cp , 0 );
}

/**********************************************************************************/

/***************  Comprehensive Shutdown Code *************************************/
void
Shutdown( struct controlPanel *cp , int retCode )
{

  if( cp )
  {

    /*************************** Close Cx port and interface ************************/

    DB("Stage 1")
    if( cp->cxInterface.cxPort )
    {
      DB("Closing CX Interface")
      CloseCxInterface( cp );
    }

    /*************************** Get Rid of Window and Related GadTools Stuff *******/

    DB("Stage 2")
    if( cp->ffWindow )
    {
      CloseFFWindow( cp );
      cp->ffWindow = NULL;
    }

    DB("Stage 3")
    if( cp->ffWinGadList )
    {
      FreeGadgets( cp->ffWinGadList );
      cp->ffWinGadList = NULL;
    }

    DB("Stage 4")
    if( cp->ffWinVi );
    {
      FreeVisualInfo( cp->ffWinVi );
      cp->ffWinGadList = NULL;
    }

    DB("Stage 5")
    DeleteFoundList( &cp->foundList );

    DB("Stage 5a")
    FreeVec( cp );

  }
  /******************************* Close Libraries & exit ************************/

  DB("Stage 6")
  if( IntuitionBase )
    CloseLibrary( IntuitionBase );

  if( GadToolsBase )
    CloseLibrary( GadToolsBase );

  if( IconBase )
    CloseLibrary( IconBase );

  if( CxBase )
    CloseLibrary( CxBase );

  if( AslBase )
    CloseLibrary( AslBase );

  exit( retCode );

}
/********************************************************************************/

