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

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

#ifndef S4INDEX_OFF

/* 'pos' is an percentage, positioning is approximate. */
int S4FUNCTION t4position2( TAG4 *t4, double *result )
{
#ifdef S4DEBUG
  if ( t4 == 0 )
    e4severe( e4parm, E4_T4POSITION2 ) ;
#endif

  if ( t4->code_base->error_code < 0 )
    return -1 ;

  *result = t4position( t4 );
  return 0;
}

#ifndef N4OTHER

double S4FUNCTION t4positionDbl( TAG4 *t4 )
{
  double pos ;
  B4BLOCK *block_on ;
  int n ;

#ifdef S4DEBUG
  if ( t4 == 0 )
    e4severe( e4parm, E4_T4POSITION ) ;
#endif

  if ( t4->code_base->error_code < 0 )
    return -1 ;

  pos = .5 ;
  for ( block_on = (B4BLOCK *)t4->blocks.last_node ; block_on != 0 ; )
  {
#ifdef S4FOX
    n = block_on->header.n_keys ;
#else
    n = block_on->n_keys + 1 ;
    if ( b4leaf( block_on ) )
      n-- ;
#endif

    if( n == 0 )
      pos = 0.0 ;
    else
      pos = (block_on->key_on+pos)/n ;

    block_on = (B4BLOCK *) block_on->link.p ;
    if ( block_on == (B4BLOCK *) t4->blocks.last_node )
      break ;
  }
#ifdef S4FOX
  if ( t4->header.descending )   /* backwards in file... */
    return 1.0 - pos ;
  else
#endif
    return pos ;
}

double S4FUNCTION t4position( TAG4 *t4 )
{
#ifdef S4FOX
  int rc, len ;
  char *result ;

#ifdef S4DEBUG
  if ( t4 == 0 )
    e4severe( e4parm, E4_T4POSITION ) ;
#endif

  if ( t4->code_base->error_code < 0 )
    return -1 ;

  if ( d4tag_selected( t4->index->data ) == t4 )
  {
    len = t4expr_key( t4, &result ) ;
    if ( len < 0 )
      return -1.0 ;
    t4version_check( t4, 0, 0 ) ;
    rc = t4seek( t4, result, len ) ;
    if ( rc != 0  && rc != r4eof && rc != r4after )
      return -1.0 ;
  }
#endif

  return t4positionDbl( t4 ) ;
}

int S4FUNCTION t4position_set( TAG4 *t4, double pos )
{
  int rc, n, final_pos ;
  B4BLOCK *block_on ;

#ifdef S4DEBUG
  if ( t4 == 0 )
    e4severe( e4parm, E4_T4POSITION_SET ) ;
#endif

  if ( t4->code_base->error_code < 0 )
    return -1 ;

#ifndef S4SINGLE
  i4version_check( t4->index, 0, 0 ) ;
#endif

#ifdef S4FOX
  if ( t4->header.descending )   /* backwards in file... */
    pos = 1.0 - pos ;
#endif

  if ( t4up_to_root( t4 ) < 0 )
    return -1 ;

  for(;;)
  {
#ifdef S4DEBUG
    if ( pos < 0.0 || pos > 1.0 )  /* Could be caused by rounding error ? */
      e4severe( e4parm, E4_INFO_ILP ) ;
#endif

    block_on = t4block(t4) ;

#ifdef S4FOX
    n = block_on->header.n_keys ;
#else
    n = block_on->n_keys+1 ;
    if ( b4leaf( block_on ) )
      n-- ;
#endif

    final_pos = (int)( n * pos ) ;
    if ( final_pos == n )
      final_pos-- ;

#ifdef S4FOX
    b4go( block_on, final_pos ) ;
#else
    block_on->key_on = final_pos ;
#endif

    pos = pos*n - final_pos ;

    rc = t4down( t4 ) ;
    if ( rc < 0 )
      return -1 ;
    if ( rc == 1 )
      return 0 ;
  }
}

#endif   /*  ifndef N4OTHER  */

#ifdef N4OTHER

double S4FUNCTION t4positionDbl( TAG4 *t4 )
{
  return t4position( t4 ) ;
}

double S4FUNCTION t4position( TAG4 *t4 )
{
  double pos ;
  B4BLOCK *block_on ;
  int n ;
#ifdef S4CLIPPER
  int first = 1 ;
#endif

#ifdef S4DEBUG
  if ( t4 == 0 )
    e4severe( e4parm, E4_T4POSITION ) ;
#endif

  if ( t4->code_base->error_code < 0 )
    return -1 ;

  block_on = (B4BLOCK *) t4->blocks.last_node ;

  if ( !b4leaf(block_on) )
    pos = 1.0 ;
  else
    pos = .5 ;

  for ( ; block_on != 0 ; )
  {
    n = block_on->n_keys + 1 ;
#ifdef S4CLIPPER
    if ( first )
    {
      if ( b4leaf( block_on ) )
        n-- ;
      first = 0 ;
    }
#else
    if ( b4leaf( block_on ) )
      n-- ;
#endif

    if( n == 0 )
      pos = 0.0 ;
    else
      pos = ( block_on->key_on + pos ) / n ;

    block_on = (B4BLOCK *) block_on->link.p ;
    if ( block_on == (B4BLOCK *)t4->blocks.last_node )
      break ;
  }
#ifdef S4CLIPPER
  if ( t4->header.descending )   /* backwards in file... */
    return 1.0 - pos ;
  else
#endif
    return pos ;
}

int S4FUNCTION t4position_set( TAG4 *t4, double pos )
{
  int rc, n, final_pos ;
  B4BLOCK *block_on ;

#ifdef S4DEBUG
  if ( t4 == 0 )
    e4severe( e4parm, E4_T4POSITION_SET ) ;
#endif

  if ( t4->code_base->error_code < 0 )
    return -1 ;

#ifdef S4CLIPPER
  if ( t4->header.descending )   /* backwards in file... */
    pos = 1.0 - pos ;
#endif

  if ( t4up_to_root( t4 ) < 0 )
    return -1 ;

  for(;;)
  {
#ifdef S4DEBUG
    if ( pos < 0.0 || pos > 1.0 )  /* Could be caused by rounding error ? */
      e4severe( e4parm, E4_INFO_ILP ) ;
#endif

    block_on = t4block( t4 ) ;

    n = block_on->n_keys + 1 ;
    if ( b4leaf( block_on ) )
      n-- ;

    final_pos = (int)( n * pos ) ;
    if ( final_pos == n )
      final_pos-- ;

    block_on->key_on = final_pos ;
    pos = pos*n - final_pos ;

    rc = t4down( t4 ) ;
    if ( rc < 0 )
      return -1 ;
    if ( rc == 1 )
      return 0 ;
  }
}

#endif  /* N4OTHER */
#endif  /* S4INDEX_OFF */
