/* d4skip.c   (c)Copyright Sequiter Software Inc., 1990-1994.  All rights reserved. */

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

int S4FUNCTION d4skip( DATA4 *data, long n )
{
#ifndef S4INDEX_OFF
  TAG4 *tag ;
#endif
  int rc, save_flag, old_eof_flag ;
  long start_rec, new_rec, count, n_skipped, recno ;
  char *key_value ;
  CODE4 *c4 ;

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

  if ( data == 0 )
#ifdef S4DEBUG
    e4severe( e4parm, E4_D4SKIP ) ;
#else
  return 0 ;
#endif

  c4 = data->code_base ;
  if ( c4->error_code < 0 )
    return -1 ;

  if ( data->rec_num < 1L )
  {
    if ( c4->skip_error == 1 )
      e4( c4, e4info, E4_INFO_SKI ) ;
    return -1L ;
  }

#ifndef S4INDEX_OFF
  tag = d4tag_selected( data ) ;
  if ( tag == 0 )
  {
#endif
    data->bof_flag = 0 ;
    start_rec = data->rec_num ;
    new_rec = start_rec+n ;
#ifndef S4OPTIMIZE_OFF
#ifndef S4DETECT_OFF
    c4->mode |= 0x02 ;
#endif
#endif
    if ( new_rec > 0L )
    {
      save_flag = c4->go_error ;
      c4->go_error = 0 ;
      rc = d4go( data, new_rec ) ;
      c4->go_error = save_flag ;
      if ( rc >= 0 && rc != r4entry )
        return rc ;
    }

    count = d4reccount(data) ;

    if ( count <= 0L || new_rec > count )
    {
      if ( count <= 0L )
      {
        if ( count < 0 )
          return -1 ;
        rc = d4go_eof( data ) ;
        if ( rc != r4eof )
          return rc ;
        data->bof_flag = 1 ;
      }
      if ( n < 0 )
      {
        data->bof_flag = 1 ;
        return r4bof ;
      }
      else
        return d4go_eof( data ) ;
    }

    if ( new_rec < 1L )
    {
      old_eof_flag = data->eof_flag ;
      rc = d4go( data, 1L ) ;
      if ( rc )
        return rc ;
      data->bof_flag = 1 ;
      data->eof_flag = old_eof_flag ;
      return r4bof ;
    }

    return d4go( data, new_rec ) ;
#ifndef S4INDEX_OFF
  }
  else
  {
    if ( data->eof_flag )
    {
      if ( n >= 0 ) return d4go_eof( data ) ;

      rc = d4bottom( data ) ;
      if ( rc && rc != r4eof )
        return rc ;
      if ( rc == r4eof )
      {
        rc = d4go_eof( data ) ;
        if ( rc != r4eof )
          return rc ;
        return r4bof ;
      }
      n++ ;
      data->rec_num = t4recno( tag ) ;
    }

    data->bof_flag = 0 ;

#ifndef S4OFF_WRITE
    if ( data->record_changed )
      if ( d4update_record( data, 0 ) < 0 ) /* was 1 */
        return -1 ;
#endif

    t4version_check( tag, 1, 0 ) ;

    if ( n == 0 )
      return 0 ;

    if ( t4recno( tag ) != data->rec_num )
    {
      rc = d4go( data, data->rec_num ) ;
      if ( rc )
        return rc ;

      t4expr_key( tag, &key_value ) ;

      rc = t4go( tag, key_value, data->rec_num ) ;
      if ( rc < 0 )
        return -1 ;

#ifdef S4HAS_DESCENDING
      if ( tag->header.descending )
      {
        if ( (rc > 0) && (n < 0) )
          n-- ;
      }
      else
        if ( (rc > 0) && (n > 0) )
          n-- ;
#else
      if ( (rc > 0) && (n > 0) )
        n-- ;
#endif
    }

#ifdef S4HAS_DESCENDING
    if ( tag->header.descending )
      n_skipped = -t4skip( tag, -n ) ;
    else
      n_skipped = t4skip( tag, n ) ;
    if ( n > 0  &&  n_skipped != n )
      return d4go_eof( data ) ;
#else
    n_skipped = t4skip( tag, n ) ;
    if ( n > 0  &&  n_skipped != n )
      return d4go_eof( data ) ;
#endif

    if ( t4eof( tag ) )
    {
      data->bof_flag = 1 ;
      return d4go_eof( data ) ;
    }

    recno = t4recno( tag ) ;
    if ( recno < 0 )
      return recno ;
#ifndef S4SINGLE
    if ( recno > data->minCount )   /* ensure correct sequencing for multi-user */
    {
      if ( recno > d4reccount( data ) )
      {
        rc = t4skip( tag, ( n > 0 ? 1L : -1L ) ) ;
        if ( rc < 0 )
          return rc ;
        if ( rc == 0 )
        {
          data->bof_flag = 1 ;
          return d4go_eof( data ) ;
        }
        recno = t4recno( tag ) ;
        if ( recno <= 0 || recno > data->minCount )
          return -1 ;
      }
    }
#endif
    rc = d4go( data, recno ) ;
    if ( rc )
      return rc ;
    if ( n == n_skipped )
      return 0 ;

#ifdef S4HAS_DESCENDING
    if ( ( n < 0 && !tag->header.descending ) ||  ( n < 0 && tag->header.descending ) )
#else
      if ( n < 0 )
#endif
      {
        data->bof_flag = 1 ;
        return r4bof ;
      }
  }
#endif
  return 0 ;
}
