/***************************************************************************
 *                                                                         *
 *   PHASEDBG.C                                                            *
 *                                                                         *
 *   Copyright (c) 1994-1997 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   Track the phases of the server, for better debugging, tracking, etc.  *
 *   Do this by bracketing important phases or application-specific        *
 *   processing with BEG_PHASE() and END_PHASE() macros.  These            *
 *   macros generate no code if DEBUG is not #-defined.  They generate     *
 *   interceptable vector calls if DEBUG is turned on.                     *
 *                                                                         *
 *                                            - R. Stein 10/14/94          *
 *                                                                         *
 ***************************************************************************/

#ifdef GCWINNT
#include <windows.h>
#endif
#include "gcomm.h"
#include "majorbbs.h"
#include "phasedbg.h"

#define FILREV "$Revision: 11 $"

static VOID begphs(CHAR *name,LONG num);
static VOID endphs(CHAR *name,LONG num);
#ifdef DEBUG
static VOID rcdphs(CHAR *name,LONG num);
#endif // DEBUG

VOID (*beg_phase)(CHAR *name,LONG num)=begphs;   /* BEG_PHASE() vector    */
VOID (*end_phase)(CHAR *name,LONG num)=endphs;   /* END_PHASE() vector    */

#ifdef DEBUG
struct phasedbg phasedbg[NUMPHS];  /* cyclic array of phase information    */
struct phasedbg pnotavl={"Phase info unavailable"}; /* dummy info          */
INT phsseq=0;                      /* phasedbg[] index, 0 to NUMPHS-1      */
INT phsful=0;                      /* count how much phasedbg[] filled up  */
#endif // DEBUG

#ifdef GCWINNT
VOID (*prtPhase)(INT x, INT y)=NULL;      /* Print phase vector    */
#endif // GCWINNT

static VOID
begphs(                            /* default BEG_PHASE handler            */
CHAR *name,                        /*   unique name of phase (non-volatile)*/
LONG num)                          /*   any number or pointer              */
{
#ifdef DEBUG
     rcdphs(name,num);
     pstphs(0)->flags|=PDBBEG;

#ifdef GCWINNT
     if (prtPhase != NULL) {
          (*prtPhase)(30,0);      // HACK make it configurable
     }
#endif //GCWINNT
#else
     (VOID)name;
     (VOID)num;
#endif // DEBUG
}

static VOID
endphs(                            /* default END_PHASE handler            */
CHAR *name,                        /*   unique name of phase (non-volatile)*/
LONG num)                          /*   any number or pointer              */
{
#ifdef DEBUG
     rcdphs(name,num);
#ifdef GCWINNT
     if (prtPhase != NULL) {
          (*prtPhase)(30,0);      // HACK make it configurable
     }
#endif //GCWINNT
#else
     (VOID)name;
     (VOID)num;
#endif // DEBUG
}

#ifdef DEBUG
static VOID
rcdphs(                            /* record phase info in phasedbg[]      */
CHAR *name,                        /*   name of phase                      */
LONG num)                          /*   number or pointer                  */
{
     struct phasedbg *pdp;
#ifdef GCWINNT
     static INT gVarsLoaded=0;
     static INT *__usrnum;
     static INT *__nterms;
     static struct user *(*__usroff)(INT usrnum);
     HMODULE hWGS;
     FARPROC pProc;
     GBOOL fOk=TRUE;

     if (gVarsLoaded == 0) {
          gVarsLoaded++;
          if ((hWGS=GetModuleHandle("wgserver.exe")) != NULL) {
               if ((pProc=GetProcAddress(hWGS,"_nterms")) != NULL) {
                    __nterms=(INT *)pProc;
               }
               else {
                    fOk=FALSE;
               }
               if (fOk && (pProc=GetProcAddress(hWGS,"_usrnum")) != NULL) {
                    __usrnum=(INT *)pProc;
               }
               else {
                    fOk=FALSE;
               }
               if (fOk && (pProc=GetProcAddress(hWGS,"_usroff")) != NULL) {
                    __usroff=(struct user *(*)(INT))pProc;
                    gVarsLoaded++;
               }
          }
     }
#endif
     pdp=&phasedbg[phsseq];
     pdp->name=name;
     pdp->num=num;
#ifdef GCWINNT
     if (gVarsLoaded == 2 && 0 <= *__usrnum && *__usrnum < *__nterms) {
          pdp->usrnum=*__usrnum;
          pdp->usrcls=(*__usroff)(*__usrnum)->usrcls;
          pdp->usrsta=(*__usroff)(*__usrnum)->state;
          pdp->usrsbs=(*__usroff)(*__usrnum)->substt;
     }
     else {
          pdp->usrnum=-1;
          pdp->usrcls=-1;
          pdp->usrsta=-1;
          pdp->usrsbs=-1;
     }
#else
#ifndef GCDOSL
     pdp->usrnum=usrnum;
     if (0 <= usrnum && usrnum < nterms) {
          pdp->usrcls=usroff(usrnum)->usrcls;
          pdp->usrsta=usroff(usrnum)->state;
          pdp->usrsbs=usroff(usrnum)->substt;
     }
     else {
          pdp->usrcls=-1;
          pdp->usrsta=-1;
          pdp->usrsbs=-1;
     }
#endif // GCDOSL
#endif // GCWINNT
     pdp->flags=0;
     if (phsful < NUMPHS) {
          phsful++;
     }
     if (++phsseq >= NUMPHS) {
          phsseq=0;
     }
}
#endif // DEBUG

VOID
rptphs(                            /* report on past phases                */
FILE *fp)                          /*   file to send report to, FOPWA-opn'd*/
{
#ifndef GCWINNT
#ifdef DEBUG
     struct phasedbg *pdp;
     INT i;

     if (phsful == 0) {
          return;
     }
     fprintf(fp,"Last %d phase transitions (top=early, bottom=latest):\n",
             phsful);
     for (i=phsful-1 ; i >= 0 ; i--) {
          pdp=pstphs(i);
          fprintf(fp,pdp->flags&PDBBEG ? "BEG %-24.24s" : "END %-24.24s",
                  pdp->name);
          fprintf(fp,"0x%08lX",pdp->num);
#ifndef GCDOSL
          if (0 <= pdp->usrnum && pdp->usrnum < nterms) {
               fprintf(fp," CH%02X%2d",channel[pdp->usrnum],pdp->usrcls);
               if ((pdp->usrcls > SUPIPG || pdp->usrcls == BBSPRV)
                && 0 <= pdp->usrsta && pdp->usrsta < nmods) {
                    fprintf(fp," %-24.24s",module[pdp->usrsta]->descrp);
               }
               else {
                    fprintf(fp," state=%6d            ",pdp->usrsta);
               }
               fprintf(fp,"%6d",pdp->usrsbs);
          }
          else {
               fprintf(fp," usrnum=%d",pdp->usrnum);
          }
#endif // GCDOSL
          fprintf(fp,"\n");
     }
#ifndef GCDOSL
     fprintf(fp,"Status %d",status);
     if (status == CRSTG && goodstg(input) && strlen(input) < INPSIZ) {
          fprintf(fp,"  \"%s\"",input);
     }
     fprintf(fp,"\n");
#endif // GCDOSL
#endif // DEBUG
#endif // GCWINNT
     (VOID)fp;
}

struct phasedbg *                  /* returns pointer to phasedbg struct   */
pstphs(                            /* get information on a past phase      */
INT index)                         /*   0=most recent, NUMPHS-1=earliest   */
{
#ifdef DEBUG
     if (index >= phsful) {
          return(&pnotavl);
     }
     return(&phasedbg[(phsseq+NUMPHS-1-index)%NUMPHS]);
#else
     (VOID)index;
     return(NULL);
#endif // DEBUG
}
