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

// CEGO INCLUDES
#include "CegoClob.h"

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

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

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

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

CegoClob::CegoClob(char *clobBuf, unsigned long long clobSize)
{
    _buf = clobBuf;
    _size = clobSize;
    _pageId = 0;
}

CegoClob::CegoClob(PageIdType pageId, char *clobBuf, unsigned long long clobSize)
{
    _buf = clobBuf;
    _size = clobSize;
    _pageId = pageId;
}

CegoClob::~CegoClob()
{
}

void CegoClob::readClob(const Chain& fileName)
{    
    if ( _buf )
	free ( _buf);
    
    File clobFile(fileName);
    clobFile.open(File::READ);
    
    _size = clobFile.Size();
    _buf = (char*)malloc(_size);
    
    unsigned long long rb; 
    char *bufPtr = _buf;
    
    while ( ( rb = clobFile.readByte((char*)bufPtr, CLOB_BLOCKSIZE)) > 0  )
    {
	bufPtr += rb;
    }
    
    clobFile.close();
    reset();
}

void CegoClob::writeClob(const Chain& fileName)
{
    File clobFile(fileName);
    clobFile.open(File::WRITE);
    
    char *bufPtr = _buf;

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

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

    unsigned long long writtenByte = wb;

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

    clobFile.close();   
}
    
unsigned long long CegoClob::getSize() const
{
    return _size;
}

char* CegoClob::getBufPtr()
{
    return _buf;
}

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

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

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

bool CegoClob::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 CegoClob::putChunk(char *chunkBuf, unsigned long long chunkSize)
{
    if ( _chunkPtr - _buf + chunkSize > _size )
	throw Exception(EXLOC, "Clob buffer exceeded");

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

char* CegoClob::getChunkPtr()
{
    return _chunkPtr;
}

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

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

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

Chain CegoClob::getHead() const
{
    Chain h;
    if ( _size < 10 )
    {
	h = valAsChain();
    }
    else
    {
	h = Chain(_buf, 10) + Chain("...");
    }
    return h;
}

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

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

Chain CegoClob::toChain() const
{
    Chain ref = Chain("[") + Chain(_pageId) + Chain("]"); 
    return ref;
}

Chain CegoClob::valAsChain() const
{
    Chain s(_buf, _size);
    return s;
}

ostream& operator << (ostream& s, const CegoClob& qe)
{    
    s << qe.valAsChain();
    return s;
}
