/*-- AutoRev header do NOT edit!
*
*   Program         :   Fass.c
*   Copyright       :   © Copyright 1991 Jaba Development
*   Author          :   Jan van den Baard
*   Creation Date   :   08-Sep-91
*   Current version :   1.01
*   Translator      :   DICE v2.6
*
*   REVISION HISTORY
*
*   Date          Version         Comment
*   ---------     -------         ------------------------------------------
*   17-Oct-91     1.02            FileRequester path selection added.
*   21-Sep-91     1.01            Now uses the Dos ReadArgs for the Shell.
*   08-Sep-91     1.00            Font directory assignment commodity.
*   08-Sep-91     1.00            Based on code by Stefan Sticht. (thanks!)
*
*-- REV_END --*/

/*
 * --- Include a whole buch of headers...
 */
#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <libraries/commodities.h>
#include <libraries/gadtools.h>
#include <libraries/asl.h>
#include <intuition/intuition.h>
#include <workbench/startup.h>
#ifndef abs
#define abs
#endif
#include <stdlib.h>
#include <string.h>
#include <clib/alib_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/commodities_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/asl_protos.h>
#include <clib/intuition_protos.h>
#include <clib/utility_protos.h>

/*
 * --- Macro's to (de)activate the commodity
 */
#define CxOn(b)       ActivateCxObj(b,TRUE);
#define CxOff(b)      ActivateCxObj(b,FALSE);

/*
 * --- Calculate a bit-mask from a signal bit.
 */
#define BitMask(b)    ( 1L << ((ULONG)b) )

/*
 * --- Parameters and defaults.
 */
UBYTE *COM_PRIORITY  =  "PRIORITY";      /* PRIORITY=<pri>     */
UBYTE *COM_POPWINDOW =  "POPWINDOW";     /* POPWINDOW=<YES|NO> */
UBYTE *COM_POPKEY    =  "POPKEY";        /* POPKEY=<hotkey>    */
UBYTE *COM_QUIT      =  "QUIT";          /* QUIT=<hotkey>      */

WORD   COM_DEF_PRI   =  0;               /* default priority   */
UBYTE *COM_DEF_KEY   =  "lalt f";        /* default hotkey     */
UBYTE *COM_DEF_POP   =  "NO";            /* default popwindow  */
UBYTE *COM_DEF_QUI   =  "lalt q";        /* default quit       */

#define COM_KEYHOT      1L              /* event ID           */
#define COM_QUITIT      2L              /* event ID           */

/*
 * --- Commodity information
 */
#define FASS_VERSION    "v1.02"
#define FASS_NAME       "Fass"
#define FASS_DESCR      "Font assignment commodity."
#define FASS_COPY       "© 1991 Jaba Development"
#define FASS_TITLE      FASS_NAME " " FASS_VERSION ", " FASS_COPY

/*
 * --- Minimum library version required
 */
#define MIN_LIB         36L

/*
 * --- Non autoinit libraries required
 */
struct CxBase           *CxBase     = NULL;
struct IconBase         *IconBase   = NULL;

extern struct WBStartup *_WBMsg;

/*
 * --- Autoinit libraries required
 */
extern struct IntuitionBase *IntuitionBase;
extern struct UtilityBase   *UtilityBase;
extern struct GadToolsBase  *GadToolsBase;

struct MsgPort          *FASS_port  = NULL;    /* Commodity MsgPort */
char                   **FASS_tool  = NULL;    /* ToolType array    */
struct RDArgs           *FASS_args  = NULL;    /* Shell args        */
struct RDArgs            FASS_iargs = { 0,0,0,0,0,0,0,RDAF_NOPROMPT };

ULONG                    FASS_arg[4];

UBYTE                   *FASS_temp  = "PRIORITY/n,POPWINDOW/k,POPKEY/k,QUIT/k";

struct Screen           *FASS_plock = NULL;
struct Window           *FASS_wnd   = NULL;
struct Gadget           *FASS_glist = NULL;
struct MsgPort          *FASS_idprt = NULL;

struct Gadget           *Path, *Ass, *Hide, *Quit, *Get;

APTR                     FASS_vinfo = NULL;
ULONG                    FASS_idmsk = NULL;
UWORD                    FASS_open  = FALSE;

CxObj                   *FASS_brok  = NULL;    /* The broker        */
CxObj                   *FASS_hkey;            /* The hotkey filter */
CxObj                   *FASS_quit;            /* The quit filter   */

/*
 * --- The broker data
 */
struct NewBroker         FASS_nbrok = {
    NB_VERSION,FASS_NAME,FASS_TITLE,FASS_DESCR,
    NBU_NOTIFY|NBU_UNIQUE,COF_SHOW_HIDE,NULL,0
};

ULONG                    FASS_smask = NULL;    /* MsgPort signal mask */
UBYTE                    FASS_dop   = FALSE;   /* Window on startup ? */
UBYTE                   *FASS_keys;            /* HotKey string       */
UBYTE                   *FASS_qt;              /* Quit string         */

/*
 * --- Identification string for the Version CLI-command
 */
UBYTE                   *FASS_ver = "$VER: Fass © 1991 Jaba Development -- v1.02";

/*
 * --- The window data
 */
struct TagItem WindowTags[] = {
    WA_Left,        10,
    WA_Top,         15,
    WA_InnerWidth,  250,
    WA_InnerHeight, 47,
    WA_AutoAdjust,  TRUE,
    WA_IDCMP,       IDCMP_GADGETUP | IDCMP_CLOSEWINDOW | IDCMP_REFRESHWINDOW,
    WA_Flags,       WFLG_DRAGBAR | WFLG_CLOSEGADGET | WFLG_ACTIVATE | WFLG_SMART_REFRESH | WFLG_RMBTRAP | WFLG_GIMMEZEROZERO,
    WA_PubScreen,   0,
    WA_Gadgets,     0,
    TAG_DONE };

UBYTE               FASS_title[40];
UBYTE               FASS_def[256];

/*
 * --- The ASL FileRequester data.
 */
struct TagItem FReqTags[] = {
    ASL_Hail,       "Select FONTS: path...",
    ASL_Dir,        FASS_def,
    ASL_ExtFlags1,  FIL1F_NOFILES,
    TAG_DONE };

/*
 * --- Use topaz 80 for now
 */
struct TextAttr TOPAZ_80 = {
    (STRPTR)"topaz.font",TOPAZ_EIGHTY,FS_NORMAL,FPF_ROMFONT };

/*
 * --- EasyStruct for Say
 */
struct EasyStruct   FASS_say = {
    sizeof(struct EasyStruct),NULL,"Fass message...",0,"OK" };

/*
 * --- Program function proto-types
 */
void    CloseFASS( long );
void    OpenFASS( void );
void    CheckFASS( void );
void    OpenFWin( void );
void    CloseFWin( void );
void    Say( char * );
void    CreateFONTS( long );
void    GetPath( void );

/*
 * --- Open up and allocate the resources required
 */
void OpenFASS( void )
{
    UBYTE       *popup;
    WORD         pri;

   /*
    * --- Open up non autoinit libraries
    */
    if ( NOT( IconBase = (struct IconBase *)OpenLibrary( "icon.library", MIN_LIB )))
        CloseFASS( 20L );
    if ( NOT( CxBase = (struct CxBase *)OpenLibrary( "commodities.library", MIN_LIB )))
        CloseFASS( 20L );

    if ( _WBMsg ) {
       /*
        * --- Initialize the ToolTypes array
        */
        FASS_tool = (char **)ArgArrayInit( 0L, (char **)_WBMsg );

        pri       = ArgInt( FASS_tool, COM_PRIORITY, COM_DEF_PRI );
        popup     = ArgString( FASS_tool, COM_POPWINDOW, COM_DEF_POP );
        FASS_keys = ArgString( FASS_tool, COM_POPKEY, COM_DEF_KEY );
        FASS_qt   = ArgString( FASS_tool, COM_QUIT, COM_DEF_QUI );
    } else {
        if ( FASS_arg[0] )  pri       = (WORD)FASS_arg[0];
        else                pri       = COM_DEF_PRI;
        if ( FASS_arg[1] )  popup     = (UBYTE *)FASS_arg[1];
        else                popup     = COM_DEF_POP;
        if ( FASS_arg[2] )  FASS_keys = (UBYTE *)FASS_arg[2];
        else                FASS_keys = COM_DEF_KEY;
        if ( FASS_arg[3] )  FASS_qt   = (UBYTE *)FASS_arg[3];
        else                FASS_qt   = COM_DEF_QUI;
    }

   /*
    * --- Set broker priority
    */
    FASS_nbrok.nb_Pri = pri;

   /*
    * --- Check if window should be opened uppon startup
    */
    if ( NOT Stricmp( popup, "YES"))
        FASS_dop = TRUE;

   /*
    * --- Create a MsgPort
    */
    if ( NOT( FASS_port = CreateMsgPort()))
        CloseFASS( 21L );

   /*
    * --- Get the port signalmask and set the port in the broker
    */
    FASS_smask         = BitMask( FASS_port->mp_SigBit );
    FASS_nbrok.nb_Port = FASS_port;

   /*
    * --- Setup the broker
    */
    if ( NOT( FASS_brok = CxBroker( &FASS_nbrok, NULL )))
        CloseFASS( 22L );

   /*
    * --- Setup the HotKey filters and attach them to the broker
    */
    if ( NOT( FASS_hkey = HotKey( FASS_keys, FASS_port, COM_KEYHOT )))
        CloseFASS( 23L );
    AttachCxObj( FASS_brok, FASS_hkey );
    if ( NOT( FASS_quit = HotKey( FASS_qt, FASS_port, COM_QUITIT )))
        CloseFASS( 23L );
    AttachCxObj( FASS_brok, FASS_quit );

   /*
    * --- Check for occured errors
    */
    if (CxObjError( FASS_hkey ) || CxObjError( FASS_quit ))
        CloseFASS( 24L );

   /*
    * --- Activate the broker
    */
    CxOn( FASS_brok );

   /*
    * --- Get the default FONTS path name
    */
    CreateFONTS( 2L );
}

/*
 * --- Close up and de-allocate the used resources
 */
void CloseFASS( long code )
{
    struct Message  *tmp; /* to clear the MsgPort */

   /*
    * --- Delete the broker
    */
    if ( FASS_brok )        DeleteCxObjAll( FASS_brok );

   /*
    * --- Clear and delete the MsgPort
    */
    if ( FASS_port ) {
        while (( tmp = GetMsg( FASS_port ))) ReplyMsg( tmp );
        DeleteMsgPort( FASS_port );
    }

   /*
    * --- If Workbench clear ArgArray else free Dos args
    */
    if ( _WBMsg )
        ArgArrayDone();
    else if ( FASS_args )
        FreeArgs( FASS_args );

   /*
    * --- Close the non autoinit libraries
    */
    if ( CxBase )           CloseLibrary( CxBase );
    if ( IconBase )         CloseLibrary( IconBase );

   /*
    * --- bye bye
    */
    exit( code );
}

/*
 * --- Process the messages coming through the MsgPort
 */
void CheckFASS( void )
{
    struct Message      *msg;
    struct IntuiMessage *imsg;
    ULONG                sig, type, id, class;
    BOOL                 running = TRUE;
    APTR                 obj;

    if ( FASS_dop )
        OpenFWin();

    do {
        sig = Wait( SIGBREAKF_CTRL_C | FASS_smask | FASS_idmsk );

        if (( sig & SIGBREAKF_CTRL_C ) == SIGBREAKF_CTRL_C ) {
           /*
            * --- Break signal received. Shutting down...
            */
            running = FALSE;
        } else if (( sig & FASS_smask) == FASS_smask ) {
           /*
            * --- Got a message on the MsgPort. Examine it
            */
            while (( msg = (struct Message *)GetMsg( FASS_port ))) {

               /*
                * Get the message type and id
                */
                id   = CxMsgID((CxMsg *)msg);
                type = CxMsgType((CxMsg *)msg);
                ReplyMsg(msg);

                switch( type ) {

                    case    CXM_IEVENT:

                        switch( id ) {

                            case    COM_KEYHOT:
                               /*
                                * --- They called us...
                                */
                                OpenFWin();
                                break;

                            case    COM_QUITIT:
                               /*
                                * --- bye bye
                                */
                                running = FALSE;
                                break;
                        }
                        break;

                    case    CXM_COMMAND:
                       /*
                        * --- They want us to do something...
                        */
                        switch( id ) {

                            case    CXCMD_KILL:
                               /*
                                * --- They want us dead....
                                */
                                running = FALSE;
                                break;

                            case    CXCMD_DISABLE:
                               /*
                                * --- They want us disabled...
                                */
                                CxOff( FASS_brok );
                                break;

                            case    CXCMD_ENABLE:
                               /*
                                * --- They want us enabled...
                                */
                                CxOn( FASS_brok );
                                break;

                            case    CXCMD_UNIQUE:
                               /*
                                * --- They tried to run a commodity
                                * --- using our name.
                                */
                            case    CXCMD_APPEAR:
                               /*
                                * --- They want us to open our window...
                                */
                                OpenFWin();
                                break;
                            case    CXCMD_DISAPPEAR:
                               /*
                                * --- They want us to close our window...
                                */
                                CloseFWin();
                                break;
                        }
                        break;
                }
            }
        } else if ( FASS_open ) {
            if(( sig & FASS_idmsk ) == FASS_idmsk ) {
               /*
                * --- Aha... A window message
                */
                while(( imsg = GT_GetIMsg( FASS_idprt ))) {

                   /*
                    * --- Get the message class and object
                    */
                    class = imsg->Class;
                    obj   = imsg->IAddress;
                    GT_ReplyIMsg(imsg );

                    switch( class ) {

                        case IDCMP_REFRESHWINDOW:
                           /*
                            * --- They say it must be done....
                            */
                            GT_BeginRefresh( FASS_wnd );
                            GT_EndRefresh( FASS_wnd, TRUE );
                            break;

                        case IDCMP_CLOSEWINDOW:
                           /*
                            * --- They want the window closed (HIDE)
                            */
                            CloseFWin();
                            break;

                        case IDCMP_GADGETUP:
                           /*
                            * --- They have pressed a gadget
                            */
                            if ( obj == (APTR)Path ) {
                               /*
                                * --- Check you input
                                */
                                CreateFONTS( FALSE );
                                break;
                            } else if ( obj == (APTR)Ass ) {
                               /*
                                * --- Assign your new path
                                */
                                CreateFONTS( TRUE );
                                break;
                            } else if ( obj == (APTR)Hide ) {
                               /*
                                * --- Hide our window
                                */
                                CloseFWin();
                                break;
                            } else if ( obj == (APTR)Quit ) {
                               /*
                                * --- bye bye
                                */
                                running = FALSE;
                                break;
                            } else if ( obj == (APTR)Get ) {
                               /*
                                * --- Get the path using the FileRequester.
                                */
                                GetPath();
                                break;
                            }
                            break;
                    }
                    break;
                }
            }
        }
    } while( running == TRUE );

   /*
    * --- The end, Fin, Einde, Finito....
    */
    CloseFWin();
    CxOff( FASS_brok );
}

/*
 * --- Open up the FASS window
 */
void OpenFWin( void )
{
    struct NewGadget    ng;
    struct Gadget      *gadget, *f;

    if ( NOT FASS_open ) {
       /*
        * --- Lock the default public screen
        */
        if ( NOT( FASS_plock = LockPubScreen( NULL )))
            return;

       /*
        * --- Get us the screen it's visual info (for gadtools)
        */
        if ( NOT( FASS_vinfo = GetVisualInfo( FASS_plock, TAG_DONE )))
            goto wError;

       /*
        * --- Create a gadget context
        */
        if ( NOT ( f = gadget = CreateContext( &FASS_glist )))
            goto wError;

       /*
        * --- Make the path gadget
        */
        ng.ng_LeftEdge   = 49;
        ng.ng_TopEdge    = 14;
        ng.ng_Width      = 196;
        ng.ng_Height     = 14;
        ng.ng_TextAttr   = &TOPAZ_80;
        ng.ng_GadgetID   = 0;
        ng.ng_VisualInfo = FASS_vinfo;
        ng.ng_GadgetText = "Please enter FONTS path :     ";
        ng.ng_Flags      = PLACETEXT_ABOVE;

        if ( NOT( gadget = CreateGadget( STRING_KIND, gadget, &ng, GTST_MaxChars, 256L, GTST_String, FASS_def, TAG_DONE )))
            goto wError;

        Path              = gadget;
        Path->Activation |= GACT_STRINGCENTER;

       /*
        * --- Make the get gadget
        */

        ng.ng_LeftEdge   = 5;
        ng.ng_Width      = 35;
        ng.ng_GadgetText = "Get";
        ng.ng_GadgetID   = 4;
        ng.ng_Flags      = PLACETEXT_IN;

        gadget = CreateGadget( BUTTON_KIND, gadget, &ng, TAG_DONE );

        Get = gadget;

       /*
        * --- Make the assign gadget
        */
        ng.ng_LeftEdge   = 5;
        ng.ng_TopEdge    = 31;
        ng.ng_Width      = 74;
        ng.ng_GadgetID   = 1;
        ng.ng_GadgetText = "Assign";
        ng.ng_Flags      = PLACETEXT_IN;

        gadget = CreateGadget( BUTTON_KIND, gadget, &ng, TAG_DONE );

        Ass = gadget;

       /*
        * --- Make the hide gadget
        */
        ng.ng_LeftEdge   = 88;
        ng.ng_GadgetID   = 2;
        ng.ng_GadgetText = "HIDE";

        gadget = CreateGadget( BUTTON_KIND, gadget, &ng, TAG_DONE );

        Hide = gadget;

       /*
        * --- Make the quit gadget
        */
        ng.ng_LeftEdge   = 171;
        ng.ng_GadgetID   = 3;
        ng.ng_GadgetText = "QUIT";

        if ( NOT ( gadget = CreateGadget( BUTTON_KIND, gadget, &ng, TAG_DONE )))
            goto wError;

        Quit = gadget;

       /*
        * --- Complete our window taglist
        */
        WindowTags[7].ti_Data = (ULONG)FASS_plock;
        WindowTags[8].ti_Data = (ULONG)f;

       /*
        * --- Open our window
        */
        if( NOT( FASS_wnd = OpenWindowTagList( NULL, &WindowTags[0] )))
            goto wError;

       /*
        * --- They say it has to be done
        */
        GT_RefreshWindow( FASS_wnd, NULL );

       /*
        * --- Activate our string gadget
        */
        ActivateGadget( Path, FASS_wnd, NULL );

       /*
        * --- Set our window it's title
        */
        strcpy((char *)&FASS_title[0],FASS_NAME " " FASS_VERSION " : ");
        strncat((char *)&FASS_title[0],(char *)FASS_keys,26L);

        SetWindowTitles( FASS_wnd, (char *)&FASS_title[0], (char *)-1L );

       /*
        * --- Needed to read the window messages
        */
        FASS_idprt = FASS_wnd->UserPort;
        FASS_idmsk = BitMask( FASS_idprt->mp_SigBit );

        FASS_open = TRUE;
        return;
    }
    return;

wError:
    CloseFWin();
    return;
}

/*
 * --- Close up the FASS window
 */
void CloseFWin( void )
{
    if( FASS_open ) {
       /*
        * --- Close our window
        */
        if ( FASS_wnd ) {
            CloseWindow( FASS_wnd );
            FASS_idprt = NULL;
            FASS_idmsk = NULL;
            FASS_wnd   = NULL;
        }

       /*
        * --- Free our gadgets
        */
        if ( FASS_glist ) {
            FreeGadgets( FASS_glist );
            FASS_glist = NULL;
        }

       /*
        * --- Free our visualinfo
        */
        if ( FASS_vinfo ) {
            FreeVisualInfo( FASS_vinfo );
            FASS_vinfo = NULL;
        }

       /*
        * --- And unlock the used public screen
        */
        if ( FASS_plock ) {
            UnlockPubScreen( NULL, FASS_plock );
            FASS_plock = NULL;
        }

        FASS_open = FALSE;
    }
}

/*
 * --- Display a requester
 */
void Say( char *message )
{
    FASS_say.es_TextFormat = message;

    EasyRequest( NULL, &FASS_say, NULL, NULL );
}

/*
 * --- Get the FONTS: path using the ASL FileRequester.
 */
void GetPath( void )
{
    struct FileRequester    *freq = 0l;

    if ( freq = AllocAslRequest( ASL_FileRequest, TAG_DONE )) {
        if ( AslRequest( freq, FReqTags )) {
            strcpy( FASS_def, freq->rf_Dir );
            GT_SetGadgetAttrs( Path, FASS_wnd, 0l, GTST_String, FASS_def, TAG_DONE );
        }
        FreeAslRequest( freq );
    }
}

/*
 * --- Try to assign the new FONTS path
 */
void CreateFONTS( long set )
{
    struct FileInfoBlock    *finfo = NULL;
    UBYTE                   *pbuf;
    BPTR                     lock = NULL;
    BOOL                     succ = FALSE;

   /*
    * --- Get the FONTS directory full path name
    */
    if (( lock = Lock( "FONTS:" , ACCESS_READ )))
        succ = NameFromLock( lock, (char *)&FASS_def[0], 256L );
    if (( NOT succ) || ( NOT lock ))
        strcpy((char *)&FASS_def[0],"SYS:Fonts");
    if ( lock ) {
        UnLock( lock );
        lock = NULL;
    }

   /*
    * --- If set is 2 we dont want to do more
    */
    if( set == 2 ) return;

   /*
    * --- Is there another way to get this ???????
    */
    pbuf = (char *)((struct StringInfo *)Path->SpecialInfo)->Buffer;

   /*
    * --- Allocate a FileInfoBlock structure
    */
    if (( finfo = (struct FileInfoBlock *)AllocMem( (ULONG)sizeof(struct FileInfoBlock) , MEMF_PUBLIC | MEMF_CLEAR ))) {
       /*
        * --- Try to lock your input
        */
        if (( lock = Lock( pbuf, ACCESS_READ ))) {
           /*
            * --- Examine the lock
            */
            if (( Examine( lock, finfo ))) {
               /*
                * --- Check if it's a directory
                */
                if ( finfo->fib_DirEntryType > 0 ) {
                   /*
                    * --- Check if it must be assigned
                    */
                    if( set ) {
                       /*
                        * Try to assign the directory
                        */
                        if (( AssignLock( "FONTS", lock ))) {
                            Say("Directory assigned!");
                            strcpy( (char *)&FASS_def[0], pbuf );
                            goto suxxess;
                        } else
                            Say("Can't make the assign!");
                    } else
                        goto checked;
                } else
                    Say("Not a directory!");
            } else
                Say("Can't examine object!");
        } else
            Say("Can't lock the object!");
    } else
        Say("Out of memory!");

   /*
    * --- Faulty input! Redisplay old path
    */
    strcpy(pbuf,(char *)&FASS_def[0]);
    RefreshGList(Path,FASS_wnd,NULL,1L);
    ActivateGadget( Path, FASS_wnd, NULL );
checked:
   /*
    * --- Only unlock if lock isn't used for the assignment
    */
    if(lock) UnLock(lock);
suxxess:
    if(finfo)   FreeMem( finfo, (ULONG)sizeof(struct FileInfoBlock ));
}

/*
 * --- Simple main which set's things in motion
 */
void _main( void )
{
    if ( NOT _WBMsg ) {
        setmem( (void *)&FASS_arg[0], 16L, 0L );
        if (( FASS_args = ReadArgs( FASS_temp, &FASS_arg[0], &FASS_iargs ))) {
            OpenFASS();
            CheckFASS();
            CloseFASS( 0L );
        }
        CloseFASS( 27L );
    } else {
        if ( _WBMsg->sm_ArgList->wa_Lock )
            CurrentDir( _WBMsg->sm_ArgList->wa_Lock );

        OpenFASS();
        CheckFASS();
        CloseFASS( 0L );
    }
    atoi(""); /*** otherwise we get a link error and we don't want that ***/
    _waitwbmsg();
}
