///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoObjectCursor.cc
// -------------------
// Cego object cursor class implementation
//      
// Design and Implementation by Bjoern Lemke
//     
// (C)opyright 2000-2010 Bjoern Lemke
//
// 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, 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; see the file COPYING.  If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
//
// IMPLEMENTATION MODULE
//
// Class: CegoObjectCursor
// 
// Description: A cursor, to trace native database objects
//
// Status: QG-2.6
//
///////////////////////////////////////////////////////////////////////////////

// cego includes
#include "CegoDefs.h"
#include "CegoObjectCursor.h"

CegoObjectCursor::CegoObjectCursor()
{
}

CegoObjectCursor::CegoObjectCursor(CegoBufferPool *pBufPool, CegoLockHandler *pLockHandle, 
				   int tabSetId, 
				   CegoObject::ObjectType type, 
				   int fileId, int pageId)
{
    _pBufPool = pBufPool;
    _pLockHandle = pLockHandle;

    _tabSetId = tabSetId;

    _fileId = fileId;
    _pageId = pageId;

    _startFileId = fileId;
    _startPageId = pageId;
    
    _type = type;
    
    _lockId = 0;
    _recLock = 0;
    
    _isEOC = false;

    _modId = _pBufPool->getModId("CegoObjectCursor");
}

CegoObjectCursor::~CegoObjectCursor()
{
    abort();
}

int CegoObjectCursor::getTabSetId()
{
    return _tabSetId;
}

void* CegoObjectCursor::getFirst(int& len, CegoDataPointer& dp)
{

    if ( _isEOC )
	return 0;

    
    try {
	
	_pBufPool->bufferFix(_bp,_tabSetId, _fileId, _pageId, CegoBufferPool::SYNC, _pLockHandle);
	
	try
	{
	    _lockId = _pLockHandle->lockData(_type, _fileId, _pageId, CegoLockHandler::READ);
	}
	catch ( Exception e)
	{
	    Chain msg;
	    e.pop(msg);
	    
	    _lockId = 0;
	    
	    _pBufPool->log(_modId, Logger::LOGERR, Chain("Data page lock error for fileId=") 
			   + Chain(_fileId) + Chain(" pageId=") + Chain(_pageId) + Chain(" : ") +  msg);		
	    _pBufPool->bufferUnfix(_bp, false, _pLockHandle);
	    throw Exception(EXLOC, msg);
	}
	
	if ( void* p = _bp.getFirstEntry() )
	{
	    dp.setFileId(_fileId);
	    dp.setPageId(_pageId);
	    
	    len = _bp.getEntryLen();
	    dp.setOffset(_bp.getEntryPos());
	    
	    _recLock = 0;
	    
	    if ( _type == CegoObject::RBSEG )
		_recLock = _pLockHandle->lockRBRecord(_bp, dp, CegoLockHandler::READ);
	    else
		_recLock = _pLockHandle->lockRecord(_bp, dp, CegoLockHandler::READ);
	    
	    return p;
	}
	else
	{	
	    _pLockHandle->unlockData(_type, _lockId);    
	    _lockId = 0;
	    
	    _fileId = _bp.getNextFileId();
	    _pageId = _bp.getNextPageId();
	    
	    _pBufPool->bufferUnfix(_bp, false, _pLockHandle);
	    
	    while ( ! ( _fileId == 0 && _pageId == 0 ) )
	    {
		
		CegoBufferPage nbp;						
		
		_pBufPool->bufferFix(nbp, _tabSetId, _fileId, _pageId, CegoBufferPool::SYNC, _pLockHandle);
		
		_bp = nbp;
		
		try
		{
		    _lockId = _pLockHandle->lockData(_type, _fileId, _pageId, CegoLockHandler::READ);
		}
		catch ( Exception e)
		{
		    _lockId = 0;
		    
		    Chain msg;
		    e.pop(msg);			    
		    _pBufPool->log(_modId, Logger::LOGERR, Chain("Data page lock error for fileId=") 
				   + Chain(_fileId) + Chain(" pageId=") + Chain(_pageId) + Chain(" : ") +  msg);		
		    
		    
		    _pBufPool->bufferUnfix(_bp, false, _pLockHandle);
		    
		    throw e;
		}
		
		if ( void* p = _bp.getFirstEntry())
		{
		    
		    dp.setFileId(_fileId);
		    dp.setPageId(_pageId);
		    
		    len = _bp.getEntryLen();
		    dp.setOffset(_bp.getEntryPos());
		    
		    _recLock = 0;
		    
		    if ( _type == CegoObject::RBSEG )
			_recLock = _pLockHandle->lockRBRecord(_bp, dp, CegoLockHandler::READ);
		    else
			_recLock = _pLockHandle->lockRecord(_bp, dp, CegoLockHandler::READ);
		    
		    return p;
		}
		else
		{
		    _pLockHandle->unlockData(_type, _lockId);    
		    _lockId = 0;
		    
		    _fileId = _bp.getNextFileId();
		    _pageId = _bp.getNextPageId();
		    
		    _pBufPool->bufferUnfix(_bp, false, _pLockHandle);
		}
	    }
	    _isEOC = true;
	    return 0;
	} 
    }
    catch ( Exception e)
    {
	abort();
	throw Exception(EXLOC, Chain("Object cursor failed"), e);			    
    }
}

void* CegoObjectCursor::getNext(int& len, CegoDataPointer& dp)
{
    
    if ( _isEOC )
	return 0;

    if ( _recLock > 0 )
    {
	if ( _type == CegoObject::RBSEG )
	    _pLockHandle->unlockRBRecord(_recLock);
	else
	    _pLockHandle->unlockRecord(_recLock);

	_recLock = 0;
    }

    
    try
    {
	
	void* p = _bp.getNextEntry();    
	if ( p )
	{
	    
	    dp.setFileId(_fileId);
	    dp.setPageId(_pageId);
	    
	    len = _bp.getEntryLen();
	    dp.setOffset(_bp.getEntryPos());
	    
	    if ( _type == CegoObject::RBSEG )
		_recLock = _pLockHandle->lockRBRecord(_bp, dp, CegoLockHandler::READ);
	    else
		_recLock = _pLockHandle->lockRecord(_bp, dp, CegoLockHandler::READ);
	    
	    return p;
	}
	else
	{
	    
	    _pLockHandle->unlockData(_type, _lockId);    
	    _lockId = 0;
	    
	    _fileId = _bp.getNextFileId();
	    _pageId = _bp.getNextPageId();
	    
	    _pBufPool->bufferUnfix(_bp, false, _pLockHandle);
	    
	    while ( ! ( _fileId == 0 && _pageId == 0 ) )
	    {
		
		CegoBufferPage nbp;
		_pBufPool->bufferFix(nbp, _tabSetId, _fileId, _pageId, CegoBufferPool::SYNC, _pLockHandle);
		
		_bp = nbp;
		
		try
		{
		    _lockId = _pLockHandle->lockData(_type, _fileId, _pageId, CegoLockHandler::READ);
		}
		catch ( Exception e )
		{
		    _lockId = 0;
		    
		    Chain msg;
		    e.pop(msg);
		    _pBufPool->log(_modId, Logger::LOGERR, Chain("Data page lock error for fileId=") 
				   + Chain(_fileId) + Chain(" pageId=") + Chain(_pageId) + Chain(" : ") +  msg);			    
		    _pBufPool->bufferUnfix(_bp, false, _pLockHandle);
		    
		    throw e;
		}
		
		if ( void* p = _bp.getFirstEntry())
		{
		    
		    dp.setFileId(_fileId);
		    dp.setPageId(_pageId);
		    
		    len = _bp.getEntryLen();
		    dp.setOffset(_bp.getEntryPos());
		    
		    if ( _type == CegoObject::RBSEG )
			_recLock = _pLockHandle->lockRBRecord(_bp, dp, CegoLockHandler::READ);
		    else
			_recLock = _pLockHandle->lockRecord(_bp, dp, CegoLockHandler::READ);
		    		    
		    return p;
		}
		else
		{
		    _pLockHandle->unlockData(_type, _lockId);    
		    _lockId = 0;
		    
		    _fileId = _bp.getNextFileId();
		    _pageId = _bp.getNextPageId();
			
		    _pBufPool->bufferUnfix(_bp, false, _pLockHandle);
		}
	    }
	    _isEOC = true;	
	    return 0;
	}
    }	
    catch ( Exception e)
    {	    	    
	abort();
	throw Exception(EXLOC, Chain("Object cursor failed"), e);
    }
}

void CegoObjectCursor::abort()
{
    if (_bp.isFixed())
    {
	_pBufPool->bufferUnfix(_bp, false, _pLockHandle);
    }
    if (_lockId > 0 )
    {
	_pLockHandle->unlockData(_type, _lockId);
	_lockId = 0;
    }
    
    if ( _recLock > 0 )
    {
	if ( _type == CegoObject::RBSEG )
	    _pLockHandle->unlockRBRecord(_recLock);
	else
	    _pLockHandle->unlockRecord(_recLock);

	_recLock = 0;
    }
    
    _isEOC = true;

}

void CegoObjectCursor::reset()
{
    abort();
    _isEOC = false;
    _fileId = _startFileId;
    _pageId = _startPageId;
}

