/***************************************************************************
 *                                                                         *
 *   FILE.CPP                                                              *
 *                                                                         *
 *   Copyright (c) 1993-1997 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   File Wrapper Class                                                    *
 *                                                                         *
 *                                                 - N.C. Osterc  11/04/98 *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "majorbbs.h"
#include "galfilh.h"
#include <cstring>
#include "library.h"
#include "file.h"

#define FILREV "$Revision: 4 $"

MARKSOURCE(file);

file::file()                       // dfault constr
{
     ::memset(static_cast<struct flfile*>(this),0,sizeof(struct flfile));
     m_lock=0;
     m_flCode=FLMAN_UPDATEREC;
     m_renCode=RENKEYREM;
}

file::file(                        // constructor
const CHAR *newlibname,
const CHAR *newfilname)
{
     m_flCode=FLMAN_UPDATEREC;
     m_renCode=RENKEYREM;
     m_lock=0;
     ::memset(static_cast<struct flfile*>(this),0,sizeof(struct flfile));
     ::stlcpy(libname,newlibname,FLNAMESZ);
     ::stlcpy(filname,newfilname,FLFILENM);
     ::stlcpy(m_oldName,newfilname,FLFILENM);
     load();
}

file::~file()                      // destructor
{
}

bool
file::getWriteLock(                // lock for write
INT *othusn)
{
     return((*othusn=::w2writ(libname,filname,m_lock)) == NOCONFLICT);
}

VOID
file::releaseWriteLock()
{
     donewrit(m_lock);
}

bool
file::load()                       // load file information into class
{
     ASSERT(::strlen(libname) > 0);
     ASSERT(::strlen(filname) > 0);

     bool rc=false;
     struct fllib *libptr=libfind(libname);

     if ((0 != libptr) && (0 == (libptr->flags&FLGDOS))) {
          ::dfaSetBlk(flfdat);
          setKey();
          rc=::dfaAcqEQ(static_cast<struct flfile*>(this),&m_key,COMPLF);
          ::dfaRstBlk();
     }
     return(rc);
}

bool
file::approve(                    // approve this file
USHORT newdate)
{
     bool rc=false;

     if (getWriteLock(&m_othUnum)) {
          if (notapped(udate)) {
               library *pl=new library(libname);
               pl->lib.appwait--;
               chuldate(&(pl->lib),udate,1);
               ::stlcpy(udate,ddat2srt((0 == newdate) ? today() : newdate),DATESZ);
               utime=now();
               pl->update();
               delete pl;
               rc=updateRecord();
          }
          releaseWriteLock();
     }
     return(rc);
}

bool
file::unApprove()                  // unapprove this file
{
     bool rc=false;

     if (getWriteLock(&m_othUnum)) {
          if(!notapped(udate)) {
               library *pl=new library(libname);
               pl->lib.appwait++;
               chuldate(&(pl->lib),udate,0);
               ::stlcpy(udate,NOTAPPED,DATESZ);
               utime=0;
               pl->update();
               delete pl;
               rc=updateRecord();
          }
          releaseWriteLock();
     }
     return(rc);
}

bool
file::log(
bool approve)
{
     ASSERT(0 != libfind(libname));

     bool rc;
     library *plib=new library(libname);

     if (plib->lib.numfiles+1 > plib->lib.maxfil) {
          rc=false;
     }
     else if ((plib->lib.totbytes+flclfit(siz,plib->lib.cluster)) >
      plib->lib.maxbyt) {
          rc=false;
     }
     else if (insertRecord()) {
          plib->lib.numfiles++;
          plib->lib.totbytes+=flclfit(siz,plib->lib.cluster);
          if (approve) {
               chuldate(&(plib->lib),udate,0);
          }
          else {
               plib->lib.appwait++;
          }
          plib->update();
          rc=true;
     }
     delete plib;
     return(rc);
}

bool
file::unLog()                      // unlog this file
{
     ASSERT(0 != libfind(libname));

     bool rc=false;

     if (getWriteLock(&m_othUnum)) {
          library *plib=new library(libname);
          ::dfaSetBlk(flfdat);
          setKey();
          if (::dfaAcqEQ(NULL,&m_key,COMPLF)) {
               ::dfaDelete();
               plib->lib.numfiles--;
               plib->lib.totbytes-=flclfit(siz,plib->lib.cluster);
               if (notapped(udate)) {
                    plib->lib.appwait--;
               }
               chuldate(&(plib->lib),udate,0);
               plib->update();
               rc=true;
          }
          ::dfaRstBlk();
          delete plib;
          releaseWriteLock();
     }
     return(rc);
}

bool
file::insertRecord()               // insert record
{
     bool rc=false;

     struct fllib *libptr=libfind(libname);

     if ((0 != libptr) && (0 == (libptr->flags&FLGDOS))) {
          ::dfaSetBlk(flfdat);
          setKey();
          if (!::dfaAcqEQ(NULL,&m_key,COMPLF)) {
               ::dfaInsertV(static_cast<struct flfile*>(this)
                 ,FLFILREC+strlen(desc)+1);
               rc=true;
          }
          ::dfaRstBlk();
     }
     return(rc);
}

bool
file::updateRecord()               // update disk
{
     bool rc=false;

     struct fllib* libptr=libfind(libname);

     if ((0 != libptr) && (0 == (libptr->flags&FLGDOS))) {
          ::dfaSetBlk(flfdat);
          setKey();
          if (::dfaAcqEQ(NULL,&m_key,COMPLF)) {
               ::dfaUpdateV(static_cast<struct flfile*>(this)
                  ,FLFILREC+strlen(desc)+1);
               rc=true;
          }
          ::dfaRstBlk();
     }
     return(rc);
}

VOID
file::setDescription(              // set up description
const CHAR *newdesc)
{
     ::stzcpy(descedit,newdesc,DESCSIZ);

     CHAR* s=descedit;

     do {
          while (*s == '\n') {
               ::strcpy(s,s+1);
          }
     } while ('\0' != *s++);

     darsdesc(NDESCLN,'\r');

     INT loop;
     INT back;

     desc[0]='\0';
     for (loop=0; (loop < dargc) && (countc(desc,'\r') < NDESCLN); loop++) {
          if (::strlen(dargv[loop]) < SDESCLN) {
               ::stlcat(desc,dargv[loop],DESCSIZ);
               ::stlcat(desc,"\r",DESCSIZ);
          }
          else {
               // TODO: Find out what's going on
               for (back=SDESCLN-1; (back > (SDESCLN-20)); back--) {
                    s=&dargv[loop][back];
                    if (' ' == *s) {
                         break;
                    }
                    else {
                         s="";
                    }
               }
               if ('\0' == *s) {
                    CHAR tmpbuf[SDESCLN];
                    ::stlcpy(tmpbuf,dargv[loop],SDESCLN);
                    ::stlcat(desc,tmpbuf,DESCSIZ);
                    ::stlcat(desc,"\r",DESCSIZ);
                    dargv[loop]=&dargv[loop][SDESCLN-1];
               }
               else {
                    CHAR* tmpptr=new CHAR[back+1];
                    ::stlcpy(tmpptr,dargv[loop],back);
                    ::stlcat(desc,tmpptr,DESCSIZ);
                    ::stlcat(desc,"\r",DESCSIZ);
                    delete [] tmpptr;
                    dargv[loop]=++s;
               }
               loop--;
          }
     }
}

bool
file::canRemoveKeyWord(            // can we remove a keyword?
CHAR* newfilname)
{
     return(delkw("",libname,newfilname));
}

VOID
file::addKeyWords(                 // add keywords
CHAR* filename)
{
     INT loop;

     if (!longsrch) {
          fllib *libptr=libfind(libname);

          if ((libptr != NULL) && (!(libptr->flags&FLGDOS))) {
               fluoff(usrnum);
               if (!delkw("",filename,libname) && kwbuf[0].keyword[0] == '\0') {
                    if (makwdlst(desc,filename)) {
                         for (loop=0 ; loop < dargc ; loop++) {
                              addkw(dargv[loop],filename,libname);
                         }
                    }
               }
          }
     }
}

FLMANCODE
file::rename()                     // rename file
{
     ASSERT(::strlen(libname) > 0);
     ASSERT(::strlen(filname) > 0);

     FLMANCODE flc=FLMAN_WORKING;
     CHAR keepName[FLFILENM];

     switch (m_renCode) {
     case RENPREP:
          ::stlcpy(keepName,filname,FLFILENM);
          ::stlcpy(filname,m_oldName,FLFILENM);
          if (!getWriteLock(&m_othUnum)) {
               ::stlcpy(filname,keepName,FLFILENM);
               return(FLMAN_ERROR);
          }
          ::stlcpy(filname,keepName,FLFILENM);
          m_renCode=RENKEYREM;
          break;
     case RENKEYREM:
          if (longsrch || !canRemoveKeyWord(m_oldName)) {
               m_renCode=RENLAST;
          }
          break;
     case RENLAST:
          ::stlcpy(keepName,filname,FLFILENM);
          ::stlcpy(filname,m_oldName,FLFILENM);
          removeRecord();
          ::stlcpy(filname,keepName,FLFILENM);
          renameActual(m_oldName,filname);
          insertRecord();
          addKeyWords(filname);
          m_renCode=RENKEYREM;
          releaseWriteLock();
          return(FLMAN_SUCCESS);
     default:
          ASSERTM(FALSE,"Unhandled rename switch case");
          break;
     }
     return(flc);
}

FLMANCODE
file::update()                     // update existing file
{
     ASSERT(::strlen(libname) > 0);
     ASSERT(::strlen(filname) > 0);

     switch (m_flCode) {
     case FLMAN_UPDATEREC:
          if (!getWriteLock(&m_othUnum)) {
               return(FLMAN_ERROR);
          }
          if (!updateRecord()) {
               releaseWriteLock();
               return(FLMAN_ERROR);
          }
          m_flCode=(longsrch ? FLMAN_OPDONE : FLMAN_KEYWORDS);
          break;
     case FLMAN_KEYWORDS:
          if (!canRemoveKeyWord(filname)) {
               addKeyWords(filname);
               m_flCode=FLMAN_OPDONE;
          }
          break;
     case FLMAN_OPDONE:
          releaseWriteLock();
          m_flCode=FLMAN_UPDATEREC;
          return(FLMAN_SUCCESS);
     default:
          ASSERTM(FALSE,"Unhandled case in update switch");
          break;
     }
     return(FLMAN_WORKING);
}

bool
file::removeRecord()               // remove the database record
{
     bool rc=false;

     ::dfaSetBlk(flfdat);
     setKey();
     if (::dfaAcqEQ(NULL,&m_key,COMPLF)) {
          ::dfaDelete();
          rc=true;
     }
     ::dfaRstBlk();
     return(rc);
}

VOID
file::removeActual()               // actually delete the file
{
     CHAR           sprBuf[GCSTRPTH];
     struct fllib*  libptr=libfind(libname);

     ASSERT(0 != libptr);

     ::makePath(sprBuf,libpath(libptr),filname,GCSTRPTH);
     ::unlink(sprBuf);
}

VOID
file::renameActual(                // actually rename file on disk
CHAR *oldName,
CHAR *newName)
{
     CHAR           oldBuf[GCSTRPTH];
     CHAR           newBuf[GCSTRPTH];
     struct fllib*  libptr=libfind(libname);

     ASSERT(0 != libptr);

     ::makePath(oldBuf,libpath(libptr),oldName,GCSTRPTH);
     ::makePath(newBuf,libpath(libptr),newName,GCSTRPTH);
     ::rename(oldBuf,newBuf);
}

FLMANCODE                          // status code
file::despose()                    // remove this file (from disk and database)
{
     ASSERT(::strlen(libname) > 0);
     ASSERT(::strlen(filname) > 0);

     FLMANCODE flc=FLMAN_NOTFOUND;
     struct fllib* libptr=libfind(libname);

     if (0 != libptr) {
          if (libptr->flags&FLGCBD) {
               return(FLMAN_FLAG4COPY);
          }
          else if (0 == (libptr->flags&FLGDOS)) {
               if (unLog()) {
                    flc=FLMAN_SUCCESS;
               }
               else {
                    return(flc);
               }
          }
          removeActual();
     }
     else {
          flc=FLMAN_NOTFOUND;
     }
     return(flc);
}

VOID
file::setKey()                     // set up composite key
{
     ::stlcpy(m_key.libname,libname,FLNAMESZ);
     ::stlcpy(m_key.filname,filname,FLFILENM);
}

VOID
file::setOldName(
CHAR *oldName)
{
     ASSERT(0 != oldName);

     ::stlcpy(m_oldName,oldName,FLFILENM);
}

bool
file::nameOk()
{
     return(::okfname(filname));
}
