/***************************************************************************
 *                                                                         *
 *   THREADU.C                                                             *
 *                                                                         *
 *   Copyright (c) 1994-1997 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   This is a suite of utility routines for dealing with Forum message    *
 *   threads.                                                              *
 *                                                                         *
 *                                               - C. Robert  10/25/94     *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "threadu.h"

#define FILREV "$Revision: 7 $"

static INT maxcch;                 /* max # of threads in in-memory cache  */
static INT swpnxt;                 /* in-memory thread to swap to disk next*/

static INT cchhdl;                 /* handle to in-memory cache array      */

struct thrinf {                    /* per-thread information structure     */
     USHORT forum;                 /*   Forum number thread resides in     */
     LONG thrid;                   /*   unique thread ID within Forum      */
     USHORT nmsgs;                 /*   number of messages within thread   */
};

#define CCHISZ      40             /* increment size for resizing cache    */

static
DFAFILE *tctbb;                    /* thread-count Btrieve data file ptr   */

static struct thrinf *sinthr(USHORT forum,LONG thrid);
static VOID southr(struct thrinf *thrptr);

VOID
inithu(                            /* initialize thread utilities          */
INT maxinm)                        /*   max # of threads in in-memory cache*/
{
     maxcch=maxinm;
     swpnxt=0;
     cchhdl=newarr(CCHISZ,sizeof(struct thrinf));
     tctbb=dfaOpen("galthrs2.dat",sizeof(struct thrinf),NULL);
}

USHORT
ninthr(                            /* get number of messages in a thread   */
USHORT forum,                      /*   forum number thread resides in     */
LONG thrid)                        /*   unique thread ID within Forum      */
{
     INT i;
     struct thrinf thrinf,*tp;

     for (i=0 ; i < ninarr(cchhdl) ; i++) {
          tp=arrelem(cchhdl,i);
          if (tp->nmsgs != 0 && tp->forum == forum && tp->thrid == thrid) {
               return(tp->nmsgs);
          }
     }
     dfaSetBlk(tctbb);
     thrinf.forum=forum;
     thrinf.thrid=thrid;
     thrinf.nmsgs=0;
     dfaAcqEQ(&thrinf,&thrinf,0);
     dfaRstBlk();
     return(thrinf.nmsgs);
}

GBOOL                              /*   did this just create a new thread? */
incthr(                            /* increment # of messages in a thread  */
USHORT forum,                      /*   forum number thread resides in     */
LONG thrid)                        /*   unique thread ID within Forum      */
{
     struct thrinf *thrptr;

     thrptr=sinthr(forum,thrid);
     if (++thrptr->nmsgs == 1) {
          return(TRUE);
     }
     return(FALSE);
}

GBOOL                              /*   did this just destroy a thread?    */
decthr(                            /* decrement # of messages in a thread  */
USHORT forum,                      /*   forum number thread resides in     */
LONG thrid)                        /*   unique thread ID within Forum      */
{
     struct thrinf *thrptr;

     thrptr=sinthr(forum,thrid);
     if (thrptr->nmsgs == 0) {
          return(FALSE);
     }
     if (--thrptr->nmsgs == 0) {
          dfaSetBlk(tctbb);
          if (dfaAcqEQ(NULL,thrptr,0)) {
               dfaDelete();
          }
          dfaRstBlk();
          return(TRUE);
     }
     return(FALSE);
}

VOID
setthrc(                           /* set number of messages in thread     */
USHORT forum,                      /*   forum ID thread is in              */
LONG thrid,                        /*   thread ID of thread                */
USHORT msgcnt)                     /*   number of messages in thread       */
{
     struct thrinf *thrptr;

     thrptr=sinthr(forum,thrid);
     if (msgcnt == 0) {
          thrptr->nmsgs=0;
          dfaSetBlk(tctbb);
          if (dfaAcqEQ(NULL,thrptr,0)) {
               dfaDelete();
          }
          dfaRstBlk();
     }
     else {
          thrptr->nmsgs=msgcnt;
     }
}

VOID
cathrs(VOID)                       /* clear all thread counters (mcu only) */
{
     INT i;

     for (i=0 ; i < ninarr(cchhdl) ; i++) {
          ((struct thrinf *)arrelem(cchhdl,i))->nmsgs=0;
     }
     dfaSetBlk(tctbb);
     while (dfaStepLO(NULL)) {
          dfaDelete();
     }
     dfaRstBlk();
}

VOID
cfthrs(                            /* clr Forum thread counters (mcu only) */
USHORT forum)                      /*   Forum to clear all threads for     */
{
     INT i;
     struct thrinf *thrptr,tinf;

     for (i=0 ; i < ninarr(cchhdl) ; i++) {
          thrptr=arrelem(cchhdl,i);
          if (thrptr->forum == forum) {
               thrptr->nmsgs=0;
          }
     }
     dfaSetBlk(tctbb);
     tinf.forum=forum;
     tinf.thrid=0;
     if (dfaQueryGE(&tinf,0)) {
          do {
               dfaAbsRec(&tinf,0);
               if (tinf.forum != forum) {
                    break;
               }
               dfaDelete();
          } while (dfaQueryNX());
     }
     dfaRstBlk();
}

VOID
clsthu(VOID)                       /* close down thread utilities          */
{
     INT i;
     struct thrinf *thrptr;

     for (i=0 ; i < ninarr(cchhdl) ; i++) {
          thrptr=arrelem(cchhdl,i);
          if (thrptr->nmsgs != 0) {
               southr(thrptr);
          }
     }
     dfaClose(tctbb);
}

static struct thrinf *
sinthr(                            /* swap thread on disk into memory      */
USHORT forum,                      /*   forum number thread resides in     */
LONG thrid)                        /*   unique thread ID within Forum      */
{
     INT i,freeth;
     struct thrinf *thrptr,*tp;

     thrptr=NULL;
     freeth=-1;
     for (i=0 ; i < ninarr(cchhdl) ; i++) {
          tp=arrelem(cchhdl,i);
          if (tp->nmsgs != 0 && tp->forum == forum && tp->thrid == thrid) {
               thrptr=tp;
               break;
          }
          if (tp->nmsgs == 0 && freeth == -1) {
               freeth=i;
          }
     }
     if (thrptr == NULL) {
          if (freeth != -1) {
               thrptr=arrelem(cchhdl,freeth);
          }
          else if (ninarr(cchhdl) < maxcch) {
               thrptr=add2arr(cchhdl,NULL);
          }
          else {
               if (swpnxt >= ninarr(cchhdl)) {
                    swpnxt=0;
               }
               thrptr=arrelem(cchhdl,swpnxt);
               southr(thrptr);
               swpnxt++;
          }
          dfaSetBlk(tctbb);
          thrptr->forum=forum;
          thrptr->thrid=thrid;
          if (!dfaAcqEQ(thrptr,thrptr,0)) {
               thrptr->nmsgs=0;
          }
          dfaRstBlk();
     }
     return(thrptr);
}

static VOID
southr(                            /* swap thread in cache out to disk     */
struct thrinf *thrptr)             /*   pointer to thread in cache         */
{
     dfaSetBlk(tctbb);
     if (dfaAcqEQ(NULL,thrptr,0)) {
          if (((struct thrinf *)tctbb->data)->nmsgs != thrptr->nmsgs) {
               dfaUpdateV(thrptr,sizeof(struct thrinf));
          }
     }
     else {
          dfaInsertV(thrptr,sizeof(struct thrinf));
     }
     dfaRstBlk();
     thrptr->nmsgs=0;
}
