/*!
 * \file    LVC_BufferedSingleFileObjKeyIterator.cpp
 * \author  MarkusSi
 * \brief   Buffered key range iterator to access non-partitioned key objects
 */		

/*
    ========== 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

*/


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

#include "gbd900.h"
#include "hbd03.h"
#include "RunTime/RTE_Message.hpp"
#include "liveCache/LVC_ObjKeyIterator.hpp"
#include "liveCache/LVC_Messages.hpp" 
#include "liveCache/LVC_Types.hpp"
#include "liveCache/LVC_BufferedSingleFileObjKeyIterator.hpp"



/*===========================================================================*
 *  EXTERNAL VARIABLES                                                       *
 *===========================================================================*/

extern cbd900_ObjFileDir          bd90ObjFileDir;

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

  /*!-------------------------------------------------------------------------
  function:     GetNextOIdsWithKey()
  description:  see LVC_AbstractObjKeyIterator::GetNextOIds
  New function since: PTS 1134856 
  --------------------------------------------------------------------------*/
void 
LVC_BufferedSingleFileObjKeyIterator::GetNextOIdsWithKey(void            *pRestartKey,
                                                         tgg92_KernelOid *pOId, 
                                                         tsp00_Int4      &noOfOid, 
                                                         void            *pKey,
                                                         int             &KeySize,
                                                         SAPDB_Bool       bInclusive)
{
  noOfOid = 0;
  m_Trans.trError_gg00 = e_not_implemented;
};
;
/*---------------------------------------------------------------------------*/

void
LVC_BufferedSingleFileObjKeyIterator::GetNextOIds (void             *pRestartKey,
                                                   tgg92_KernelOid  *pOid, 
                                                   tsp00_Int4       &noOfOid,
                                                   SAPDB_Bool        bInclusive)
{
	ROUTINE_DBG_MEO00 ("LVC_BufferedSingleFileObjKeyIterator::GetNextOIds");

  SAPDBERR_ASSERT_STATE (IsValid());

	tgg00_BasisError      &TrError        = m_Trans.trError_gg00;
	cbd900_ObjFileInfo    &ObjFileInfo    = bd90ObjFileDir [m_ObjFileNo];
	
	/* check if the object file which belongs to this iterator still exists */ 
	if (ObjFileInfo.GetRootPage() == NIL_PAGE_NO_GG00 || ObjFileInfo.ofiRelFileIsReq_bd900)
	{
		TrError = e_file_not_found;
		LVC_Exception Error(__CONTEXT__, LVC_ITERATOR_RUNS_ON_REMOVED_FILE, 
                        SAPDB_ToString (m_ObjFileNo, _T_d));
		RTE_Message (Error);
	}

  int maxNoOfOid = noOfOid;
  noOfOid        = 0;
  for (int i=0; i<maxNoOfOid; ++i){
    if (m_curr < m_oidsInBuffer-1){
      // Return Oid from the buffer
      pOid[i] = m_oidBuffer[++m_curr];
      ++noOfOid;
    }
    else if (m_NoMoreOIds){
      // All oids have been read from the iterator and the buffer is empty
      m_curr = -1;
      break;
    }
    else {
      m_curr = -1;

		  /* fill buffer with new OIds from the index tree */
		  cbd900_ObjKeyFileId  ObjKeyFileId (ObjFileInfo, m_ObjFileNo, m_ObjKeyFileIndex);
  	
		  /* create an iterator to access the index tree */
		  SAPDB_Bool bStartKeyFound;                          // unused parameter
		  LVC_ObjKeyIterator ObjKeyIterator (m_Trans, ObjKeyFileId, m_KeyLen, bInclusive, 
                                        pRestartKey ? pRestartKey : &m_LastKey[0], 
                                        &m_UpperKey, bStartKeyFound, 
                                        ASCENDING_KEY_ORDER_BD510);
  		
		  void* pLastKey = NULL;
      for (m_oidsInBuffer=0; m_oidsInBuffer<MAX_OID_BUFFER_SIZE; ++m_oidsInBuffer){
        if (e_ok != TrError){
          m_curr         = -1;
          noOfOid        = 0;
          m_NoMoreOIds   = true;
          return;
        }
        else if (ObjKeyIterator.IsReady()){
          m_NoMoreOIds = true;
          break;
        }
        /* Insert OID into buffer */
        m_oidBuffer[m_oidsInBuffer] = ObjKeyIterator.GetOId();
        pLastKey = ObjKeyIterator.GetKeyPtr();
        ++ObjKeyIterator;
      }

      if (m_oidsInBuffer > 0){
        m_curr  = 0;
        pOid[i] = m_oidBuffer[m_curr];
        ++noOfOid;

        // Remember key, that has been read last. This is needed as there might be more subsequent
        // invalid objects (objects which do not belong to the consistent view or objects which 
        // have been modified in an unloaded version) than there is space to store oids in the 
        // buffer. In this case the pRestartKey will never change and this would result in
        // an infinite loop. Therefore in such a case the pRestartKey is set to NULL by the higher 
        // layers and the member m_LastKey is used instead 
        memcpy (&m_LastKey[0], pLastKey, m_KeyLen);
      }
    }
  }
}

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

void
LVC_BufferedSingleFileObjKeyIterator::GetPrevOIds (void             *pRestartKey,
                                                   tgg92_KernelOid  *pOid, 
                                                   tsp00_Int4       &noOfOid,
                                                   SAPDB_Bool        bInclusive)
{
	ROUTINE_DBG_MEO00 ("LVC_BufferedSingleFileObjKeyIterator::GetPrevOIds");

  SAPDBERR_ASSERT_STATE (IsValid());

	tgg00_BasisError      &TrError        = m_Trans.trError_gg00;
	cbd900_ObjFileInfo    &ObjFileInfo    = bd90ObjFileDir [m_ObjFileNo];
	
	/* check if the object file which belongs to this iterator still exists */ 
	if (ObjFileInfo.GetRootPage() == NIL_PAGE_NO_GG00 || ObjFileInfo.ofiRelFileIsReq_bd900)
	{
		TrError = e_file_not_found;
		LVC_Exception Error(__CONTEXT__, LVC_ITERATOR_RUNS_ON_REMOVED_FILE, 
                        SAPDB_ToString (m_ObjFileNo, _T_d));
		RTE_Message (Error);
	}

  int maxNoOfOid = noOfOid;
  noOfOid        = 0;
  for (int i=maxNoOfOid-1; i>=0; --i){
    if (m_curr > 0){
      // Return Oid from the buffer
      pOid[i] = m_oidBuffer[--m_curr];
      ++noOfOid;
    }
    else if (m_NoMoreOIds){
      // All oids have been read from the iterator and buffer is empty
      m_curr = -1;
      break;
    }
    else {
      m_curr = -1;

		  /* fill buffer with new OIds from the index tree */
		  cbd900_ObjKeyFileId  ObjKeyFileId (ObjFileInfo, m_ObjFileNo, m_ObjKeyFileIndex);
  	
		  /* create an iterator to access the index tree */
		  SAPDB_Bool bStartKeyFound;                          // unused parameter
		  LVC_ObjKeyIterator ObjKeyIterator (m_Trans, ObjKeyFileId, m_KeyLen, bInclusive, 
                                        pRestartKey ? pRestartKey : &m_LastKey[0], 
                                        &m_LowerKey, bStartKeyFound, 
                                        !ASCENDING_KEY_ORDER_BD510);
  		
		  void* pLastKey = NULL;
      for (m_oidsInBuffer=0; m_oidsInBuffer<MAX_OID_BUFFER_SIZE; ++m_oidsInBuffer){
        if (e_ok != TrError){
          m_curr         = -1;
          noOfOid        = 0;
          m_NoMoreOIds   = true;
          return;
        }
        else if (ObjKeyIterator.IsReady()){
          m_NoMoreOIds   = true;
          break;
        }
        /* Insert OID into buffer */
        m_oidBuffer[MAX_OID_BUFFER_SIZE-(m_oidsInBuffer+1)] = ObjKeyIterator.GetOId();
        pLastKey = ObjKeyIterator.GetKeyPtr();
        ++ObjKeyIterator;
      }

      if (m_oidsInBuffer > 0){
        if (m_oidsInBuffer < MAX_OID_BUFFER_SIZE){
          // If array is not filled completely, then shift the entries in the array 
          // to the left side
          int j;
          for (j=0; j<m_oidsInBuffer; ++j){
            m_oidBuffer[j] = m_oidBuffer[j+MAX_OID_BUFFER_SIZE-m_oidsInBuffer];
          }
          //for (j=m_oidsInBuffer; j<MAX_OID_BUFFER_SIZE; ++j){   // TODO Not needed! Performance!
          //  m_oidBuffer[j].gg92SetNil();
          //}
        }

        m_curr  = m_oidsInBuffer-1;
        pOid[i] = m_oidBuffer[m_curr];
        ++noOfOid;

        // Remember key, that has been read last. This is needed as there might be more subsequent
        // invalid objects (objects which do not belong to the consistent view or objects which 
        // have been modified in an unloaded version) than there is space to store oids in the 
        // buffer. In this case the pRestartKey will never change and this would result in
        // an infinite loop. Therefore in such a case the pRestartKey is set to NULL by the higher 
        // layers and the member m_LastKey is used instead 
        memcpy (&m_LastKey[0], pLastKey, m_KeyLen);
      }
    }
  }

  if (noOfOid < maxNoOfOid){
    // If return array is not filled completely, then shift the entries in the array
    // to the left side
    int j;
    for (j=0; j<maxNoOfOid-(noOfOid+1); ++j){
      pOid[j] = pOid[j+(noOfOid+1)];
    }
    //for (j=maxNoOfOid-(noOfOid+1); j<maxNoOfOid; ++j){ // TODO Not needed! Performance!
    //  pOid[j].gg92SetNil();
    //}
  }
}

/*---------------------------------------------------------------------------*/
LVC_BufferedSingleFileObjKeyIterator::LVC_BufferedSingleFileObjKeyIterator 
                             (tgg00_TransContext     &Trans,
    		                      tgg00_FileId	         &ObjFileId,
		                          tsp00_Int4	            KeyLen,
		                          void		               *pStartKey,
		                          void		               *pLowerKey,          
		                          void		               *pUpperKey,         
		                          SAPDBMem_IRawAllocator &Allocator,
                              bool                    bAscendingKeyOrder) 
:
LVC_AbstractObjKeyIterator (Trans, ObjFileId, KeyLen, pLowerKey, pUpperKey, bAscendingKeyOrder),	 
m_Allocator                (Allocator),
m_ObjKeyFileIndex          (0),           // = index first key file 
m_ObjFileNo                (ObjFileId.fileObjFileNo_gg00()),
m_CheckNumber              (m_StaticCheckNumber), 
m_NoMoreOIds               (false),
m_oidsInBuffer             (0),
m_curr                     (0)
{}

/*---------------------------------------------------------------------------*/
// PTS 1119480
void LVC_BufferedSingleFileObjKeyIterator::ChangeDirection (void*  pRestartKey,
                                                    bool   bAscendingKeyOrder)
{
  m_NoMoreOIds         = false;
  m_bAscendingKeyOrder = bAscendingKeyOrder;
  m_ObjKeyFileIndex    = 0;

  // TODO!!
}

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

const tsp00_Int4  LVC_BufferedSingleFileObjKeyIterator::m_StaticCheckNumber = 817;

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