/***************************************************************************
 *                                                                         *
 *   BBSRBT.C                                                              *
 *                                                                         *
 *   Copyright (c) 1992-1997 Galacticomm, Inc.    All rights reserved.     *
 *                                                                         *
 *   This is menu-rebuilder utility for Worldgroup.                        *
 *                                                                         *
 *                                    - S. Brinker    04/06/92             *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "majorbbs.h"
#include "integrou.h"
#include "excphand.h"

#define FILREV "$Revision: 7 $"

extern CHAR scntbl[][GVIDSCNSIZ];

struct stump {                     /* menu tree "stump" structure          */
     CHAR name[PNMSIZ];            /*   name of page (Btrieve key)         */
     INT parent;                   /*   index to parent                    */
     INT child;                    /*   index to child                     */
     INT upsib;                    /*   index to up sibling                */
     INT dnsib;                    /*   index to down sibling              */
     INT tx,ty;                    /*   (x,y) location in tree image       */
     INT flags;                    /*   various bit flags                  */
};

#define ISAUTO      0x0001         /* this is an auto-branch page          */
#define ISFILE      0x0002         /* this is a display-file page          */
#define ISMODU      0x0004         /* this is a module-link page           */
#define ISCSMD      0x0008         /* this is a C/S module-link page       */

VOID *stumps;                      /* dynamically alloc'd array of stumps  */
INT nstumps;                       /* number of stumps in stumps[] array   */
INT curstump;                      /* current stump # we're working with   */
INT maxstp;                        /* maximum number of stumps allowed     */
DFAFILE *mpbb;                     /* pointer to Btrieve BBSMENU.DAT file  */
INT timaxx,timaxy;                 /* max sizes of tree image x & y coords */
GBOOL csedit=FALSE;                /* use C/S side of menus                */

static CHAR dosscn[GVIDSCNSIZ];    /* saved DOS screen image               */

VOID build(VOID);
INT bldtre(CHAR *name,INT parent,INT upsib);
INT addstp(struct mnupag *pagptr,INT parent,INT upsib);
INT ydepth(struct stump *stuptr);
INT getmtx(VOID);
INT getmty(VOID);
VOID savetree(VOID);
VOID kilref(INT pagidx,CHAR *refnam);
INT fndstp(CHAR *name);
struct stump *stpoff(INT stpnum);
CHAR *mbbkey(CHAR *menuname);

VOID
main(VOID)
{
TRY
     INT exicode;
     VOID monorcol(VOID);

     initvid();
     scn2mem(dosscn,0,GVIDSCNSIZ);
     iniint();
     monorcol();
     cvtscn(scntbl[0]);
     explode(scntbl[0],20,3,59,15);
     cursiz(GVIDNOCURS);
     if ((exicode=setjmp(disaster)) != 0) {
          finint();
          clsvid();
          exit(exicode);
     }
     clrefs();
     mpbb=dfaOpen("wgsmenu2.dat",sizeof(struct mnupag),NULL);
     maxstp=(INT)dfaCountRec()+10;
     stumps=alcblok(maxstp,sizeof(struct stump));
     build();
     dfaClose(mpbb);
     savetree();
     mpbb=dfaOpen("wgsmenu2.dat",sizeof(struct mnupag),NULL);
     csedit=TRUE;
     build();
     dfaClose(mpbb);
     savetree();
     finint();
     cursiz(GVIDLILCURS);
     mem2scn(dosscn,0,GVIDSCNSIZ);
     locate(0,24);
     clsvid();
     return;
EXCEPT
}

VOID
build(VOID)
{
     struct mnupag mp;
     LONG pos;
     INT i;

     for (i=0 ; i < maxstp ; i++) {
          setmem(stpoff(i),sizeof(struct stump),0);
     }
     nstumps=1;
     strcpy(stpoff(0)->name,"*MASTER*");
     bldtre("TOP",0,0);
     if (!dfaQueryLO(0)) {
          catastro("NO RECORDS IN BBSMENU.DAT!");
     }
     do {
          dfaAbsRec(&mp,0);
          if (mp.menutype[0] == (csedit ? 'C' : 'A')
           && (mp.flags&TPOTRE) && !sameas(mp.pagnam,"TOP")) {
               pos=dfaAbs();
               bldtre(mp.pagnam,0,0);
               dfaGetAbs(NULL,pos,0);
          }
     } while (dfaQueryNX());
}

INT                                /* returns index into stumps array[]    */
bldtre(name,parent,upsib)
CHAR *name;
INT parent,upsib;
{
     LONG mybpos;
     INT i,thisp,nupsib;
     static struct mnupag tmppag;

     if (!dfaAcqEQ(&tmppag,mbbkey(name),0)) {
          kilref(parent,name);
     }
     else {
          unpack(&tmppag);
     }
     mybpos=dfaAbs();
     if ((thisp=addstp(&tmppag,parent,upsib)) != -1) {
          for (upsib=0,i=0 ; i < MAXSEL ; i++) {
               if (tmppag.page[i].selchr != '\0') {
                    if ((nupsib=bldtre(tmppag.page[i].destpage,thisp,upsib)) != -1) {
                         upsib=nupsib;
                    }
                    dfaGetAbs(&tmppag,mybpos,0);
                    unpack(&tmppag);
               }
          }
          if ((tmppag.flags&TPOTRE) && parent != 0) {
               tmppag.flags&=~TPOTRE;
               savepage(&tmppag,FALSE);
          }
     }
     return(thisp);
}

INT
addstp(pagptr,parent,upsib)
struct mnupag *pagptr;
INT parent,upsib;
{
     CHAR *name;
     INT flags=0;
     struct stump *sptr;

     if (fndstp(pagptr->pagnam) != -1) {
          kilref(parent,pagptr->pagnam);
          return(-1);
     }
     setatr(0x1A);
     locate(37,13);
     printf("%-15s",name=pagptr->pagnam);
     switch (pagptr->flags&(AUTPAG|MDLPAG|FILPAG)) {
     case AUTPAG:
          flags=ISAUTO;
          break;
     case MDLPAG:
          incref(pagptr->modnam);
          flags=(pagptr->flags&CSMPAG) ? ISCSMD : ISMODU;
          break;
     case FILPAG:
          flags=ISFILE;
          break;
     }
     if (nstumps == maxstp) {
          catastro("FATAL ERROR - STUMPS ARRAY OVERFLOW");
     }
     sptr=stpoff(nstumps);
     setmem(sptr,sizeof(struct stump),0);
     strcpy(sptr->name,name);
     if (parent) {
          sptr->tx=stpoff(parent)->tx+strlen(stpoff(parent)->name)+2;
          sptr->ty=(upsib ? ydepth(stpoff(upsib))+1 : stpoff(parent)->ty+1);
          sptr->parent=parent;
     }
     else {
          if (sameas(sptr->name,"TOP")) {
               sptr->ty=0;
          }
          else {
               sptr->ty=getmty()+1;
          }
     }
     sptr->flags|=flags;
     if (upsib) {
          sptr->upsib=upsib;
          if (stpoff(upsib)->dnsib) {
               sptr->dnsib=stpoff(upsib)->dnsib;
               stpoff(stpoff(upsib)->dnsib)->upsib=nstumps;
          }
          stpoff(upsib)->dnsib=nstumps;
     }
     else if (parent != 0) {
          if (stpoff(parent)->child) {
               sptr->dnsib=stpoff(parent)->child;
               stpoff(stpoff(parent)->child)->upsib=nstumps;
          }
          stpoff(parent)->child=nstumps;
     }
     timaxx=getmtx();
     timaxy=getmty();
     nstumps++;
     return(nstumps-1);
}

INT
ydepth(stuptr)
struct stump *stuptr;
{
     if (stuptr->child) {
          stuptr=stpoff(stuptr->child);
          while (stuptr->dnsib) {
               stuptr=stpoff(stuptr->dnsib);
          }
          if (stuptr->child) {
               return(ydepth(stuptr));
          }
     }
     return(stuptr->ty);
}

INT
getmtx(VOID)
{
     struct stump *sp;
     INT i,retval=0;

     for (i=0 ; i < nstumps ; i++) {
          sp=stpoff(i);
          if (sp->tx > retval) {
               retval=sp->tx;
          }
     }
     return(retval);
}

INT
getmty(VOID)
{
     struct stump *sp;
     INT i,retval=0;

     for (i=0 ; i < nstumps ; i++) {
          sp=stpoff(i);
          if (sp->ty > retval) {
               retval=sp->ty;
          }
     }
     return(retval);
}

VOID
savetree(VOID)
{
     FILE *tfp;
     INT i;
     CHAR *ec;
     struct stump *sp;
     struct ffblk fb;

     ec=csedit ? "wgsmenuc.idx" : "wgsmenus.idx";
     tfp=fopen(ec,FOPWB);
     if (tfp == NULL) {
          catastro("COULDN'T OPEN \"%s\" FOR WRITING!",ec);
     }
     fndfile(&fb,"wgsmenu2.dat",0);
     fwrite(&fb,sizeof(struct ffblk),1,tfp);
     fprintf(tfp,"%d %d %d\n",nstumps,timaxx,timaxy);
     for (i=0 ; i < nstumps ; i++) {
          sp=stpoff(i);
          fprintf(tfp,"%s %d %d %d %d %d %d %d\n",sp->name,sp->parent,
                       sp->child,sp->upsib,sp->dnsib,sp->tx,sp->ty,sp->flags);
     }
     fclose(tfp);
     tfp=fopen(csedit ? "wgsmenus.idx" : "wgsmenuc.idx",FOPRWB);
     if (tfp != NULL) {
          fseek(tfp,0L,0);
          fwrite(&fb,sizeof(struct ffblk),1,tfp);
          fclose(tfp);
     }
}

INT
fndstp(CHAR *name)
{
     INT i;

     for (i=0 ; i < nstumps ; i++) {
          if (sameas(name,stpoff(i)->name)) {
               return(i);
          }
     }
     return(-1);
}

VOID
kilref(INT pagidx,CHAR *refnam)
{
     INT i;
     static struct mnupag tmppag;

     if (dfaAcqEQ(&tmppag,mbbkey(stpoff(pagidx)->name),0)) {
          unpack(&tmppag);
          for (i=0 ; i < MAXSEL ; i++) {
               if (tmppag.page[i].selchr != '\0'
                   && sameas(tmppag.page[i].destpage,refnam)) {
                    setmem(&tmppag.page[i],sizeof(struct pglink),0);
               }
          }
          savepage(&tmppag,FALSE);
     }
}

struct stump *
stpoff(INT stpnum)
{
     return((struct stump *)ptrblok(stumps,stpnum));
}

CHAR *
mbbkey(                            /* returns a key depending on edit mode */
CHAR *menuname)                    /* menu name                            */
{
     static CHAR retstr[PNMSIZ+1];

     stzcpy(retstr,(csedit ? "C" : "A"),PNMSIZ+1);
     stzcat(retstr,menuname,PNMSIZ+1);
     return(retstr);
}
