/*!
  @file     Data_IndexScanTreeAccess.hpp
  @author   TorstenS
  @ingroup  DataAccess
  @brief    Primary tree iterator
  @see            

\if EMIT_LICENCE
    ========== licence begin  GPL
    Copyright (c) 2001-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end

\endif
*/



/*===========================================================================*
 *  INCLUDES                                                                 *
 *===========================================================================*/

#include "ggg90.h"

#include "DataAccess/Data_IndexScanTreeAccess.hpp"

/*===========================================================================*
 *  DEFINES                                                                  *
 *===========================================================================*/



/*===========================================================================*
 *  MACROS                                                                   *
 *===========================================================================*/



/*===========================================================================*
 *  GLOBAL VARIABLES                                                         *
 *===========================================================================*/



/*===========================================================================*
 *  LOCAL CLASSES, STRUCTURES, TYPES, UNIONS ...                             *
 *===========================================================================*/



/*===========================================================================*
 *  STATIC/INLINE FUNCTIONS (PROTOTYPES)                                     *
 *===========================================================================*/



/*===========================================================================*
 *  METHODS                                                                  *
 *===========================================================================*/


Data_IndexScanTreeAccess::Data_IndexScanTreeAccess(
    tbd_current_tree  &current,
    const SAPDB_UInt  stepWidth )
        :
        m_Current( current ),
        m_TrError( current.curr_trans->trError_gg00 ),
        m_PageAccessManager( current ),
        m_StepWidth( stepWidth ),
        m_CurrRecIndex( FIRST_REC_INDEX_BD00 ),
        m_CurrNumberOfLeaves( 1 ),
        m_IndexPage(),
        m_LeafPage()
{}

/*---------------------------------------------------------------------------*/

Data_IndexScanTreeAccess::~Data_IndexScanTreeAccess()
{
    m_LeafPage.Deassign( false ); // release the page for read
    m_IndexPage.Deassign( false );
}

/*---------------------------------------------------------------------------*/

Data_PrimPage&
Data_IndexScanTreeAccess::GetLeafNode()
{
    SAPDBTRACE_ROUTINE_DEBUG( "Data_IndexScanTreeAccess::GetLeafNode", DataTree_Trace, 5 );

    SAPDBERR_ASSERT_STATE( e_ok == m_TrError );

    if( m_LeafPage.IsAssigned() ) // usual way
    {
        if( GetNextLeafNode() )
            return( m_LeafPage );
    }
    else
    {   // called only once
        SAPDBERR_ASSERT_STATE( ! m_IndexPage.IsAssigned() );

        if( m_PageAccessManager.GetPage( m_IndexPage,
                                         m_Current.curr_tree_id.fileRoot_gg00()))
        {
            if( LEAF_LEVEL_BD00 == m_IndexPage.GetLevel())
            {
                m_LeafPage.Assign( m_IndexPage ); // root is leaf
                return( m_LeafPage );
            }
            else if( GetLeftMostLeafNode() )
                return( m_LeafPage );
        }
    }

    // error handling

    if( m_LeafPage.IsAssigned() )
        m_PageAccessManager.ReleasePage( m_LeafPage );

    if( m_IndexPage.IsAssigned() )
        m_PageAccessManager.ReleasePage( m_IndexPage );

    return( m_LeafPage ); // return empty page to indicate termination of iterator
}

/*---------------------------------------------------------------------------*/

SAPDB_Real8
Data_IndexScanTreeAccess::GetNumberOfEstimatedLeafNodes() const
{
    return( m_CurrNumberOfLeaves );
}

/*---------------------------------------------------------------------------*/
/* PRIVATE METHODS                                                           */
/*---------------------------------------------------------------------------*/

SAPDB_Bool
Data_IndexScanTreeAccess::GetLeftMostLeafNode()
{
    SAPDBTRACE_ROUTINE_DEBUG( "Data_IndexScanTreeAccess::GetLeftMostLeafNode", DataTree_Trace, 5 );

    SAPDBERR_ASSERT_STATE( e_ok == m_TrError );
    SAPDBERR_ASSERT_STATE( m_IndexPage.IsAssigned() );
    SAPDBERR_ASSERT_STATE( m_IndexPage.GetLevel() > LEAF_LEVEL_BD00 );

    Data_Level  level = m_IndexPage.GetLevel();

    while(( LEAF_LEVEL_BD00 < level ) && ( e_ok == m_TrError ))
    {
        const tgg00_Rec    *pSeparator      = m_IndexPage.GetRecord( FIRST_REC_INDEX_BD00 );
        const Data_PageNo   childPagePageNo = pSeparator->recPno_gg00().gg90GetInt4();

        if( FIRST_INDEX_LEVEL_BD00 < level )
        {
            m_PageAccessManager.ReleasePage( m_IndexPage );

            if( m_PageAccessManager.GetPage( m_IndexPage, childPagePageNo ))
                level = m_IndexPage.GetLevel();
        }
        else
        {
            SAPDBERR_ASSERT_STATE( FIRST_INDEX_LEVEL_BD00 == level );

            m_CurrRecIndex       = FIRST_REC_INDEX_BD00;
            m_CurrNumberOfLeaves = m_IndexPage.GetRecordCount();

            if( m_PageAccessManager.GetPage( m_LeafPage, childPagePageNo ))
                level = m_LeafPage.GetLevel();
        }
    }
    return( e_ok == m_TrError );
}

/*---------------------------------------------------------------------------*/

SAPDB_Bool
Data_IndexScanTreeAccess::GetNextLeafNode()
{
    SAPDBERR_ASSERT_STATE( e_ok == m_TrError );
    SAPDBERR_ASSERT_STATE( m_LeafPage.IsAssigned() );

    m_PageAccessManager.ReleasePage( m_LeafPage );

    if( ! m_IndexPage.IsAssigned()){
        return( SAPDB_FALSE ); // root is leaf
    }

    SAPDB_UInt  recCount      = m_IndexPage.GetRecordCount();
    SAPDB_UInt  currStepWidth = m_StepWidth;

    while( m_CurrRecIndex + currStepWidth >= recCount )
    {
        // right neigbhor
        const Data_PageNo nextPageNo = m_IndexPage.Successor();
        currStepWidth = m_StepWidth - ( recCount - m_CurrRecIndex );

        if( ! nextPageNo.IsValid() )
            return( SAPDB_FALSE );

        m_PageAccessManager.ReleasePage( m_IndexPage );
        m_PageAccessManager.GetPage( m_IndexPage, nextPageNo );

        recCount              = m_IndexPage.GetRecordCount();
        m_CurrRecIndex        = FIRST_REC_INDEX_BD00;
        m_CurrNumberOfLeaves += recCount;
    }

    m_CurrRecIndex += currStepWidth;

    const tgg00_Rec    *pSeparator      = m_IndexPage.GetRecord( m_CurrRecIndex );
    const Data_PageNo   childPagePageNo = pSeparator->recPno_gg00().gg90GetInt4();

    m_PageAccessManager.GetPage( m_LeafPage, childPagePageNo  );

    return( e_ok == m_TrError );
}

/*===========================================================================*
 *  END OF CODE                                                              *
 *===========================================================================*/
