///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoExpOutStream.cc 
// -------------------
// Cego export outstream implementation
//     
// Design and Implementation by Bjoern Lemke               
//     
// (C)opyright 2000-2025 Bjoern Lemke
//
// IMPLEMENTATION MODULE
//
// Class: CegoExpOutStream
// 
// Description: Database XML and binary export handle
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

// LFC INCLUDES
#include <lfcbase/Base64Coder.h>

// CEGO INCLUDES
#include "CegoExpOutStream.h"
#include "CegoXMLdef.h"

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

CegoExpOutStream::CegoExpOutStream(unsigned tabSetId, const Chain& tableName, const ListT<CegoField>& schema, CegoQueryManager* pGTM, CegoAdminHandler* pAH)
{
    _pGTM = pGTM;
    _pAH = pAH;
    _tableName = tableName;
    _pOC = pGTM->getObjectCursor(tabSetId, tableName, tableName, CegoObject::TABLE);
    _schema = schema;
    _tabSetId = tabSetId;
}

CegoExpOutStream::~CegoExpOutStream()
{   
    delete _pOC;
}

unsigned long long CegoExpOutStream::numExported() const
{
    return _rowCount;
}

Element* CegoExpOutStream::getFirst()
{
    CegoDataPointer dp;

    _rowCount = 0;
    
    if ( _pAH )
    {
	Chain info = Chain("Exporting table data for ") +  _tableName + Chain(" ...");
	_pAH->sendInfo(info + Chain("\n"));
    }

    if ( _pGTM->getFirstTuple(_pOC, _schema, dp ) )
    {
	_rowCount++;
	return getRowElement(_schema);
    }
    else
    {
	Element* pRowElement = new Element(XML_NOROWS_ELEMENT);
	return pRowElement;	
    }
}

Element* CegoExpOutStream::getNext()
{
    CegoDataPointer dp;
    if ( _pGTM->getNextTuple(_pOC, _schema, dp ) )
    {
	_rowCount++;

	if ( _pAH && ( _rowCount % XP_ROWINTERVAL == 0 ) )
	    _pAH->sendInfo(Chain(_rowCount) + Chain(" rows\r"));
	
	return getRowElement(_schema);
    }

    if ( _pAH )
	_pAH->sendInfo(Chain(_rowCount) + Chain(" rows exported\n"));
			   
    return 0;
}

Element* CegoExpOutStream::getRowElement(ListT<CegoField>& schema)
{
    Element* pRowElement = new Element(XML_ROW_ELEMENT);
    
    unsigned long long nextBlobId=0;
    unsigned long long nextClobId=0;
    
    CegoField *pF = schema.First();
    while ( pF ) 
    {
	if ( ! pF->getValue().isNull() )
	{
	    if ( pF->getType() == BLOB_TYPE )
	    {
		Chain blobId = Chain(XML_BLOBPREFIX) + Chain(nextBlobId);
		nextBlobId++;
		pRowElement->setAttribute(pF->getAttrName(), blobId);
		
		PageIdType pageId;
		memcpy(&pageId, pF->getValue().getValue(), sizeof(PageIdType));
		
		unsigned long long blobSize;
		unsigned char* blobBuf = _pGTM->getBlobData(_tabSetId, pageId, blobSize);

		Base64Coder b64;
		pRowElement->addData(b64.encode(blobSize, blobBuf));	     			
	    }
	    else if ( pF->getType() == CLOB_TYPE )
	    {
		
		Chain clobId = Chain(XML_CLOBPREFIX) + Chain(nextClobId);
		nextClobId++;
		pRowElement->setAttribute(pF->getAttrName(), clobId);
		
		PageIdType pageId;
		memcpy(&pageId, pF->getValue().getValue(), sizeof(PageIdType));
		
		unsigned long long clobSize;
		char* clobBuf = _pGTM->getClobData(_tabSetId, pageId, clobSize);
		
		pRowElement->addData(clobBuf);
		
	    }
	    else
	    {
		pRowElement->setAttribute(pF->getAttrName(), pF->getValue().valAsChain());
	    }
	}
	pF = _schema.Next();
    }
    return pRowElement;
}
