/***************************************************************************
 *                                                                         *
 *   SYNLLIBS.CPP                                                          *
 *                                                                         *
 *   Copyright (c) 1998       Galacticomm, Inc.    All Rights Reserved.    *
 *                                                                         *
 *   Active HTML File List Libraries Synthesis                             *
 *   Implementation                                                        *
 *                                                                         *
 *                                                - Phil Henning 10/16/98  *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "majorbbs.h"
#include "galacth.h"
#include "dnf.h"
#include "dnfmgr.h"
#include "ahutil.h"
#include "filtvb.h"
#include "synllibs.h"
#include "filagent.h"
#include "galfilah.h"

#define FILREV "$Revision: 6 $"

enum {LSTITEM};

static
dnfStep dnfSuccessSteps[]={
     dnfStep(DNFTABLE),
       dnfStep(DNFCOLUMN,LSTITEM,"LISTITEM"),
     dnfStep(DNFTABLEEND),
     dnfStep(DNFMAPEND)
};
static
dnfMap filSuccessMap(PPFIX "/list/libs/index.htm","Success Response",dnfSuccessSteps);

static
dnfStep dnfErrorSteps[]={
     dnfStep(DNFMAPEND)
};
static
dnfMap filErrorMap(PPFIX "/list/libs/error.htm","Error Response",dnfErrorSteps);

//
//  List Libs Synthesis Member Functions
//

MARKSOURCE(synllibs);

synListLibs::synListLibs(
acthSession* _ses,
bool anonok,
INT lvlcnt)   : synBaseAuth(_ses,anonok,theFilAgent->m_hfilkey,lvlcnt)
              , m_listAccess(LIST_ALL)
              , m_listType(TYPE_ALL)
              , m_listOrder(ORDER_ASCEND)
              , m_listDirection(DIR_GE)
              , m_listCount(theFilAgent->m_dftlst)
              , m_curCount(0)
              , m_listAll(false)
              , m_started(false)
              , m_moreLow(false)
              , m_moreHigh(false)
              , m_flParent(NULL)
              , m_allDone(false)


{
     memset(&m_fllib,0,sizeof(struct fllib));
}

synListLibs::~synListLibs()
{
}


ACTHCODE
synListLibs::proceedRequest()           // setup request context
{
     ACTHCODE rc=synBaseAuth::proceedRequest();
     bool bOrderChanged=false;

     if (rc != ACTHMORE) {
          return(rc);
     }
     if (ses->param("access")) {
          INT sz=ses->paramRoom("access");
          CHAR* val=new CHAR[sz];
          ses->param("access",val,sz);
          if (strlen(val) == 1) {
               switch (*val) {
               case 'd':
               case 'D':
                    m_listAccess=LIST_DOWNLOAD;
                    break;
               case 'u':
               case 'U':
                    m_listAccess=LIST_UPLOAD;
                    break;
               case 'a':
               case 'A':
                    m_listAccess=LIST_ADMIN;
                    break;
               default:
                    m_err=ERR_INVALIDPARAM;
                    m_errtext="access";
               }
          }
          else {
               m_err=ERR_INVALIDPARAM;
               m_errtext="access";
          }
          delete [] val;
     }
     if (m_err == ERR_NOERROR && ses->param("type")) {
          INT sz=ses->paramRoom("type");
          CHAR* val=new CHAR[sz];
          ses->param("type",val,sz);
          if (strlen(val) > 0) {
               if (sameas(val,"normal")) {
                    m_listType=TYPE_NORMAL;
               }
               else if (sameas(val,"os")) {
                    m_listType=TYPE_OS;
               }
               else {
                    m_err=ERR_INVALIDPARAM;
                    m_errtext="type";
               }
          }
          delete [] val;
     }
     if (m_err == ERR_NOERROR && ses->param("parent")) {
          INT sz=ses->paramRoom("parent");
          CHAR* val=new CHAR[sz];
          ses->param("parent",val,sz);
          if (strlen(val) > 0) {
               m_flParent=libfind(val);
               if (m_flParent == NULL) {
                    m_err=ERR_INVALIDLIB;
                    m_errtext=val;
               }
          }
          delete [] val;
     }
     if (m_err == ERR_NOERROR) {
          bool bIsAuth=(m_usr != NULL);
          m_listOrder=LoadDftOrder(m_usr == NULL ? NULL : m_usr->userid());
          if (ses->param("order")) {
               INT sz=ses->paramRoom("order");
               CHAR* val=new CHAR[sz];
               ses->param("order",val,sz);
               if (sameas(val,"~ascending") || sameas(val,"descending")) {
                    m_listOrder=ORDER_DESC;
               }
               else if (sameas(val,"~ascending set") || sameas(val,"descending set")) {
                    m_listOrder=ORDER_DESC;
                    bOrderChanged=bIsAuth;
               }
               else if (sameas(val,"~descending") || sameas(val,"ascending")) {
                    m_listOrder=ORDER_ASCEND;
               }
               else if (sameas(val,"~descending set") || sameas(val,"ascending set")) {
                    m_listOrder=ORDER_ASCEND;
                    bOrderChanged=bIsAuth;
               }
               else if (sameas(val,"~")) {
                    m_listOrder=(m_listOrder == ORDER_DESC ? ORDER_ASCEND : ORDER_DESC);
               }
               else if (sameas(val,"~ set")) {
                    m_listOrder=(m_listOrder == ORDER_DESC ? ORDER_ASCEND : ORDER_DESC);
                    bOrderChanged=bIsAuth;
               }
               else {
                    m_err=ERR_INVALIDPARAM;
                    m_errtext="order";
               }
               delete [] val;
          }
     }
     if (m_err == ERR_NOERROR && ses->param("all")) {
          m_listAll=true;
     }
     if (m_err == ERR_NOERROR && !m_listAll) {
          if (ses->param("start")) {
               INT sz=ses->paramRoom("start");
               CHAR* val=new CHAR[sz];
               ses->param("start",val,sz);
               if (strlen(val) > 0) {
                    m_strStart=val;
               }
               delete [] val;
          }
          if (m_err == ERR_NOERROR && ses->param("direction")) {
               INT sz=ses->paramRoom("direction");
               CHAR* val=new CHAR[sz];
               ses->param("direction",val,sz);
               if (sameas(val,"gt")) {
                    m_listDirection=DIR_GT;
               }
               else if (sameas(val,"ge")) {
                    m_listDirection=DIR_GE;
               }
               else if (sameas(val,"lt")) {
                    m_listDirection=DIR_LT;
               }
               else if (sameas(val,"le")) {
                    m_listDirection=DIR_LE;
               }
               else {
                    m_err=ERR_INVALIDPARAM;
                    m_errtext="direction";
               }
               delete [] val;
          }
          if (m_err == ERR_NOERROR && ses->param("count")) {
               INT sz=ses->paramRoom("count");
               CHAR* val=new CHAR[sz];
               ses->param("count",val,sz);
               if (strlen(val) > 0) {
                    INT tmpcnt=atoi(val);
                    if (tmpcnt > 0) {
                         m_listCount=min(tmpcnt,theFilAgent->m_maxlst);
                    }
               }
               delete [] val;
          }
     }
     m_SynState=((m_err == ERR_NOERROR) ? SYNSTATE_SYNTH : SYNSTATE_RESPONSE);
     if (m_err == ERR_NOERROR && bOrderChanged) {
          SaveDftOrder(m_usr == NULL ? NULL : m_usr->userid(),m_listOrder);
     }
     return(rc);
}

ACTHCODE
synListLibs::proceedSynth()             // proceed with synthesis
{

     if (m_SynSubState == SYNSUB_BUILDMAP) {
          buildMap();
     }
     else {
          buildContext() ;
          m_SynState=SYNSTATE_RESPONSE;
     }
     return(ACTHMORE);
}

VOID
synListLibs::buildContext()             // build list context
{
     if (!m_queue.empty()) {
          struct fllib Lib;
          struct fllib* pLib;
          Lib=m_queue.front();
          m_strLowLib=Lib.libname;
          string strSearch=m_strLowLib;
          while ((pLib=nextlow(strSearch.c_str())) != NULL) {
               if (okToAdd(pLib)) {
                    m_moreLow=true;
                    break;
               }
               else {
                    strSearch=pLib->libname;
               }
          }
          Lib=m_queue.back();
          m_strHighLib=Lib.libname;
          strSearch=m_strHighLib;
          while ((pLib=nexthigh(strSearch.c_str())) != NULL) {
               if (okToAdd(pLib)) {
                    m_moreHigh=true;
                    break;
               }
               else {
                    strSearch=pLib->libname;
               }
          }
     }
     else {
          struct fllib* pLib;
          m_strLowLib=m_strStart;
          string strSearch=m_strStart;
          while ((pLib=nextlow(strSearch.c_str())) != NULL) {
               if (okToAdd(pLib)) {
                    m_moreLow=true;
                    break;
               }
               else {
                    strSearch=pLib->libname;
               }
          }
          m_strHighLib=m_strStart;
          strSearch=m_strStart;
          while ((pLib=nexthigh(strSearch.c_str())) != NULL) {
               if (okToAdd(pLib)) {
                    m_moreHigh=true;
                    break;
               }
               else {
                    strSearch=pLib->libname;
               }
          }
     }
}

VOID
synListLibs::buildMap()                 // build list map
{
     struct fllib* pLib=NULL;

     if (!m_listAll && m_curCount >= m_listCount) {
          m_SynSubState=SYNSUB_LISTCONTEXT;
          return;
     }
     *(m_fllib.libname)='\0';
     if (!m_started) {
          m_strLast=m_strStart;
     }
     if (!m_started && !m_listAll && (m_listDirection&DIR_EQ)) {
          pLib=libfind(m_strStart.c_str());
          if (pLib != NULL) {
               memmove(&m_fllib,pLib,sizeof(struct fllib));
               if (okToAdd(&m_fllib)) {
                    ++m_curCount;
                    m_strLast=m_fllib.libname;
                    addToQueue();
               }
          }
     }
     else if ((m_listDirection&DIR_GT) || (m_listDirection&DIR_LT) || m_listAll) {
          while (1) {
               if (m_listAll) {
                    if (!m_started && m_listOrder == ORDER_DESC) {
                         m_curCount=numoflib-1;
                         m_started=true;
                    }
                    if (m_curCount >=0 && m_curCount < numoflib) {
                         pLib=liboff(m_curCount);
                         m_curCount=(m_listOrder == ORDER_DESC ? m_curCount - 1
                                                               : m_curCount + 1);
                    }
                    else {
                         break;
                    }
               }
               else if (m_listDirection&DIR_GT) {
                    pLib=nexthigh(m_strLast.c_str());
               }
               else if (m_listDirection&DIR_LT) {
                    pLib=nextlow(m_strLast.c_str());
               }
               else {
                    break;
               }
               if (pLib != NULL) {
                    memmove(&m_fllib,pLib,sizeof(struct fllib));
                    m_strLast=m_fllib.libname;
                    if (okToAdd(&m_fllib)) {
                         if (!m_listAll) {
                              addToQueue();
                              ++m_curCount;
                         }
                         break;
                    }
                    else {
                         *(m_fllib.libname)='\0';
                    }
               }
               else {
                    *(m_fllib.libname)='\0';
                    break;
               }
          }
     }
     if (m_listAll) {
          m_SynState=SYNSTATE_RESPONSE;
     }
     else if (pLib == NULL && m_started) {
          m_SynSubState=SYNSUB_LISTCONTEXT;
     }
     m_started=true;
}

ACTHCODE
synListLibs::proceedDerivedResponse()   // proceed with response
{
     ACTHCODE rc=ACTHMORE;

     if (m_err != ERR_NOERROR) {
          if (m_dnf == NULL) {
               rc=errorResponse(filErrorMap,PPFIX "/list/libs/");
          }
          else if (m_dnf->process() == DNFEND) {
               rc=ACTHDONE;
          }
          return(rc);
     }
     if (m_dnf == NULL) {
          m_dnf=dnfCreateHandlerURL(ses,&filSuccessMap,PPFIX);
     }
     else {
          if (!m_listAll) {
               ::setListContextVars(m_listCount,m_listOrder,m_strLowLib.c_str()
                                   ,m_strHighLib.c_str(),m_moreLow,m_moreHigh
                                   ,(m_curCount > 0) != 0,LTYPE_LIB);

          }
          else {
               ::setListContextVars(0,ORDER_DESC,"","",false,false
                                   ,(m_curCount > 0) != 0,LTYPE_LIB);
          }
          ::setListLibContextVars(m_listAccess,m_listType
                         ,m_flParent == NULL ? "" : m_flParent->libname);

          if (!m_listAll || m_allDone) {
               ::setNoList(m_curCount != 0,g_pszNoListLib);
          }
          if (*(m_fllib.libname) != '\0') {
               ::setLibVars(&m_fllib,m_usr);
          }
          switch(m_dnf->process()) {
          case DNFROWBEGIN:
               if (!m_listAll && !m_queue.empty()) {
                    if (m_listOrder == ORDER_ASCEND) {
                         m_fllib=m_queue.front();
                         m_queue.pop_front();
                    }
                    else {
                         m_fllib=m_queue.back();
                         m_queue.pop_back();
                    }
               }
               if (*(m_fllib.libname) == '\0') {
                    m_dnf->tableDone();
                    m_allDone=m_listAll;
               }
               break;
          case LSTITEM:
               break;
          case DNFROWEND:
               if (m_listAll) {
                    m_SynState=SYNSTATE_SYNTH;
               }
               *(m_fllib.libname)='\0';
               break;
          case DNFEND:
               rc=ACTHDONE;
               break;
          default:
               break;
          }
     }
     return(rc);
}

bool
synListLibs::okToAdd(                   // ok to add this lib
const struct fllib* pLib)               // lib to add
{
     if (m_listAccess == LIST_ALL) {
          if (m_usr == NULL) {
               if (strlen(pLib->keyreq) != 0) {
                    return(false);
               }
          }
          else if (!ahHasLibKey(m_usr,pLib,pLib->keyreq)) {
               return(false);
          }
     }
     if (m_listAccess == LIST_DOWNLOAD
      && !ahHasLibKey(m_usr,pLib,pLib->dlkey)) {
          return(false);
     }
     if (m_listAccess == LIST_UPLOAD
      && !ahHasLibKey(m_usr,pLib,pLib->ulkey)) {
          return(false);
     }
     if (m_listAccess == LIST_ADMIN
      && !ahIsFlop(m_usr,pLib)) {
          return(false);
     }
     if (m_listType == TYPE_NORMAL && (pLib->flags&FLGDOS)) {
          return(false);
     }
     if (m_listType == TYPE_OS && !(pLib->flags&FLGDOS)) {
          return(false);
     }
     if ((pLib->flags&FLGHID) && !ahIsFlop(m_usr,pLib)) {
          return(false);
     }
     if (m_flParent != NULL) {
          return(isChildOf(m_flParent->libname,pLib));
     }
     return(true);
}

VOID
synListLibs::addToQueue()               // add to queue
{
     if (m_listDirection&DIR_GT) {
          m_queue.push_back(m_fllib);
     }
     else {
          m_queue.push_front(m_fllib);
     }
}


INT
synListLibs::translateError()           // translate err to mcv file op
{
     switch (m_err) {
     case ERR_INVALIDLIB:
          return(ERRLL03);
     case ERR_INVALIDPARAM:
          return(ERRLL02);
     default:
          ASSERT(FALSE);
     }
     m_errtext=spr("%d",m_err);
     return(ERROOPS);
}


