/***************************************************************************
 *                                                                         *
 *   AUTSNS.C                                                              *
 *                                                                         *
 *   Copyright (c) 1993-1997 Galacticomm, Inc.    All rights reserved.     *
 *                                                                         *
 *   Autosensor routine registration, for protocols and other testing      *
 *   at the beginning of a user's session.                                 *
 *                                                                         *
 *                                               - R. Stein  2/4/93        *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "majorbbs.h"
#include "gcspsrv.h"

#define FILREV "$Revision: 6 $"

struct autsns {                            /* autosense handler information */
     AUTOSENSE *aushdl;                                  /* handler routine */
     CHAR *done;                 /* array[nterms] of 0=still working 1=done */
};

CHAR *poslng;                       /* possible languages autosensed        */
USHORT *austim;                     /* array[nterms] of the time of bgnaus()*/
INT numcand;                        /* # of candidates -- cntcand() ret val */
INT fstcand;                        /* first candidate -- cntcand() ret val */
CHAR maxcand;                       /* best candidate  -- cntcand() ret val */
USHORT auswait=10*16;               /* master timeout, 1/16 of second units */
INT numaus=0;                               /* number of autosense handlers */
struct autsns *aushandlers=NULL;             /* array of autosense handlers */

#define PRCHNK 40         /* chunk of bytes processed at-a-time by prcaus() */

VOID
iniaus(VOID)                       /* initialize autosense handler services */
{                                  /* nterms and nlingo must be known already*/
#if defined(UNIX)
     auswait=2*16;
#else
     auswait=10*16;
#endif
     poslng=alczer(nterms*nlingo);
     austim=(USHORT *)alcmem(nterms*(sizeof(USHORT)));
}

VOID
regautsns(                                 /* register an autosense handler */
AUTOSENSE *aushdl)
{
     aushandlers=(struct autsns *)alcrsz(aushandlers,
                                         sizeof(struct autsns)*numaus,
                                         sizeof(struct autsns)*(numaus+1));
     aushandlers[numaus].aushdl=aushdl;
     aushandlers[numaus].done=alczer(nterms);
     numaus++;
}

GBOOL                              /*   returns TRUE=no need, FALSE=more   */
bgnaus(                            /* begin autosensing on channel usrnum  */
GBOOL foreal)                      /*   FALSE=just init poslng[], TRUE=prep*/
                                   /*   handlers too                       */
{
     USHORT i;
     GBOOL itsdun,alldone;

     setmem(&poslng[usrnum*nlingo],nlingo,1);
     alldone=TRUE;
     if (foreal) {
          for (i=0 ; i < numaus ; i++) {
               itsdun=aushandlers[i].aushdl(0,"",0);
               aushandlers[i].done[usrnum]=itsdun;
               if (!itsdun) {
                    alldone=FALSE;
               }
          }
          if (!gcspaus(0,"",0)) {
               alldone=FALSE;
          }
          austim[usrnum]=(USHORT)(hrtval()>>12);
          if (!alldone) {
               btutrg(usrnum,OUTSIZ);
          }
     }
     return(alldone);
}

GBOOL                              /*   FALSE=some left  TRUE=done         */
prcaus(VOID)                       /* process autosensors for usrnum chan  */
{
     CHAR buffer[PRCHNK];
     INT i,nbytes;
     USHORT nowtim,snccon;
     struct autsns *aush;
     INT alldone;

     nbytes=btuica(usrnum,buffer,PRCHNK);
     nowtim=(USHORT)(hrtval()>>12);
     snccon=max(1,nowtim-austim[usrnum]);
     alldone=1;
     if (snccon < auswait) {
          for (i=0,aush=aushandlers ; i < numaus ; i++,aush++) {
               if (!aush->done[usrnum]
               && !(aush->done[usrnum]=aush->aushdl(snccon,buffer,nbytes))) {
                    alldone=0;
               }
          }
          if (!gcspaus(snccon,buffer,nbytes)) {
               alldone=0;
          }
          alldone=alldone && btuoba(usrnum) == OUTSIZ-1;
     }
     if (alldone) {
          btutrg(usrnum,0);
          btuclo(usrnum);
     }
     return(alldone);
}

VOID
setbyprot(          /* vote on a certain protocol (by language name suffix) */
CHAR *prot,     /* this protocol suffix should include slash, as in "/ANSI" */
CHAR value)
{
     INT ilingo;

     for (ilingo=0 ; ilingo < nlingo ; ilingo++) {
          if (samend(languages[ilingo]->name,prot)) {
               poslng[usrnum*nlingo+ilingo]=value;
          }
     }
}

INT
cntcand(VOID)            /* count language candidates remaining, in numcand */
{                                       /* earliest one captured in fstcand */
     INT ilingo;
     CHAR thispos;

     fstcand=numcand=0;
     maxcand=0;
     for (ilingo=0 ; ilingo < nlingo ; ilingo++) {
          if ((thispos=poslng[usrnum*nlingo+ilingo]) > maxcand) {
               numcand=1;
               fstcand=ilingo;
               maxcand=thispos;
          }
          else if (maxcand > 0 && thispos == maxcand) {
               numcand++;
          }
     }
     return(numcand);
}

INT
lngposn(chc)                        /* find possible language at position n */
INT chc;                                             /* choice, 1..nchoices */
{                                        /* returns 0..nlingo-1 or -1=error */
     INT ilingo;
     CHAR maxpos,thispos;

     maxpos=0;
     for (ilingo=0 ; ilingo < nlingo ; ilingo++) {
          if ((thispos=poslng[usrnum*nlingo+ilingo]) > maxpos) {
               maxpos=thispos;
          }
     }
     for (ilingo=0 ; ilingo < nlingo ; ilingo++) {
          if (poslng[usrnum*nlingo+ilingo] == maxpos) {
               if (--chc == 0) {
                    return(ilingo);
               }
          }
     }
     return(-1);
}
