/***************************************************************************
 *                                                                         *
 *   WLMFORU.C                                                             *
 *                                                                         *
 *   Copyright (c) 1997 Galacticomm, Inc.         All Rights Reserved.     *
 *                                                                         *
 *   Worldlink Messaging forum crossreference utilities.                   *
 *                                                                         *
 *                                            - J. Alvrus   1/28/97        *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "gme.h"
#include "wlmutl.h"
#include "wlmforu.h"

#define FILREV "$Revision: 1.2 $"

#define XRFBLKSZ 16                /* # elements to reallocate at a time   */

GBOOL wlXrefActive;                /* has forum xref been initialized?     */

struct forxref **xrfList=NULL;     /* pointer to list of xrefs             */
INT xrfInUse;                      /* # xref array elements in use         */
INT xrfAlloc;                      /* # xref array elements allocated      */

VOID xrfForCrt(const struct fordsk *newdef,const CHAR *desc,const CHAR *echoes);
VOID xrfForMod(const struct fordef *fordef,const CHAR *desc,const CHAR *echoes);
VOID xrfForDel(USHORT forum);
VOID xrfRemFor(USHORT forum,GBOOL notify);
VOID xrfNewFor(const adr_t *echo,INT necho,USHORT forum);
VOID xrfAddForum(const adr_t *echo,INT necho,USHORT forum);
VOID xrfSortList(VOID);
INT xrfComp(const VOID *target,const VOID *array,ULONG index);

VOID
initForXref(VOID)                  /* initialize forum crossref utility    */
{
     INT i,j,nfors;
     const struct fordef *fdef;
     const adr_t *echo;

     xrfInUse=0;
     nfors=numforums();
     for (i=0 ; i < nfors ; ++i) {
          fdef=fiddefp(i);
          echo=(const adr_t *)fdef->echoes;
          for (j=0 ; j < fdef->necho ; ++j) {
               if (xrfUseEcho(echo[j])) {
                    ++xrfInUse;
               }
          }
     }
     xrfAlloc=((xrfInUse/XRFBLKSZ)+1)*XRFBLKSZ;
     xrfList=alcmem(xrfAlloc*sizeof(struct forxref *));
     xrfInUse=0;
     for (i=0 ; i < nfors ; ++i) {
          fdef=fiddefp(i);
          xrfAddForum((const adr_t *)fdef->echoes,fdef->necho,fdef->forum);
     }
     xrfSortList();
     hook_gme(GMEHOOK_NOT_NEWFOR,(voidfunc)xrfForCrt);
     hook_gme(GMEHOOK_NOT_UPDFOR,(voidfunc)xrfForMod);
     hook_gme(GMEHOOK_NOT_DELFORL,(voidfunc)xrfForDel);
     wlXrefActive=TRUE;
}

VOID
closeForXref(VOID)                 /* shut down forum crossreference       */
{
     INT i;

     if (wlXrefActive) {
          for (i=0 ; i < xrfInUse ; ++i) {
               free(xrfList[i]);
          }
          free(xrfList);
     }
     wlXrefActive=FALSE;
}

VOID
xrfForCrt(                         /* forum has been created hook          */
const struct fordsk *newdef,       /*   new forum definition structure     */
const CHAR *desc,                  /*   descriptive text                   */
const CHAR *echoes)                /*   pointer to array of echo addresses */
{
     (VOID)desc;
     if (wlXrefActive) {
          xrfNewFor((const adr_t *)echoes,newdef->necho,newdef->forum);
     }
}

VOID
xrfForMod(                         /* forum has been modified hook         */
const struct fordef *fordef,       /*   forum definition structure         */
const CHAR *desc,                  /*   descriptive text                   */
const CHAR *echoes)                /*   pointer to array of echo addresses */
{
     (VOID)desc;
     if (!wlXrefActive) {
          return;
     }
     if (echoes != NULL) {
          xrfRemFor(fordef->forum,FALSE);
          xrfNewFor((const adr_t *)echoes,fordef->necho,fordef->forum);
     }
}

VOID
xrfForDel(                         /* forum deleted hook                   */
USHORT forum)                      /*   forum ID of deleted forum          */
{
     xrfRemFor(forum,TRUE);
}

VOID
xrfRemFor(                         /* remove forum from crossreference     */
USHORT forum,                      /*   forum ID of deleted forum          */
GBOOL notify)                      /*   notify outside code of change      */
{
     INT i;
     GBOOL changed;

     if (!wlXrefActive) {
          return;
     }
     changed=FALSE;
     for (i=0 ; i < xrfInUse ; ++i) {
          if (xrfList[i]->forum == forum) {
               if (notify) {
                    xrfDeleting(forum,xrfList[i]->name);
               }
               changed=TRUE;
               free(xrfList[i]);
               --xrfInUse;
               memmove(&xrfList[i],&xrfList[i+1],
                       (xrfInUse-i)*sizeof(struct forxref *));
          }
     }
     if (changed) {
          xrfChanged();
     }
}

VOID
xrfNewFor(                         /* handle adding new forum              */
const adr_t *echo,                 /*   array of echo addresses            */
INT necho,                         /*   number of addresses in array       */
USHORT forum)                      /*   forum ID                           */
{
     INT i,n;
     size_t oldsiz;

     for (i=0,n=0 ; i < necho ; ++i) {
          if (xrfUseEcho(echo[i])) {
               ++n;
          }
     }
     if (n != 0) {
          if (xrfInUse+n > xrfAlloc) {
               oldsiz=xrfAlloc*sizeof(struct forxref *);
               xrfAlloc=(((xrfInUse+n)/XRFBLKSZ)+1)*XRFBLKSZ;
               xrfList=alcrsz(xrfList,oldsiz,xrfAlloc*sizeof(struct forxref *));
          }
          xrfAddForum(echo,necho,forum);
          xrfSortList();
          xrfChanged();
     }
}

VOID
xrfAddForum(                       /* add a forum to list                  */
const adr_t *echo,                 /*   array of echo addresses            */
INT necho,                         /*   number of addresses in array       */
USHORT forum)                      /*   forum ID                           */
{                                  /*   (xrfList must already be resized)  */
     INT i;
     struct forxref *pxrf;
     const CHAR *cp;

     for (i=0 ; i < necho ; ++i) {
          if (xrfUseEcho(echo[i])) {
               cp=skppfx(echo[i]);
               xrfList[xrfInUse++]=pxrf=alcmem(fldoff(forxref,name)
                                              +strlen(cp)+1);
               pxrf->forum=forum;
               strcpy(pxrf->name,cp);
          }
     }
}

VOID
xrfSortList(VOID)                  /* sort crossreference list             */
{
     INT i,j;
     struct forxref *swap;

     for (i=0 ; i < xrfInUse-1 ; ++i) {
          for (j=i+1 ; j < xrfInUse ; ++j) {
               if (stricmp(xrfList[i]->name,xrfList[j]->name) > 0) {
                    swap=xrfList[i];
                    xrfList[i]=xrfList[j];
                    xrfList[j]=swap;
               }
          }
     }
}

INT                                /*   (returns NOIDX if not found)       */
xrfForumIdx(                       /* get index of forum in xref list      */
const CHAR *forName)               /*   WL forum name                      */
{
     INT i;

     if ((i=(INT)binSearch(forName,xrfList,xrfInUse,xrfComp)) == xrfInUse) {
          return(NOIDX);
     }
     return(i);
}

INT                                /*   > 0 = target > test, etc.          */
xrfComp(                           /* crossref search comparison function  */
const VOID *target,                /*   target object                      */
const VOID *array,                 /*   array object                       */
ULONG index)                       /*   index of array element to test     */
{
     (VOID)array;
     ASSERT(array == xrfList);
     ASSERT(index < xrfInUse);
     return(stricmp(target,xrfList[(INT)index]->name));
}
