/* d4go.c   (c)Copyright Sequiter Software Inc., 1988-1996.  All rights reserved. */

#include "d4all.h"
#ifndef S4UNIX
   #ifdef __TURBOC__
      #pragma hdrstop
   #endif
#endif

#ifdef S4CLIENT
/* d4go, d4skip, d4seek, after complete, perform the record information transferral... */
int d4goVirtual( DATA4 *data, const long recNo, const int rc, const void *outVoid, void *connectionVoid )
{
   const CONNECTION4GO_INFO_OUT *out ;
   CONNECTION4 *connection ;
   CODE4 *c4 ;

   out = (CONNECTION4GO_INFO_OUT *)outVoid ;
   connection = (CONNECTION4 *)connectionVoid ;
   c4  = data->codeBase ;

   if ( rc == r4entry )   /* invalid record (beyond eof) */
   {
      data->recNum = -1 ;
      memset( data->record, ' ', dfile4recWidth( data->dataFile ) ) ;
      if ( c4->errGo )
         return error4describe( c4, e4read, E93101, d4alias( data ), 0, 0 ) ;
   }

   if ( rc > 0 )  /* eg. r4entry */
      return rc ;

   if ( rc < 0 )
   {
      data->recNum = -1 ;
      if ( c4->errGo )
         connection4errorDescribe( connection, c4, rc, E93101, d4alias( data ), 0, 0 ) ;
      return rc ;
   }

   if ( out->recNo != recNo )
      return error4( c4, e4info, E83101 ) ;
   /* now copy the data into the record */
   memcpy( data->record, ((char *)out) + sizeof( CONNECTION4GO_INFO_OUT ), dfile4recWidth( data->dataFile ) ) ;

   data->recNum = recNo ;
   data->bofFlag = data->eofFlag = 0 ;

   if ( out->recordLocked == 1 )
   {
      d4localLockSet( data, recNo ) ;
      memcpy( data->recordOld, data->record, dfile4recWidth( data->dataFile ) ) ;
      data->recNumOld = recNo ;
      #ifndef S4OFF_MULTI
         #ifndef S4OFF_MEMO
            data->memoValidated = 1 ;
         #endif
      #endif
   }

   return 0 ;
}

int S4FUNCTION d4go( DATA4 *data, const long recNo )
{
   int rc ;
   CONNECTION4 *connection ;
   CONNECTION4GO_INFO_IN info ;
   CODE4 *c4 ;

   #ifdef S4VBASIC
      if ( c4parm_check( data, 2, E93101 ) )
         return -1 ;
   #endif

   #ifdef E4PARM_HIGH
      if ( data == 0 )
         return error4( 0, e4parm_null, E93101 ) ;
   #endif

   c4 = data->codeBase ;

   #ifdef S4OFF_WRITE
      if ( error4code( c4 ) < 0 )
         return e4codeBase ;
   #else
      rc = d4updateRecord( data, 0 ) ;   /* returns -1 if error4code( codeBase ) < 0 */
      if ( rc )
         return rc ;
   #endif

   connection = data->dataFile->connection ;
   if ( connection == 0 )
      return e4connection ;

   connection4assign( connection, CON4GO, data4clientId( data ), data4serverId( data ) ) ;
   info.recNo = recNo ;
   connection4addData( connection, &info, sizeof( CONNECTION4GO_INFO_IN ), 0 ) ;
   rc = connection4repeat( connection, -2, -1, -1, data ) ;
   if ( rc == r4locked )
      return rc ;

   return d4goVirtual( data, recNo, rc, connection4data( connection ), connection ) ;
}

#else

int S4FUNCTION d4go( DATA4 *data, const long recNo )
{
   int rc, fromDisk ;
   CODE4 *c4 ;
   #ifndef S4OFF_MULTI
      int didLock ;
   #endif
   #ifndef S4OFF_MEMO
      int i ;
   #endif

   #ifdef S4VBASIC
      if ( c4parm_check( data, 2, E93101 ) )
         return -1 ;
   #endif

   #ifdef EPARM_HIGH
      if ( data == 0 )
         return error4( 0, e4parm_null, E93101 ) ;
   #endif

   c4 = data->codeBase ;
   rc = 0 ;

   if ( error4code( c4 ) < 0 )
      return e4codeBase ;

   #ifndef S4OFF_WRITE
      if ( data->recordChanged )
      {
         rc = d4updateRecord( data, 0 ) ;
         if ( rc )
            return rc ;
      }
      #ifndef S4OFF_MEMO
         else
      #endif
   #endif
      #ifndef S4OFF_MEMO
         if ( data->fieldsMemo != 0 )
            for ( i = 0; i < data->dataFile->nFieldsMemo; i++ )
               f4memoReset( data->fieldsMemo[i].field ) ;
      #endif

   if ( d4recCountLessEq( data, recNo ) == 0 )  /* past eof */
   {
      data->recNum = -1 ;  /* at an invalid position */
      memset( data->record, ' ', data->dataFile->recWidth ) ;  /* clear the record to avoid corruption */
      #ifndef S4SERVER
         if ( c4->errGo )
            return error4describe( c4, e4read, E91102, d4alias( data ), 0, 0 ) ;
      #endif
      return r4entry ;
   }

   fromDisk = 0 ;
   #ifndef S4OFF_MULTI
      didLock = 0 ;

      #ifdef S4SERVER
         if ( !dfile4lockTest( data->dataFile, data4clientId( data ), data4serverId(data ), recNo ) )  /* record not already locked */
      #else
         if ( !d4lockTest( data, recNo ) )  /* record not already locked */
      #endif
      {
         switch( code4unlockAuto( c4 ) )
         {
            case LOCK4ALL :
               rc = code4unlockDo( tran4dataList( data->trans ) ) ;
               break ;
            case LOCK4DATA :
               rc = d4unlock( data ) ;
               break ;
            default:
               break ;
         }
         if ( rc < 0 )
            return error4stack( c4, rc, E93101 ) ;

         if ( c4->readLock )
         {
            #ifdef S4SERVER
               rc = dfile4lock( data->dataFile, data4clientId( data ), data4serverId( data ), recNo ) ;
            #else
               rc = d4lock( data, recNo ) ;
            #endif
            if ( rc )
               return rc ;
            didLock = 1 ;
         }
      }

      #ifndef S4OFF_MEMO
         if ( !data->memoValidated )
            #ifdef S4SERVER
               if ( dfile4lockTest( data->dataFile, data4clientId( data ), data4serverId( data ), recNo ) )  /* record not already locked */
            #else
               #ifndef S4OFF_MULTI
                  if ( d4lockTest( data, recNo ) )  /* record not already locked */
               #endif
            #endif
               fromDisk = 1 ;
      #endif  /* S4OFF_MEMO */
   #endif

   rc = dfile4goData( data->dataFile, recNo, data->record, fromDisk ) ;

   if ( rc )
   {
      data->recNum = -1 ;  /* at an invalid position */
      #ifndef S4OFF_MULTI
         if ( didLock == 1 )
            #ifdef S4SERVER
               dfile4unlockRecord( data->dataFile, data4clientId( data ), data4serverId( data ), recNo ) ;
            #else
               d4unlockRecord( data, recNo ) ;
            #endif
      #endif
      return rc ;
   }
   else
      data->recNum = recNo ;

   data->bofFlag = data->eofFlag = 0 ;

   #ifndef S4OFF_MULTI
      #ifdef S4SERVER
         if ( dfile4lockTest( data->dataFile, data4clientId( data ), data4serverId( data ), recNo ) )  /* record not already locked */
      #else
         if ( d4lockTest( data, recNo ) )  /* record not already locked */
      #endif
      {
   #endif
      memcpy( data->recordOld, data->record, dfile4recWidth( data->dataFile ) ) ;
      data->recNumOld = data->recNum ;
   #ifndef S4OFF_MULTI
      #ifndef S4OFF_MEMO
         data->memoValidated = 1 ;
      #endif
      }
      #ifndef S4OFF_MEMO
         else
            data->memoValidated = 0 ;
      #endif
   #endif

   return 0 ;
}

/* fromDisk is set to true if a disk read is desired from the go */
#ifdef P4ARGS_USED
   #pragma argsused
#endif
int dfile4goData( DATA4FILE *data, long rec, void *record, int fromDisk )
{
   unsigned len ;
   CODE4 *cb ;

   #ifdef E4PARM_HIGH
      if ( data == 0 )
         return error4( 0, e4parm_null, E91102 ) ;
   #endif

   cb = data->c4 ;

   if( error4code( cb ) < 0 )
      return e4codeBase ;

   if ( rec <= 0 )
      len = 0 ;
   else
   {
      #ifndef S4OFF_MULTI
         #ifndef S4OPTIMIZE_OFF
            if ( fromDisk == 1 ) /* if bufferred old, and only record is locked, read from disk */
               if ( data->file.doBuffer && data->fileServerLock != 0 )
                  cb->opt.forceCurrent = 1 ;
         #endif
      #endif

      len = file4read( &data->file, dfile4recordPosition( data, rec ), record, data->recWidth ) ;

      #ifndef S4OFF_MULTI
         #ifndef S4OPTIMIZE_OFF
            if ( fromDisk == 1 )
               cb->opt.forceCurrent = 0 ;
         #endif
      #endif

      if( error4code( cb ) < 0 )
         return -1 ;
   }

   if ( len != data->recWidth )
   {
      memset( record, ' ', data->recWidth ) ;  /* clear the partially read record to avoid corruption */
      #ifndef S4SERVER
         if ( cb->errGo )
            return error4describe( cb, e4read, E91102, data->file.name, 0, 0 ) ;
      #endif
      return r4entry ;
   }
   return 0 ;
}

int d4goData( DATA4 *data, long rec )
{
   int rc ;
   rc = dfile4goData( data->dataFile, rec, data->record, 0 ) ;
   if ( rc != 0 )
      data->recNum = -1 ;  /* at an invalid position */
   else
      data->recNum = rec ;
   return rc ;
}
#endif  /* S4CLIENT */

int  S4FUNCTION d4goEof( DATA4 *data )
{
   long count ;
   #ifndef S4OFF_WRITE
      int rc ;
   #endif

   #ifdef E4PARM_HIGH
      if ( data == 0 )
         return error4( 0, e4parm_null, E93103 ) ;
   #endif

   if ( error4code( data->codeBase ) < 0 )
      return e4codeBase ;

   #ifndef S4OFF_WRITE
      rc = d4updateRecord( data, 0 ) ;  /* was 1 */
      if ( rc )
         return rc ;
   #endif

   count = d4recCount( data ) ;
   if ( count < 0 )
      return -1 ;
   data->recNum = count + 1L ;
   data->eofFlag = 1 ;
   if ( data->recNum == 1 )
      data->bofFlag = 1 ;
   memset( data->record, ' ', dfile4recWidth( data->dataFile ) ) ;
   return r4eof ;
}