/* Next available MSG number is  33 */

/***************************************************************************
   Module Name:  appmngr.cc

   Copyright (C) 1994,1996 by Autodesk, Inc.
 
   Permission to use, copy, modify, and distribute this software in 
   object code form for any purpose and without fee is hereby granted, 
   provided that the above copyright notice appears in all copies and 
   that both that copyright notice and the limited warranty and 
   restricted rights notice below appear in all supporting 
   documentation.
 
   AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.  
   AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.  AUTODESK, INC.
   DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 
   UNINTERRUPTED OR ERROR FREE.
 
   Use, duplication, or disclosure by the U.S. Government is subject to 
   restrictions set forth in FAR 52.227-19 (Commercial Computer 
   Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 
   (Rights in Technical Data and Computer Software), as applicable.
    
   .

   Description:  App loads and unloads a series of ADS apps, and displays
                 The currently loaded ADS and RXADS applications.

   Author     :
                 Autodesk, Inc.
                 2320 Marinship Way
                 Sausalito, CA. 94965
                 (415)332-2344

    This Arx application is a conversion from the original sample ADS app
    appmngr.c.

    CREATED BY:  William Howison, January 1994

    What it tests :

    - Loading of old style ADS applications.
      ads_xload

    - Unloading of old style ADS applications.
      ads_xunload

    - Listing currently loaded old and new style ADS applications.
      ads_loaded

    Function Entry Points:
      AcRx::AppRetCode
        acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt);

    Exported ADS Functions
        TESTXLOAD                 [Test ADS_ XLOAD/XUNLOAD/LOADED functions]

    Modification History:
        Jan 27 1994 - bch - original creation

    Notes and restrictions on use:


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

/**************************************************************************/
/*  MODULE NAME  */
/**************************************************************************/
#define    APPMNGR

/****************************************************************************/
/*  DEFINES  */
/****************************************************************************/
#define ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))

/**************************************************************************/
/*  TYPEDEFS  */
/**************************************************************************/
/* ADS Function Table */
typedef struct {
    char    *name;
    int     (*fptr)();
} ftblent;

typedef struct resbuf rbtype;

/**************************************************************************/
/*  INCLUDES  */
/**************************************************************************/

#include <math.h>
#include <stdio.h>
#include <string.h>
#include "adslib.h"
#include "rxdefs.h"
#include "adesk.h"
#include "ol_errno.h"

/****************************************************************************/
/*  LOCALLY DEFINED ENTRY POINTS INVOKED BY Arx                              */
/****************************************************************************/
extern "C" {
void acrxAnalyzeSystem();
AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt);

}

/****************************************************************************/
/*  LOCAL FUNCTION FORWARD DECLARATIONS  */
/****************************************************************************/
int     testappmngr();

/**************************************************************************/
/*  GLOBAL VARIABLES  */
/**************************************************************************/
/* Table of ADS functions */
ftblent exfun[] = {
            {/*MSG0*/"C:TESTAPPMNGR", testappmngr},
        };

/* Table of ADS applications */
char    *AppTable[] = {
            /*MSG0*/"ads_perr",
#if 0
            /*MSG0*/"appmngr",
#endif
            /*MSG0*/"arbmat",
            /*MSG0*/"asctext",
            /*MSG0*/"colext",
            /*MSG0*/"dlgtest",
            /*MSG0*/"dragger",
            /*MSG0*/"fact",
            /*MSG0*/"gpalsym",
            /*MSG0*/"gravity",
            /*MSG0*/"magnets",
            /*MSG0*/"project",
            /*MSG0*/"ptext",
            /*MSG0*/"sld2ps",
            /*MSG0*/"sqr",
            /*MSG0*/"tower",
        };

/**************************************************************************/
/*  EXTERNAL FUNCTION DECLARATIONS  */
/**************************************************************************/

/**************************************************************************/
/*  EXTERNAL VARIABLE DECLARATIONS  */
/**************************************************************************/

/****************************************************************************/
/*  LOCAL FUNCTION DECLARATIONS  */
/****************************************************************************/

int funcload   _((void));
int funcunload _((void));
int dofun      _((void));
int geterrno   _((void));

/******************************************************************************/
/*.doc geterrno(internal) */
/*+
    This function is called to obtain the value of the AutoCAD system
    variable ERRNO and return it as a result.
-*/
/******************************************************************************/
int
/*FCN*/geterrno()
{
    rbtype errval;

    ads_getvar(/*MSG0*/"ERRNO", &errval);

    return errval.resval.rint;
}

/******************************************************************************/
/*.doc funcload(internal) */
/*+
    This function is called to define all function names in the ADS
    function table.  Each named function will be callable from lisp or
    invokable from another ADS application.
-*/
/******************************************************************************/
int
/*FCN*/funcload()
{
    int i;

    for (i = 0; i < ELEMENTS(exfun); i++) {
        if (!ads_defun(exfun[i].name, i))
            return RTERROR;
    }

    return RTNORM;
}

/******************************************************************************/
/*.doc funclunoad(internal) */
/*+
    This function is called to undefine all function names in the ADS
    function table.  Each named function will be removed from the
    AutoLISP hash table.
-*/
/******************************************************************************/
int
/*FCN*/funcunload()
{
    int i;

    /* Undefine each function we defined */

    for (i = 0; i < ELEMENTS(exfun); i++) {
        ads_undef(exfun[i].name,i);
    }

    return RTNORM;
}
/******************************************************************************/
/*.doc dofun(internal) */
/*+
    This function is called to invoke the function which has the
    registerd function code that is obtained from  ads_getfuncode.  The
    function will return RTERROR if the function code is invalid, or
    RSERR if the invoked function fails to return RTNORM.  The value
    RSRSLT will be returned if the function code is valid and the
    invoked subroutine returns RTNORM.
-*/
/******************************************************************************/
int
/*FCN*/dofun()
{
    int    val;
    int    rc;

    ads_retvoid();
        
    if ((val = ads_getfuncode()) < 0 || val > ELEMENTS(exfun))
        return RTERROR;
 
    rc = (*exfun[val].fptr)();
 
    return ((rc == RTNORM) ? RSRSLT:RSERR);
}

/******************************************************************************/
/*.doc testappmngr(internal) */
/*+
    This function is called from dofun function as a result of RQSUBR
    request being sent to the main dispatch loop.

    The function will walk thru the AppTable and perform an ADS_XLOAD
    on each application.  The message Loading apname... will be printed
    before each application is attempted to be loaded.  If the load
    fails, then the message will be followed by the messaged FAILED..

    The next phase of the test will make a call to the function
    ADS_LOADED to obtain the list of currently loaded applications.  It
    will then walk thu the list and perform an ADS_XUNLOAD on each
    application.  The message Unloading appname... will be printed
    before each application is attempted to be unloaded.  Note, that
    some applications may generate messages of their own, so the output
    may not be exactly as described.  If an application fails to be
    unloaded, then the message FAILED will follow the unloading
    message.

    This function always returns RTNORM.
-*/
/******************************************************************************/
int
/*FCN*/testappmngr()
{
    rbtype      *args;
    rbtype      *tapl;
    rbtype      *applist;
    int         x;
    int         i;
    int         pcount;

    args = ads_getargs();
    ads_printf(/*MSG3*/"\nPerforming ads_xload, ads_xunload, and ads_loaded test\n");
    pcount = 5;
    if (args != NULL) {
        if (args->restype == RTSHORT)
            pcount = args->resval.rint;
    }

    for (i = 1; i <= pcount; i++) {
        ads_printf(/*MSG4*/"\n\n\nPass %d.\n\n\n", i);
        for (x = 0; x < ELEMENTS(AppTable); x++) {
            ads_printf(/*MSG5*/"Loading %s...\n", AppTable[x]);
            if (ads_xload(AppTable[x]) != RTNORM)
                switch(geterrno()) {
                case OL_ENULLPTR:
                    ads_printf(/*MSG6*/"Filename argument was a NULL pointer.\n");
                    break;
                case OL_EOPEN:
                    ads_printf(/*MSG7*/"Specified file could not be opened.\n");
                    break;
                case OL_ELOADED:
                    ads_printf(/*MSG8*/"Specified file is already loaded.\n");
                    break;
                case OL_ENOMEM:
                    ads_printf(/*MSG9*/"No room for app control block.\n");
                    break;
                case OL_EMAXAPP:
                    ads_printf(/*MSG10*/"Max number of ADS apps loaded.\n");
                    break;
                case OL_EEXEC:
                    ads_printf(/*MSG11*/"App could not be executed.\n");
                    break;
                case OL_EVERSION:
                    ads_printf(/*MSG12*/"App contains wrong ADS version #.\n");
                    break;
                }
        }

        for (tapl = applist = ads_loaded(); tapl != NULL; tapl = tapl->rbnext) {
            if (tapl->restype == RTSTR && tapl->resval.rstring != NULL) {
                ads_printf(/*MSG13*/"Unloading %s...\n", tapl->resval.rstring);
                if (ads_xunload(tapl->resval.rstring) != RTNORM)
                    switch(geterrno()) {
                    case OL_ENULLPTR:
                        ads_printf(/*MSG14*/"Filename argument was a NULL pointer.\n");
                        break;
                    case OL_EDENIED:
                        ads_printf(/*MSG15*/"An app cannot unload itself this way,\n");
                        ads_printf(/*MSG16*/"and nested apps cannot be unloaded.\n");
                        break;
                    case OL_EREFUSE:
                        ads_printf(/*MSG17*/"App refused to unload.\n");
                        break;
                    case OL_ENOTLOADED:
                        ads_printf(/*MSG18*/"App is not loaded, so it\n");
                        ads_printf(/*MSG19*/"cannot be unloaded.\n");
                        break;
                    }
            }
        }

        if (applist != NULL)
            ads_relrb(applist);
    }
    return RTNORM;
}

/* =================== Arx Module Interface Functions ================ */

// System Analysis Function.

void 
/*FCN*/acrxAnalyzeSystem()
{
    // If you have dependencies on other applications, this function is
    // called whenever an application is loaded or unloaded, or for that
    // matter, whenever a service is registered or removed.
}

AcRx::AppRetCode 
/*FCN*/acrxEntryPoint(AcRx::AppMsgCode msg, void * ptr)
{

    if (ptr != NULL) {
        // We have been handed some kind of object
        // but we aren't going to do anything with it.
    }

    switch(msg) {
	case AcRx::kInitAppMsg:
            acrxUnlockApplication(ptr);
	    break;
        case AcRx::kInvkSubrMsg:
            dofun();
            break;
        case AcRx::kLoadDwgMsg:
            funcload();
            break;
        case AcRx::kUnloadDwgMsg:
            funcunload();
            ads_printf(/*MSG2*/"Unloading.\n");
            break;
	case AcRx::kUnloadAppMsg:
        default:
	    break;
    }
    return AcRx::kRetOK;
}
