///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoBlob.cc
// ------------
// Cego blob 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: CegoBlob
// 
// Description: 
//
// Status: QG-2.6
//
///////////////////////////////////////////////////////////////////////////////

#include "CegoBlob.h"

#include <lfc/Exception.h>
#include <lfc/File.h>

#include "CegoDefs.h"

#include <string.h>
#include <stdlib.h>

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

CegoBlob::CegoBlob(int fileId, int pageId)
{
    _buf = 0;
    _size = 0;
    _fileId = fileId;
    _pageId = pageId;
}

CegoBlob::CegoBlob(int fileId, int pageId, unsigned char *blobBuf, long blobSize)
{
    _buf = blobBuf;
    _size = blobSize;
    _fileId = fileId;
    _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 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 wb = _size > BLOB_BLOCKSIZE ? BLOB_BLOCKSIZE : _size;

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

    int 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();
    
}
    
long CegoBlob::getSize() const
{
    return _size;
}

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

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

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

bool CegoBlob::nextChunk(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, 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;
}

int CegoBlob::getChunkSize()
{
    return _chunkSize;
}

void CegoBlob::setFileId(int fileId)
{
    _fileId = fileId;
}

int CegoBlob::getFileId() const
{
    return _fileId;
}

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

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

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

bool CegoBlob::operator == ( const CegoBlob& b)
{
    if ( _fileId == b._fileId && _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;
}
