/***************************************************************************
 *                                                                         *
 *   UIESYN.CPP                                                            *
 *                                                                         *
 *   Copyright (c) 1997 Galacticomm, Inc.                                  *
 *                                                                         *
 *                                                                         *
 *   Account Synthesis Class.                                              *
 *                                                  - N.C. Osterc 10/26/98 *
 *                                                                         *
 ***************************************************************************/

#include "uiesyn.h"
#include "uiemsg.h"
#include "galuieah.h"
#include "ahutil.h"
#include <cstring>

#define FILREV "$Revision: 9 $"
#define ISSAVE (ISPARAM("save"))
#define MINWIDTH   40
#define MAXWIDTH   136
#define MAXLINES   255
#define MINLINES   2
#define CONTOUTPUT 2

// Dynafile defs

enum {PARAMS, RESPONSE, LANGITEM};

INT errArray[ERR_HIGHERROR]={ERROOPS,ERR01,ERR02,ERR03,ERR04,ERR05,ERR06
                            ,ERR07,ERR08,ERR09,ERR10,ERR11,ERR12,ERR13};

dnfStep dnfDefTableSteps[]={
     dnfStep(DNFTABLE),
          dnfStep(DNFCOLUMN,LANGITEM,"LISTITEM"),
     dnfStep(DNFTABLEEND),
     dnfStep(DNFMAPEND)
};

dnfStep dnfConfSteps[]={
     dnfStep(DNFMAPEND)
};

dnfStep dnfErrSteps[]={
     dnfStep(DNFMAPEND)
};

dnfMap defTableMap(PPFIX "/index.htm","Default w/table",dnfDefTableSteps);
dnfMap dnfConfMap(PPFIX "/confirm.htm","Confirmed save",dnfConfSteps);
dnfMap dnfErrMap(PPFIX "/error.htm","Error",dnfErrSteps);

// class method defs

MARKSOURCE(uieSyn);

uieSynthesis::uieSynthesis(        // default constructor
               acthSession *_ses):
               acthSynthesis(_ses),
               m_usrPtr(NULL),
               m_dnfPtr(NULL),
               m_pTvb(NULL),
               m_err(ERR_NOERROR),
               m_langvar(""),
               m_succRedir(false),
               m_errRedir(false),
               m_onsuccessFile(NULL),
               m_errParam(NULL),
               m_onerrorFile(DFTERROR)
{
     m_pTvb=new uieVar();
     m_cyc.setSlice(timslc);
     m_pValBuf[0]='\0';
     m_ahState=PARAMS;
     memset(&m_usrext, 0, sizeof(uaccext));
}

uieSynthesis::~uieSynthesis()      // destructor
{
     if (m_dnfPtr != NULL) {
          delete m_dnfPtr;
     }
     if (m_pTvb != NULL) {
          delete m_pTvb;
     }
     if (m_onsuccessFile != NULL) {
          delete [] m_onsuccessFile;
     }
     if (m_errParam != NULL) {
          delete [] m_errParam;
     }

}

ACTHCODE
uieSynthesis::initRequest()        // take care of stuff for init request
{
     if ((strchr(ses->urlsfx(),'.')) == NULL) {
          if (ses->forceDir()) {
               return(ACTHDONE);
          }
     }
     if (!m_templInit) {
          initTemplates();
          m_templInit=true;
     }
     m_pTvb->setVarsDefault();
     return(ACTHMORE);
}

ACTHCODE
uieSynthesis::isUserOK()           // check some basic stuff about user and session
{
     if ((m_usrPtr=ses->getUser()) == NULL) {
          return(ACTHNOANON);
     }
     if (!hasAgentAccess()) {
          return(ACTHFORBID);
     }
     return(initRequest());
}

VOID
uieSynthesis::setMap(              // set up m_dnfptr to appropriate map
dnfMap *map)
{
     m_dnfPtr=dnfCreateHandlerURL(ses,map,PPFIX "/");
}

ACTHCODE
uieSynthesis::proceed()            // proceed entry point
{
     ACTHCODE retval;

     if (ses->urlargc() > 0 && strchr(ses->urlargv(0),'.') == NULL) {
          return(ACTHNOTFND);
     }
     if ((retval=isUserOK()) != ACTHMORE) {
          return(retval);
     }

     if (m_cyc.start()) {
          do {
               switch (m_ahState) {
               case PARAMS:
                    m_usrAccPtr=GetAccPtr(m_usrPtr->userid());
                    movmem(m_usrAccPtr,&m_account,sizeof(struct usracc));
                    m_ahState=RESPONSE;
                    if (ses->param("save")) {
                         if (getNameParam() && getCompanyParam()
                          && getAddress1Param() && getAddress2Param()
                          && getCountryParam() && getPhoneParam()
                          && getWidthParam() && getLinesParam()
                          && getComputerParam() && getSexParam()
                          && getAnsiParam() && getOutputParam()
                          && getEditorParam() && getLangParam()
                          && getPasswordHintParam() && getAltEmailParam()) {
                              saveAccount();
                              return(successResponse(dnfConfMap,PPFIX "/"));
                         }
                         else {
                              return(errorResponse(dnfErrMap,PPFIX "/"));
                         }
                    }
                    else {
                         setMap(&defTableMap);
                    }
                    break;
               case RESPONSE:
                    retval=dynafile();
                    break;
               }
          } while (m_cyc.haveTime() && retval != ACTHDONE);
     }
     return(retval);
}

VOID
uieSynthesis::saveAccount()        // save account info
{
     if (!onsysn(m_usrPtr->userid(),1)) {
          dfaSetBlk(accbb);
          if (dfaAcqEQ(NULL,m_usrPtr->userid(),0)) {
               dfaUpdate(&m_account);
          }
          dfaRstBlk();
     }
     else {
          movmem(&m_account,m_usrAccPtr,sizeof(struct usracc));

     }
     saveAccountExt(m_usrPtr->userid());
}

VOID
uieSynthesis::saveAccountExt(
const char *userid)
{
     ::dfaSetBlk(::dfaUserExt);
     stlcpy(m_usrext.userid, userid, UIDSIZ);
     if (dfaAcqEQ(NULL, userid, 0)) {
          dfaUpdate(&m_usrext);
     }
     else {
          dfaInsert(&m_usrext);
     }
     ::dfaRstBlk();
}

bool
uieSynthesis::checkProfan()        // check profanity
{
     (*setpfn)(m_pValBuf);
     if (pfnlvl > 1) {
          setError(ERR_PROFANE,m_paramName.c_str());
          return(false);
     }
     return(true);
}

bool
uieSynthesis::lengthOK(            // is length of string ok?
SHORT min,
SHORT max)
{
     if (strlen(m_pValBuf) >= max) {
          setError(ERR_TOOLONG,m_paramName.c_str(),ltoa(max-1));
          return(false);
     }
     else if (strlen(m_pValBuf) < min) {
          setError(ERR_TOOSHORT,m_paramName.c_str(),ltoa(min));
          return(false);
     }
     return(true);
}

bool
uieSynthesis::hasKey(              // does user have key?
const CHAR *key)
{
     if (!m_usrPtr->hasKey(key)) {
          setError(ERR_NOAXES,m_paramName.c_str());
          return(false);
     }
     return(true);
}

bool
uieSynthesis::getPasswordHintParam()
{
     m_paramName="passhint";

     if (GETPARAMVAL(m_paramName.c_str())) {
          if (lengthOK(0, HINTSIZ)) {
               stlcpy(m_usrext.pwdhint, m_pValBuf, HINTSIZ);
               return(true);
          }
     }
     return(false);
}

bool
uieSynthesis::getAltEmailParam()
{
     m_paramName="altemail";

     if (GETPARAMVAL(m_paramName.c_str())) {
          if (lengthOK(0, ALTEMLSIZ)) {
               stlcpy(m_usrext.alteml, m_pValBuf, ALTEMLSIZ);
               return(true);
          }
     }
     return(false);
}

bool
uieSynthesis::getNameParam()       // handle "name" param
{
     m_paramName="name";

     if (!GETPARAMVAL(m_paramName.c_str())
      || sameas(m_account.usrnam,m_pValBuf)) {
          return(true);
     }
     else if (hasKey(namchgky)
      && lengthOK((namdft == 1 || namdft == 2 ? minuid: 5),NADSIZ)
      && checkProfan()) {
          stlcpy(m_account.usrnam,m_pValBuf,NADSIZ);
          return(true);
     }
     return(false);
}

bool
uieSynthesis::getCompanyParam()    // handle "company" param
{
     m_paramName="company";
     GETPARAMVAL(m_paramName.c_str());
     if (!ISPARAM(m_paramName.c_str()) || sameas(m_account.usrad1,m_pValBuf)) {
          return(true);
     }
     else if (hasKey(comchgky) && lengthOK(0,NADSIZ) && checkProfan()) {
          stlcpy(m_account.usrad1,m_pValBuf,NADSIZ);
          return(true);
     }
     return(false);
}

bool
uieSynthesis::getAddress1Param()   // handle "address1" param
{
     m_paramName="address1";
     if (!GETPARAMVAL(m_paramName.c_str())
      || sameas(m_account.usrad2,m_pValBuf)) {
          return(true);
     }
     else if (hasKey(adrchgky) && lengthOK(5,NADSIZ) && checkProfan()) {
          stlcpy(m_account.usrad2,m_pValBuf,NADSIZ);
          return(true);
     }
     return(false);
}

bool
uieSynthesis::getAddress2Param()   // handle "Address2" param
{
     m_paramName="address2";
     GETPARAMVAL(m_paramName.c_str());
     if (!ISPARAM(m_paramName.c_str()) || sameas(m_account.usrad3,m_pValBuf)) {
          return(true);
     }
     else if (hasKey(adrchgky) && lengthOK(5,NADSIZ) && checkProfan()) {
          stlcpy(m_account.usrad3,m_pValBuf,NADSIZ);
          return(true);
     }
     return(false);
}

bool
uieSynthesis::getCountryParam()    // handle "country" param
{
     m_paramName="country";
     if (!GETPARAMVAL(m_paramName.c_str())
      || sameas(m_account.usrad4,m_pValBuf)) {
          return(true);
     }
     else if (hasKey(adrchgky) && lengthOK(0,NADSIZ) && checkProfan()) {
          stlcpy(m_account.usrad4,m_pValBuf,NADSIZ);
          return(true);
     }
     return(false);
}

bool
uieSynthesis::getPhoneParam()      // handle "phone" param
{
     m_paramName="phone";
     GETPARAMVAL(m_paramName.c_str());
     if (sameas(m_account.usrpho,m_pValBuf)) {
          return(true);
     }
     else if (hasKey(phochgky) && lengthOK(7,PHOSIZ) && checkProfan()) {
          stlcpy(m_account.usrpho,m_pValBuf,NADSIZ);
          return(true);
     }
     return(false);
}

bool
uieSynthesis::getWidthParam()      // handle "width" param
{
     m_paramName="width";
     GBOOL got=GETPARAMVAL(m_paramName.c_str());
     INT iwid=atoi(m_pValBuf);
     if (!got || m_account.scnwid == iwid) {
          return(true);
     }
     else if (!hasKey(scwchgky)) {
          return(false);
     }
     else if (iwid > MINWIDTH && iwid < MAXWIDTH) {
          m_account.scnwid=iwid;
     }
     else {
          setError(ERR_INVALID,m_paramName.c_str());
          return(false);
     }
     return(true);
}

bool
uieSynthesis::getLinesParam()      // handle "lines" param
{
     m_paramName="lines";
     GETPARAMVAL(m_paramName.c_str());
     INT ilines=atoi(m_pValBuf);
     if (m_account.scnfse == ilines) {
          return(true);
     }
     else if (hasKey(sclchgky) && ilines >= MINLINES && ilines <= MAXLINES) {
          m_account.scnfse=ilines;
     }
     else {
          setError(ERR_INVALID,m_paramName.c_str());
          return(false);
     }
     return(true);
}

bool
uieSynthesis::getComputerParam()   // handle "computer" param
{
     m_paramName="computer";
     GBOOL got=GETPARAMVAL(m_paramName.c_str());
     INT atype=atoi(m_pValBuf);
     if (!got || m_account.systyp == atype) {
          return(true);
     }
     else if (hasKey(syschgky)) {
          if (atype > 0 && atype < 5) {
               m_account.systyp=(atype == 4 ? 0 : atype);
               return(true);
          }
          setError(ERR_INVALID,m_paramName.c_str());
     }
     return(false);
}

bool
uieSynthesis::getSexParam()        // handle "sex" param
{
     m_paramName="sex";
     GBOOL got=GETPARAMVAL(m_paramName.c_str());

     CHAR sex=toupper(m_pValBuf[0]);
     if (!got || m_account.sex == sex) {
          return(true);
     }
     else if (hasKey(sexchgky)) {
          if (sex == 'F' || sex == 'M') {
               m_account.sex=sex;
               return(true);
          }
          setError(ERR_INVALID,m_paramName.c_str());
     }
     return(false);
}

bool
uieSynthesis::getAnsiParam()       // handle "ansi" param
{
     m_paramName="ansi";
     GBOOL got=GETPARAMVAL(m_paramName.c_str());
     INT ansset=atoi(m_pValBuf);
     if (!got || (ansset == 1 && m_account.ansifl&ANSMAN)
      || (ansset == 2 && m_account.ansifl&ANSON)
      || (ansset == 3 && !(m_account.ansifl&(ANSON|ANSMAN)))) {
          return(true);
     }
     else if (hasKey(anschgky)) {
          if (ansset > 0 && ansset < 4) {
               m_account.ansifl=0;
               if (ansset == 1) {
                    m_account.ansifl|=ANSMAN;
               }
               else if (ansset == 2) {
                    m_account.ansifl|=ANSON;
               }
               return(true);
          }
          setError(ERR_INVALID,m_paramName.c_str());
     }
     return(false);
}

bool
uieSynthesis::getOutputParam()     // handle "output" param
{
     m_paramName="output";
     GBOOL got=GETPARAMVAL(m_paramName.c_str());
     CHAR scnbrk=toupper(m_pValBuf[0]);
     if (!got || (scnbrk == 'P' && m_account.scnbrk == m_account.scnfse)
      || (scnbrk == 'C' && m_account.scnbrk == CONTOUTPUT)) {
          return(true);
     }
     else if (hasKey(pauchgky)) {
          if (scnbrk == 'P') {
               m_account.scnbrk=scnbrk;
               return(true);
          }
          else if (scnbrk == 'C') {
               m_account.scnbrk=CONTOUTPUT;
               return(true);
          }
          setError(ERR_INVALID,m_paramName.c_str());
     }
     return(false);
}

bool
uieSynthesis::getEditorParam()     // handle "editor" param
{
     m_paramName="editor";
     GBOOL got=GETPARAMVAL(m_paramName.c_str());
     CHAR edt=toupper(m_pValBuf[0]);
     if (!got || (edt == 'F' && !(m_account.usrprf&PRFLIN))
      || (edt == 'L' && m_account.usrprf&PRFLIN)) {
          return(true);
     }
     else if (hasKey(edtchgky)) {
          if (edt == 'F') {
               m_account.usrprf&=~PRFLIN;
               return(true);
          }
          else if (edt == 'L') {
               m_account.usrprf|=PRFLIN;
               return(true);
          }
          setError(ERR_INVALID,m_paramName.c_str());
     }
     return(false);
}

bool
uieSynthesis::getLangParam()       // handle "language" param
{
     m_paramName="language";
     if (!GETPARAMVAL(m_paramName.c_str())) {
          return(true);
     }
     INT found=getgen(&m_generic,(CHAR *)m_usrPtr->userid());

     if ((found && sameas(m_pValBuf,m_generic.lngnam))
      || (!found && strlen(m_pValBuf) == 0)) {
          return(true);
     }
     else if (hasKey(langchg)) {
          if (sameas(m_pValBuf,msg_autolang)) {
               stlcpy(m_generic.lngnam,m_pValBuf,LNGSIZ);
               setgen(&m_generic);
               return(true);
          }
          for (INT i=0; i < nlingo; i++) {
               if (sameas(languages[i]->name,m_pValBuf)) {
                    stlcpy(m_generic.lngnam,m_pValBuf,LNGSIZ);
                    setgen(&m_generic);
                    return(true);
               }
          }
          setError(ERR_INVALID,m_paramName.c_str());
     }
     return(false);
}

ACTHCODE
uieSynthesis::dynafile()           // dynafile
{
     ASSERT(m_dnfPtr != NULL);
     ASSERT(m_usrAccPtr != NULL);

     ACTHCODE retval=ACTHMORE;

     if (m_err != ERR_NOERROR) {
          setErrorVbs();
     }
     setmbk(uieAHMsg);
     m_pTvb->setVars(m_usrAccPtr);
     if (m_usrPtr->hasKey(langchg)) {
          t_LanguageHtml=m_langvar;
     }
     switch(m_dnfPtr->process()) {
     case DNFBEGIN:
          if (m_usrPtr->hasKey(langchg)) {
               getgen(&m_generic,(CHAR *)m_usrPtr->userid());
               t_LanguageHtml=m_langvar=stpans(rawmsg(LANGOPEN));
          }
          break;
     case DNFROWBEGIN:
          if (!m_usrPtr->hasKey(langchg)) {
               break;
          }
          if (m_dnfPtr->rowNumber() > nlingo) {
               m_dnfPtr->tableDone();
          }
          else if (m_dnfPtr->rowNumber() == nlingo) {
               t_LanguageHtml=m_langvar="";
               if (m_generic.lngnam[0] == '\0') {
                    setLangVar(true,msg_autolang);
               }
               else {
                    setLangVar(false,msg_autolang);
               }
               t_LanguageHtml=m_langvar+=stpans(rawmsg(LANGEND));
          }
          else {
               if (m_dnfPtr->rowNumber() > 0) {
                    t_LanguageHtml=m_langvar="";
               }
               if (m_generic.lngnam[0] != '\0'
                && sameas(languages[m_dnfPtr->rowNumber()]->name
                ,m_generic.lngnam)) {
                    setLangVar(true,languages[m_dnfPtr->rowNumber()]->name);
               }
               else {
                    setLangVar(false,languages[m_dnfPtr->rowNumber()]->name);
               }
          }
          m_pTvb->setVars(m_usrAccPtr);
          break;
     case DNFROWEND:
          if (!m_usrPtr->hasKey(langchg)) {
               m_dnfPtr->tableDone();
          }
          break;
     case DNFEND:
          retval=ACTHDONE;
          break;
     }
     rstmbk();
     m_pTvb->setVarsDefault();
     return(retval);
}

VOID
uieSynthesis::setLangVar(          // set up language text variable
bool select,
const CHAR *optval)
{
     clrprf();
     if (select) {
          prfmsg(LANGBODY,SEL,optval);
     }
     else {
          prfmsg(LANGBODY,"",optval);
     }
     t_LanguageHtml=m_langvar+=stpans(prfbuf);
}

bool
uieSynthesis::hasAgentAccess()     // does user have access?
{
     ASSERT(m_usrPtr != NULL);

     return(m_usrPtr->hasKey(huiekey));
}

VOID
uieSynthesis::setError(            // set error code
errorcodes err,                    // error code
const CHAR *arg1,                  // argument for m_errparam
const CHAR *arg2)                  // argument for m_errlength;
{
     m_err=err;
     if (arg1 != NULL) {
          m_errparam=arg1;
     }
     if (arg2 != NULL) {
          m_errlength=arg2;
     }
}

VOID
uieSynthesis::setErrorVbs()        // set up error text variables
{
     setmbk(uieAHMsg);
     clingo=0;
     prfmsg(translateError(),m_errparam.c_str(),m_errlength.c_str());
     t_ErrorMessage=prfbuf;
     clrprf();
     rstmbk();
}

INT
uieSynthesis::translateError()
{
     if (m_err > 0 && m_err < ERR_HIGHERROR) {
          return(errArray[m_err]);
     }
     m_errparam=spr("%d",(INT)m_err);
     return(errArray[ERR_UNRECOGNIZED]);
}

VOID
uieSynthesis::initTemplates()      //  init onsuccess/onerrror
{
     m_succRedir=getOnParam("onsuccess",&m_onsuccessFile);
     if (ses->param("onerror")) {
          INT sz=ses->paramRoom("onerror");
          m_errParam=new CHAR[sz];
          ses->param("onerror",m_errParam,sz);
     }
     m_onerrorFile=DFTERROR;
}

bool                               //   is a redirct?
uieSynthesis::getOnParam(          // get onxxx parameter
CHAR const * paramName,            //   parameter to get
CHAR** pStorePtr)                  //   store redir path here
{
     if (ses->param(paramName)) {
          if (*pStorePtr != NULL) {
               delete [] *pStorePtr;
          }
          INT sz=ses->paramRoom(paramName);
          *pStorePtr=new CHAR[sz];
          ses->param(paramName,*pStorePtr,sz);
          if (isProtocol(*pStorePtr) || **pStorePtr == '/') {
               return(true);
          }
          return(false);
     }
     else if (*pStorePtr != NULL) {
          delete [] *pStorePtr;
          *pStorePtr=NULL;
     }
     return(false);
}

ACTHCODE                           //   continue synthesis?
uieSynthesis::errorResponse(       // process an error
dnfMap& map,                       //   map to use
CHAR const * path)                 //   path to template directory
{
     if (m_errParam != NULL) {
          for (int i=0 ; i < itemcntd(m_errParam,",") ; i++) {
               CHAR* errcs=itemidxd(m_errParam,i,",");
               CHAR* restr=strchr(errcs,' ');
               if (atoi(errcs) == 0 && restr == NULL) {
                    // found default redir
                    strmove(errcs,unpad(skpwht(errcs)));
                    if (strlen(errcs) > 0) {
                         m_onerrorFile=errcs;
                    }
               }
               else if (atoi(errcs) == m_err && restr != NULL) {
                    strmove(restr,unpad(skpwht(restr)));
                    if (strlen(restr) > 0) {
                         m_onerrorFile=restr;
                         break;
                    }
               }
          }

     }
     m_errRedir=(isProtocol(m_onerrorFile.c_str()) || m_onerrorFile[0] == '/');
     if (m_errRedir) {
          ses->redirect(m_onerrorFile.c_str());
          return(ACTHDONE);
     }
     ASSERT(path != NULL);
     string dest=path;
     dest+=m_onerrorFile;
     m_dnfPtr=dnfCreateHandler(&bout,&map,dest.c_str());
     return(ACTHMORE);
}

ACTHCODE                           //   continue synthesis?
uieSynthesis::successResponse(     // process an onsuccess
dnfMap& map,                       //   map to use
CHAR const * path)                 //   path to template directory
{
     if (m_succRedir) {
          ses->redirect(m_onsuccessFile);
          return(ACTHDONE);
     }
     ASSERT(path != NULL);
     string dest=path;

     dest+=(m_onsuccessFile == NULL ? DFTSUCCESS : m_onsuccessFile);
     m_dnfPtr=dnfCreateHandler(&bout,&map,dest.c_str());
     return(ACTHMORE);
}

