/***************************************************************************
 *                                                                         *
 *   POLLAPI.CPP                                                           *
 *                                                                         *
 *   Copyright (c) 1997 Galacticomm, Inc.                                  *
 *                                                                         *
 *                                                                         *
 *   Poll API Class.                                                       *
 *                                                  - N.C. Osterc  9/11/98 *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "pollapi.h"
#include "majorbbs.h"

#define FILREV "$Revision: 18 $"

#define PREF_FRAMES   0x00000001   // frames are on
#define PREF_NOFRAMES 0x00000002   // frames off

#define AHMODNAME     "AH Polls"   // module name - for storing in generic db

bool g_mapsInited=false;                // have maps been inited?
VOID (*oldMod)(const struct polldata);  // old vector

VOID
updateMap(                              // update map
const struct polldata pdata);

CLSDATEMMAP g_mMapClose;           // map of close dates
CRTDATEMMAP g_mMapCreate;          // map of create dates

struct webSettings {
     CHAR userid[UIDSIZ];          // userid
     CHAR modnam[MNMSIZ];          // module (see AHMODNAME)
     LONG flags;                   // flags
} g_webSets;

MARKSOURCE(pollapi);

pollAPI::pollAPI() : m_pollPtr(NULL),  // default constructor
                     m_pQueue(NULL),
                     m_curAnswer(0)
{
     m_pQueue=new POLLQUEUE;
     m_pollPtr=NULL;
}

pollAPI::~pollAPI()                // destructor
{
     deletePollPtr();
     emptyQueue();
     if (m_pQueue != NULL) {
          delete m_pQueue;
     }
}

bool
pollAPI::isPoll(                   // is this a valid poll?
const CHAR *pollname)
{
     ASSERT(pollname != NULL);

     bool valid=false;

     dfaSetBlk(pbb);
     if (dfaQueryEQ(pollname,0)) {
          valid=true;
     }
     dfaRstBlk();
     return(valid);
}

bool
pollAPI::resetAnswers(
const CHAR *pollname)
{
     bool done=false;
     ASSERT(isPoll(pollname));

     poll *p=new poll(pollname);
     struct pollstat pStat;

     if (m_curAnswer >= MAXQUES) {
          dfaSetBlk(sbb);
          m_savPos=dfaAcqEQ(&pStat,p->getName(),2) ? dfaAbs() : 0L;
          dfaRstBlk();
          if (clearTallyAndStat(pStat,p)) {
               m_curAnswer=0;
               done=true;
          }
     }
     else {
          cupacomp cleanCompKey;
          cleanCompKey.qnum=m_curAnswer;
          stzcpy(cleanCompKey.pollname,p->getName(),PNAMELEN);
          dfaSetBlk(abb);
          if (dfaAcqEQ(&m_adata,&cleanCompKey,1)) {
               dfaDelete();
          }
          else {
               ++m_curAnswer;
          }
          dfaRstBlk();
     }
     return(done);
}

bool
pollAPI::clearTallyAndStat(
struct pollstat pStat,
poll *p)
{
     bool done=false;
     dfaSetBlk(sbb);
     if (dfaAcqAbsLock(&pStat,m_savPos,2,0)) {
          dfaDelete();
          if (dfaAcqNX(&pStat)) {
               m_savPos=dfaAbs();
          }
     }
     else {
          dfaSetBlk(tbb);
          if (dfaAcqEQ(NULL,p->getName(),0)) {
               dfaDelete();
          }
          dfaRstBlk();
          done=true;
     }
     dfaRstBlk();
     return(done);
}

const CHAR *
pollAPI::getPollNameHi()
{
     static struct polldata pdata;
     setmem(&pdata,sizeof(struct polldata),0);
     dfaSetBlk(pbb);
     if (dfaQueryHI(0)) {
          dfaAbsRec(&pdata,0);
     }
     dfaRstBlk();
     return(pdata.pname);
}

poll *
pollAPI::getPollEQ(                // get poll by name
const CHAR *pollname)
{
     ASSERT(pollname != NULL);

     deletePollPtr();
     if (isPoll(pollname)) {
          m_pollPtr=new poll(pollname);
     }
     return(m_pollPtr);
}

poll *
pollAPI::getPollGE(                // get poll greater-equal than string speced
const CHAR *startString)
{
     ASSERT(startString != NULL);

     deletePollPtr();
     dfaSetBlk(pbb);
     if (dfaAcqGE(&m_pdata,startString,0)) {
          m_pollPtr=new poll(m_pdata.pname);
     }
     dfaRstBlk();
     return(m_pollPtr);
}

poll *
pollAPI::getPollGT(                // get poll greater than string speced
const CHAR *startString)
{
     ASSERT(startString != NULL);

     deletePollPtr();
     dfaSetBlk(pbb);
     if (dfaAcqGT(&m_pdata,startString,0)) {
          m_pollPtr=new poll(m_pdata.pname);
     }
     dfaRstBlk();
     return(m_pollPtr);
}

poll *
pollAPI::getPollLE(                // get poll less-than-or-equal to string spc
const CHAR *startString)
{
     ASSERT(startString != NULL);

     deletePollPtr();
     dfaSetBlk(pbb);
     if (dfaAcqLE(&m_pdata,startString,0)) {
          m_pollPtr=new poll(m_pdata.pname);
     }
     dfaRstBlk();
     return(m_pollPtr);
}

poll *
pollAPI::getPollLT(                // get poll less than string specified
const CHAR *startString)
{
     ASSERT(startString != NULL);

     deletePollPtr();
     dfaSetBlk(pbb);
     if (dfaAcqLT(&m_pdata,startString,0)) {
          m_pollPtr=new poll(m_pdata.pname);
     }
     dfaRstBlk();
     return(m_pollPtr);
}

VOID
pollAPI::setFrames(                // turn frames on/off for user
bool on,
const CHAR *userid)
{
     ASSERT(userid != NULL);
     LONG flags;

     getSettings(&flags,userid);

     if (on) {
          flags&=~PREF_NOFRAMES;
          flags|=PREF_FRAMES;
     }
     else {
          flags|=PREF_NOFRAMES;
          flags&=~PREF_FRAMES;
     }
     g_webSets.flags=flags;
     stlcpy(g_webSets.userid,userid,UIDSIZ);
     stlcpy(g_webSets.modnam,AHMODNAME,MNMSIZ);
     dfaSetBlk(genbb);
     if (dfaAcqEQ(NULL,&g_webSets,0)) {
          dfaUpdateV(&g_webSets,sizeof(struct webSettings));
     }
     else {
          dfaInsertV(&g_webSets,sizeof(struct webSettings));
     }
     dfaRstBlk();
}

bool
pollAPI::getSettings(              // get stored settings
LONG *settings,                   // where to put settings flag
const CHAR *userid)                // for which user?
{
     ASSERT(userid != NULL);
     bool retval=false;

     setmem(&g_webSets,sizeof(struct webSettings),0);
     stlcpy(g_webSets.userid,userid,UIDSIZ);
     stlcpy(g_webSets.modnam,AHMODNAME,MNMSIZ);
     dfaSetBlk(genbb);
     if (dfaAcqEQ(&g_webSets,&g_webSets,0)) {
          retval=true;
     }
     *settings=g_webSets.flags;
     dfaRstBlk();
     return(retval);
}

bool
pollAPI::userFramesOn(             // are frames on for user?
const CHAR *userid)
{
     ASSERT(userid != NULL);
     LONG flags;

     getSettings(&flags,userid);
     return(flags&PREF_FRAMES);
}

bool
pollAPI::userFramesOff(             // are frames off for user?
const CHAR *userid)
{
     ASSERT(userid != NULL);
     LONG flags;

     getSettings(&flags,userid);
     return(flags&PREF_NOFRAMES);
}

VOID
pollAPI::deletePollPtr()           // delete m_pollPtr, set to NULL
{
     if (m_pollPtr != NULL) {
          delete m_pollPtr;
          m_pollPtr=NULL;
     }
}

VOID
pollAPI::pushBackQueue(            // push back poll object
const CHAR *pollname)
{
     ASSERT(pollname != NULL);
     if (m_pQueue != NULL) {
          m_pQueue->push_back(pollname);
     }
}

VOID
pollAPI::pushFrontQueue(           // push front poll object
const CHAR *pollname)
{
     ASSERT(pollname != NULL);
     if (m_pQueue != NULL) {
          m_pQueue->push_front(pollname);
     }
}

PPOLLQUEUE
pollAPI::getQueuePtr()             // get built queue
{
     return(m_pQueue);
}

const CHAR *                       // poll name or NULL
pollAPI::getDateGT(                // is there a poll greater?
const CHAR *pollname,              // pollname
bool create,                       // create or close?
USHORT date)                       // poll date
{
     if (pollname != NULL && pollname[0] != '\0') {
          mapCompare mcomp(pollname,date);

          if (create) {
               if ((m_cri=g_mMapCreate.find(mcomp)) != g_mMapCreate.end()) {
                    ++m_cri;
                    if (m_cri != g_mMapCreate.end()) {
                         return((*m_cri).second);
                    }
               }
          }
          else {
               if ((m_cli=g_mMapClose.find(mcomp)) != g_mMapClose.end()) {
                    ++m_cli;
                    if (m_cli != g_mMapClose.end()) {
                         return((*m_cli).second);
                    }
               }
          }
     }
     else {  // passed in no pollname - brute force look-up
          if (create) {
               for (m_cri=g_mMapCreate.begin(); m_cri != g_mMapCreate.end()
                ; m_cri++) {
                    if (((*m_cri).first).getDate() > date) {
                         return((*m_cri).second);
                    }
               }
          }
          else {
               for (m_cli=g_mMapClose.begin(); m_cli != g_mMapCreate.end()
                ; m_cli++) {
                    if (((*m_cli).first).getDate() > date) {
                         return((*m_cli).second);
                    }
               }
          }
     }
     return(NULL);
}

const CHAR *                       // poll name or NULL
pollAPI::getDateGE(                // is there a poll greater-than-equal
bool create,                       // create or close?
USHORT date)                       // poll date
{
     if (create) {
          for (m_cri=g_mMapCreate.begin(); m_cri != g_mMapCreate.end()
               ; m_cri++) {
               if (((*m_cri).first).getDate() >= date) {
                    return((*m_cri).second);
               }
          }
     }
     else {
          for (m_cli=g_mMapClose.begin(); m_cli != g_mMapCreate.end()
               ; m_cli++) {
               if (((*m_cli).first).getDate() >= date) {
                    return((*m_cli).second);
               }
          }
     }
     return(NULL);
}


const CHAR *                       // poll name or NULL
pollAPI::getDateLT(                // is there a poll less?
const CHAR *pollname,              // poll name
bool create,                       // close or create?
USHORT date)                       // poll date
{
     if (pollname != NULL && pollname[0] != '\0') {
          mapCompare mcomp(pollname,date);
          if (create) {
               if ((m_cri=g_mMapCreate.find(mcomp)) != g_mMapCreate.end()
                && m_cri != g_mMapCreate.begin()) {
                    --m_cri;
                    return((*m_cri).second);
               }
          }
          else {
               if ((m_cli=g_mMapClose.find(mcomp)) != g_mMapClose.end()
                && m_cli != g_mMapClose.begin()) {
                    --m_cli;
                    return((*m_cli).second);
               }
          }
     }
     else {  // passed in no pollname - brute force look-up
          if (create) {
               for (m_cri=g_mMapCreate.end(), --m_cri
                ; m_cri != g_mMapCreate.begin()
                ; m_cri--) {
                    if (((*m_cri).first).getDate() < date) {
                         return((*m_cri).second);
                    }
               }
          }
          else {
               for (m_cli=g_mMapClose.end(), --m_cli
                ; m_cli != g_mMapCreate.begin()
                ; m_cli--) {
                    if (((*m_cli).first).getDate() < date) {
                         return((*m_cli).second);
                    }
               }
          }
     }
     return(NULL);
}

const CHAR *                       // poll name or NULL
pollAPI::getDateLE(                // is there a poll less-than-equal
bool create,                       // close or create?
USHORT date)                       // poll date
{
     if (create) {
          for (m_cri=g_mMapCreate.end(), --m_cri
               ; m_cri != g_mMapCreate.begin()
               ; m_cri--) {
               if (((*m_cri).first).getDate() <= date) {
                    return((*m_cri).second);
               }
          }
     }
     else {
          for (m_cli=g_mMapClose.end(), --m_cli
               ; m_cli != g_mMapCreate.begin()
               ; m_cli--) {
               if (((*m_cli).first).getDate() <= date) {
                    return((*m_cli).second);
               }
          }
     }
     return(NULL);
}

const CHAR *                       // poll name or NULL
pollAPI::getDateEQ(                // is there a poll equal
const CHAR *pollname,              // pollname
bool create,                       // create or close?
USHORT date)                       // poll date
{
     ASSERT(pollname != NULL);
     mapCompare mcomp(pollname,date);

     if (create) {
          if ((m_cri=g_mMapCreate.find(mcomp)) != g_mMapCreate.end()) {
               return((*m_cri).second);
          }
     }
     else {
          if ((m_cli=g_mMapClose.find(mcomp)) != g_mMapClose.end()) {
               return((*m_cli).second);
          }
     }
     return(NULL);
}

const CHAR *
pollAPI::pollDateLow(              // get poll w/ lowest date
bool create)
{
     if (create && !g_mMapCreate.empty()) {
          m_cri=g_mMapCreate.begin();
          return((*m_cri).second);
     }
     else if (!g_mMapClose.empty()) {
          m_cli=g_mMapClose.begin();
          return((*m_cli).second);
     }
     return(NULL);
}

const CHAR *
pollAPI::pollDateHi(               // get poll w/ highest date
bool create)
{
     if (create && !g_mMapCreate.empty()) {
          m_cri=g_mMapCreate.end();
          --m_cri;
          return((*m_cri).second);

     }
     else if (!g_mMapClose.empty()) {
          m_cli=g_mMapClose.end();
          --m_cli;
          return((*m_cli).second);
     }
     return(NULL);
}

VOID
pollAPI::emptyQueue()              // empty the queue
{
     ASSERT(m_pQueue != NULL);

     while (!m_pQueue->empty()) {
          delete m_pQueue->back();
          m_pQueue->pop_back();
     }
}

VOID
pollAPI::initMaps()                // initialize maps
{
     if (g_mapsInited) {
          return;
     }
     struct polldata pdata;
     dfaSetBlk(pbb);
     if (dfaAcqLO(&pdata,0)) {
          do {
               mapCompare mclose(pdata.pname,pdata.closedate);
               pair<mapCompare,CHAR *> cloPair(mclose,strdup(pdata.pname));
               g_mMapClose.insert(cloPair);
               mapCompare mcreate(pdata.pname,pdata.createdate);
               pair<mapCompare,CHAR *> crtPair(mcreate,strdup(pdata.pname));
               g_mMapCreate.insert(crtPair);
          } while (dfaAcqGT(&pdata,pdata.pname,0));
     }
     dfaRstBlk();
     g_mapsInited=true;
}

VOID
updateMap(                         // handle a poll modification/addition
const struct polldata pdata)
{
     CLSDATEMMAP::iterator p;
     mapCompare mComp(pdata.pname,pdata.closedate);

     if (g_mMapClose.find(mComp) == g_mMapClose.end()) {
          // if this is true, poll closedate changed or new poll

          for (p=g_mMapClose.begin(); p != g_mMapClose.end(); p++) {
               if (sameas((*p).second,pdata.pname)) {
#ifdef DEBUG
                    shocst("PNQ ERASING MAP ENTRY","Erasing %s",pdata.pname);
#endif
                    g_mMapClose.erase(p,p);
               }
          }
#ifdef DEBUG
            shocst("PNQ ADDING to MAP","Adding: %s",pdata.pname);
#endif
            mapCompare mClose(pdata.pname,pdata.closedate);
            pair<mapCompare,CHAR *> cloPair(mClose,strdup(pdata.pname));
            g_mMapClose.insert(cloPair);
            mapCompare mCreate(pdata.pname,pdata.createdate);
            pair<mapCompare,CHAR *> crtPair(mCreate,strdup(pdata.pname));
            g_mMapCreate.insert(crtPair);
     }
     if (oldMod != NULL) {
          (*oldMod)(pdata);
     }
}

