///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoBlob.cc
// ------------
// Cego blob implementation
//      
// Design and Implementation by Bjoern Lemke
//     
// (C)opyright 2000-2025 Bjoern Lemke
//
// IMPLEMENTATION MODULE
//
// Class: CegoBlob
//
// Description: Binary large object container class
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

// CEGO INCLUDES
#include "CegoBlob.h"

// LFC INCLUDES
#include <lfcbase/Exception.h>
#include <lfcbase/File.h>

// POSIX INCLUDES
#include <string.h>
#include <stdlib.h>

CegoBlob::CegoBlob()
{
    _buf = 0;
    _size = 0;
    _pageId = 0;
}

CegoBlob::CegoBlob(PageIdType pageId)
{
    _buf = 0;
    _size = 0;
    _pageId = pageId;
}

CegoBlob::CegoBlob(PageIdType pageId, unsigned char *blobBuf, unsigned long long blobSize)
{
    _buf = blobBuf;
    _size = blobSize;
    _pageId = pageId;
}

CegoBlob::~CegoBlob()
{
}

void CegoBlob::readBlob(const Chain& fileName)
{
    if ( _buf )
	free ( _buf);
    
    File blobFile(fileName);
    blobFile.open(File::READ);
    
    _size = blobFile.Size();
    _buf = (unsigned char*)malloc(_size);
    
    unsigned long long rb; 
    unsigned char *bufPtr = _buf;
    
    while ( ( rb = blobFile.readByte((char*)bufPtr, BLOB_BLOCKSIZE)) > 0  )
    {
	bufPtr += rb;
    }

    blobFile.close();
    reset();
}

void CegoBlob::writeBlob(const Chain& fileName)
{
    File blobFile(fileName);
    blobFile.open(File::WRITE);
    
    unsigned char *bufPtr = _buf;

    unsigned long long wb = _size > BLOB_BLOCKSIZE ? BLOB_BLOCKSIZE : _size;

    blobFile.writeByte((char*)bufPtr, wb);

    unsigned long long writtenByte = wb;

    while ( writtenByte < _size )  
    {
	bufPtr += wb;
	wb = _size - wb > BLOB_BLOCKSIZE ? BLOB_BLOCKSIZE : _size - wb;
	blobFile.writeByte((char*)bufPtr, wb);
	writtenByte += wb;
    }

    blobFile.close();   
}
    
unsigned long long CegoBlob::getSize() const
{
    return _size;
}

unsigned char* CegoBlob::getBufPtr()
{
    return _buf;
}

void CegoBlob::allocate(unsigned long long size)
{    
    if ( _buf )
	free ( _buf);
    
    _size = size;
    _buf = (unsigned char*)malloc(_size);
}

void CegoBlob::release()
{
    if ( _buf )
    {
	free ( _buf);
	_buf = 0;
    }
}

void CegoBlob::reset()
{
    _chunkPtr = _buf;
    _chunkSize = 0;
    return;
}

bool CegoBlob::nextChunk(unsigned long long chunkSize)
{
    _chunkPtr += _chunkSize;

    if ( _chunkPtr >= _buf + _size )
	return false;
    
    if ( _chunkPtr + chunkSize < _buf + _size )
	_chunkSize = chunkSize;
    else
	_chunkSize = _buf + _size - _chunkPtr;   
    return true;
}

void CegoBlob::putChunk(unsigned char *chunkBuf, unsigned long long chunkSize)
{
    if ( _chunkPtr - _buf + chunkSize > _size )
	throw Exception(EXLOC, "Blob buffer exceeded");

    memcpy(_chunkPtr, chunkBuf, chunkSize);
    _chunkPtr += chunkSize;
}

unsigned char* CegoBlob::getChunkPtr()
{
    return _chunkPtr;
}

unsigned long long CegoBlob::getChunkSize()
{
    return _chunkSize;
}

void CegoBlob::setPageId(PageIdType pageId)
{
    _pageId = pageId;
}

PageIdType CegoBlob::getPageId() const
{
    return _pageId;
}

CegoBlob& CegoBlob::operator = ( const CegoBlob& b)
{
    _size = b._size;
    _pageId = b._pageId;
    _buf = b._buf;
    _chunkSize = b._chunkSize;
    _chunkPtr = b._chunkPtr;
    return (*this);
}

bool CegoBlob::operator == ( const CegoBlob& b)
{
    if ( _pageId == b._pageId )
	return true;
    return false;
}

Chain CegoBlob::toChain() const
{
    Chain s;
    s = "N/A";    
    return s;
}
    
ostream& operator << (ostream& s, const CegoBlob& qe)
{    
    s << qe.toChain();
    return s;
}
