/* Next available MSG number is   8 */

/***************************************************************************
   Module Name:  fact.cc

   Copyright (C) 1994 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:  Another Sample ADS application

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

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

    CREATED BY:  Anita Gottapati & Ed Becnel  January 15, 1994

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

    Exported ADS Functions
        SQRT
	FACT

    Modification History:
        Jan 31 1994 - eab - modified to use ads_defun()

    Notes and restrictions on use:


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


#include <stdlib.h>
#include <string.h>
#include "rxdefs.h"
#include "adslib.h"


extern int squareRoot();
extern ads_real rsqr(ads_real );

extern int fact();
static ads_real rfact(int );

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

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

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

/* Table of ADS functions */
ftblent exfun[] = {
            {/*MSG0*/"SQRT", squareRoot},
	    {/*MSG0*/"FACT", fact}
        };

extern "C" 
{                         
AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg,void * pkt);
}


/******************************************************************************/
/*.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);
}


AcRx::AppRetCode 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:
	    break;
        case AcRx::kInvkSubrMsg:
            dofun();
            break;
        case AcRx::kLoadADSMsg:
            funcload();
            break;
        case AcRx::kUnloadADSMsg:
            funcunload();
            ads_printf(/*MSG2*/"Unloading.\n");
            break;
	case AcRx::kUnloadAppMsg:
        default:
	    break;
    }
    return AcRx::kRetOK;
}

 
int squareRoot()
{
    ads_real val;
    ads_real retval = -1.0;
    int i = RTNORM;
    int getinput = FALSE;
    struct resbuf *arg = NULL;
    
    arg = ads_getargs();
    if (arg) {
        switch(arg->restype) {
	case RTREAL:
            val = arg->resval.rreal;
	    break;
	case RTSHORT:
            val = (ads_real)arg->resval.rint;
	    break;
	default:
	    getinput = TRUE;
	}
    } else {
        getinput = TRUE;
    }

    if (getinput)
        i = ads_getreal("Enter a positive real/integer number: ",&val);
    
    switch (i) {
    case RTNORM:
        if (val < 0.0) { 
            ads_fail("Square root of negative number is not defined\n");
            break;
        }
	retval = rsqr(val);
        break;

    case RTNONE:
        ads_printf("Null input to prompt !! \n");
        break;

    case RTCAN:
        ads_printf("Command Cancelled \n");
        break;

    case RTERROR:
        ads_printf("Error returned from ads_getreal \n");
	return RTERROR;
    default:
        ads_printf("Unknown return code from ads_getreal \n");
	return RTERROR;
    }
    if (retval == -1.0)
        ads_retnil();
    else
        ads_retreal(retval);
    return RTNORM;
}

 
ads_real rsqr(ads_real val)
{
    int n = 50;
        
    if (val == 0.0)
        return 0.0;
        
    ads_real y = (val * 2 + 0.1) / (val + 0.1);
    ads_real c = (y - val /y) /2;
    ads_real c1 = 0.0;
        
    while ((c != c1) && (n-- >0)) { 
        y -= c;
        c1 = c;
        c = (y - val/y) /2;
    }
    return y;
}
        
        
int fact()
{
    // prompt for the input value
    int val,rcode = RTNORM;
    ads_real retval = -1.0;
    int getinput = FALSE;
    struct resbuf *arg = NULL;
    
    arg = ads_getargs();
    if (arg) {
        switch(arg->restype) {
	case RTREAL:
            val = (int)arg->resval.rreal;
	    break;
	case RTSHORT:
            val = arg->resval.rint;
	    break;
	default:
	    getinput = TRUE;
	}
    } else {
        getinput = TRUE;
    }

    if (getinput)
        rcode = ads_getint("Input positive integer value less than 170 \n", &val);
        
    switch (rcode) { 
    case RTNORM:
        if ((val  > 170) || ( val < 0)) {
            ads_fail("Illegal Value \n");
	    break;
        }
        retval = rfact(val);
        break;
    case RTNONE:
        ads_printf("Null input to prompt !! \n");
        break;
    case RTCAN:
        ads_printf("Command Cancelled \n");
        break;
    case RTERROR:
        ads_printf("Error returned from ads_getint \n");
	return RTERROR;
    default:
        ads_printf("Unknown Error Code \n");
	return RTERROR;
    }
    if (retval == -1.0)
        ads_retnil();
    else
        ads_retreal(retval);
    return RTNORM;
}

static ads_real rfact(int n)
{
    ads_real ans = 1.0;

    while (n)
        ans *= (ads_real)n--;

    return ans;
}

