///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoLogRecord.cc
// ----------------
// Cego Log Record class implementation
//                                                         
// Design and Implementation by Bjoern Lemke               
//     
// (C)opyright 2000-2025 Bjoern Lemke
//
// IMPLEMENTATION MODULE
//
// Class: CegoLogRecord
//
// Description: Log record data structure
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

// CEGO INCLUDES
#include "CegoLogRecord.h"

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

CegoLogRecord::CegoLogRecord()
{
    _encObj = false;
    _dataLen=0;
    _data = 0;
    _ts=0;
    _tid=0;
    _tastep=0;
    _lsn=0;
}

CegoLogRecord::~CegoLogRecord()
{
}

unsigned long long CegoLogRecord::getLSN() const
{
    return _lsn;
}

void CegoLogRecord::setLSN(unsigned long long lsn)
{
    _lsn = lsn;
}

unsigned long long CegoLogRecord::getTID() const
{
    return _tid;
}

void CegoLogRecord::setTID(unsigned long long tid)
{
    _tid = tid;
}

unsigned long long CegoLogRecord::getTAStep() const
{
    return _tastep;
}

void CegoLogRecord::setTAStep(unsigned long long tastep)
{
    _tastep = tastep;
}

long long CegoLogRecord::getTS() const
{
    return _ts;
}

void CegoLogRecord::setTS(long long ts)
{
    _ts = ts;
}

void CegoLogRecord::setObjectInfo(const Chain& objName, CegoObject::ObjectType objType)
{
    _objName = objName;
    _objType = objType;
    _encObj = true;
}

const Chain& CegoLogRecord::getObjName() const
{
    return _objName;
}

CegoObject::ObjectType CegoLogRecord::getObjType() const
{
    return _objType;
}

CegoLogRecord::LogAction CegoLogRecord::getAction() const
{
    return _logAction;
}

void CegoLogRecord::setAction(LogAction a)
{
    _logAction = a;
}

char* CegoLogRecord::getData() const
{
    return _data;
}
 
void CegoLogRecord::setData(char* data)
{
    _data = data;
}

unsigned CegoLogRecord::getDataLen() const
{
    return _dataLen;
}

void CegoLogRecord::setDataLen(unsigned l)
{
    _dataLen = l;
}

unsigned CegoLogRecord::getFileId() const
{
    return _fileId;
}

void CegoLogRecord::setFileId(unsigned fileId)
{
    _fileId = fileId;
}

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

void CegoLogRecord::setPageId(PageIdType pageId)
{
    _pageId = pageId;
}
 
unsigned CegoLogRecord::getEncodingLength() const
{
    // 4 * sizeof(unsigned long long) => lsn, tid, ts
    unsigned len = 3 * sizeof(unsigned long long) + sizeof(CegoLogRecord::LogAction);

    if ( _tid > 0 )
	len += sizeof(unsigned long long);
    
    if ( _logAction == CegoLogRecord::LOGREC_BUPAGE )
	len += sizeof(PageIdType) ;
    else if ( _logAction == CegoLogRecord::LOGREC_BUFBM )
	len += sizeof(unsigned);
    else
    {
	len++; // obj flag
	if ( _encObj )
	    len += _objName.length() + sizeof(CegoObject::ObjectType);
    }

    len += sizeof(unsigned);
    len += _dataLen;

    return len;
}

void CegoLogRecord::encode(void* p) const
{    
    char* lrp = (char*)p;
    
    memcpy( lrp, &_lsn, sizeof(unsigned long long));
    lrp = lrp + sizeof(unsigned long long);

    memcpy( lrp, &_tid, sizeof(unsigned long long));
    lrp = lrp + sizeof(unsigned long long);

    if ( _tid > 0 )
    {
	memcpy( lrp, &_tastep, sizeof(unsigned long long));
	lrp = lrp + sizeof(unsigned long long);
    }
    
    memcpy( lrp, &_ts, sizeof(unsigned long long));
    lrp = lrp + sizeof(unsigned long long);

    memcpy( lrp, &_logAction, sizeof(CegoLogRecord::LogAction));
    lrp = lrp + sizeof(CegoLogRecord::LogAction);
    
    if ( _logAction == CegoLogRecord::LOGREC_BUPAGE )
    {
	memcpy( lrp, &_pageId, sizeof(PageIdType));
	lrp = lrp + sizeof(PageIdType);
    }
    else if ( _logAction == CegoLogRecord::LOGREC_BUFBM )
    {
	memcpy( lrp, &_fileId, sizeof(unsigned));
	lrp = lrp + sizeof(unsigned);
    }
    else 
    {
	if ( _encObj  )
	{
	    char c = 1;
	    memcpy(lrp, (char*)&c, 1);
	    lrp++;

	    memcpy(lrp, (char*)_objName, _objName.length());
	    lrp = lrp + _objName.length();
	    
	    memcpy( lrp, &_objType, sizeof(CegoObject::ObjectType));
	    lrp = lrp + sizeof(CegoObject::ObjectType);		    
	}
	else
	{
	    char c = 0;
	    memcpy(lrp, (char*)&c, 1);
	    lrp++;	    
	}
    }

    memcpy( lrp, &_dataLen, sizeof(unsigned));
    lrp = lrp + sizeof(unsigned);

    if ( _dataLen > 0 )
    {
	memcpy(lrp, _data, _dataLen);
    }
}

void CegoLogRecord::decode(void* p)
{
    char* lrp = (char*)p;

    memcpy( &_lsn, lrp, sizeof(unsigned long long));
    lrp = lrp + sizeof(unsigned long long);

    memcpy( &_tid, lrp, sizeof(unsigned long long));
    lrp = lrp + sizeof(unsigned long long);

    if ( _tid > 0 )
    {
	memcpy( &_tastep, lrp, sizeof(unsigned long long));
	lrp = lrp + sizeof(unsigned long long);
    }
    
    memcpy( &_ts, lrp, sizeof(unsigned long long));
    lrp = lrp + sizeof(unsigned long long);

    memcpy( &_logAction, lrp, sizeof(CegoLogRecord::LogAction));
    lrp = lrp + sizeof(CegoLogRecord::LogAction);
    
    if ( _logAction == CegoLogRecord::LOGREC_BUPAGE )
    {	
	memcpy( &_pageId, lrp, sizeof(PageIdType));
	lrp = lrp + sizeof(PageIdType);
    }
    else if ( _logAction == CegoLogRecord::LOGREC_BUFBM )
    {
	memcpy( &_fileId, lrp, sizeof(unsigned));
	lrp = lrp + sizeof(unsigned);
    }
    else
    {
	char c;
	memcpy(&c, lrp, 1);
	lrp++;
	
	if ( c > 0 )
	{	    
	    _objName = Chain(lrp);
	    lrp = lrp + _objName.length();
	    
	    memcpy( &_objType, lrp, sizeof(CegoObject::ObjectType));
	    lrp = lrp + sizeof(CegoObject::ObjectType);
	}
    }

    memcpy( &_dataLen, lrp, sizeof(unsigned));
    lrp = lrp + sizeof(unsigned);

    if ( _dataLen > 0 )
    {
	_data = (char*)malloc(_dataLen);
	memcpy(_data, lrp, _dataLen);
    }
    else
    {
	_data = 0;
    }
}

void CegoLogRecord::decodeLSN(void* p)
{
    char* lrp = (char*)p;
    memcpy(&_lsn, lrp, sizeof(unsigned long long));
}

void CegoLogRecord::decodeLogAction(void* p)
{
    char* lrp = (char*)p;
    lrp = lrp + 3 * sizeof(unsigned long long);
    memcpy( &_logAction, lrp, sizeof(CegoLogRecord::LogAction));
}

CegoLogRecord& CegoLogRecord::operator = ( const CegoLogRecord& l)
{
    _lsn = l._lsn;
    _tid = l._tid;
    _tastep = l._tastep;
    _ts = l._ts;
    _logAction = l._logAction;
    _objName = l._objName;
    _objType = l._objType;
    _data = l._data;
    _dataLen = l._dataLen;
    _pageId = l._pageId;
    
    return (*this);
}

ostream& operator << (ostream& s, const CegoLogRecord& logRec)
{
    s << logRec.toChain();
    return s;
}

Chain CegoLogRecord::toChain() const
{
    Chain s;
    
    s = Chain("[") + getObjName() + Chain(",") + Chain(_tid) + Chain(",") + Chain(_tastep) + Chain(",");
    
    switch (_logAction)
    {
    case (CegoLogRecord::LOGREC_CREATE):
	s += Chain("CREATE");
	break;
    case (CegoLogRecord::LOGREC_DROP):
	s += Chain("DROP");
	break;
    case (CegoLogRecord::LOGREC_TRUNCATE):
	s += Chain("TRUNCATE");
	break;
    case (CegoLogRecord::LOGREC_ALTER):
	s += Chain("ALTER");
	break;
    case (CegoLogRecord::LOGREC_INSERT):
	s += Chain("INSERT");
	break;
    case (CegoLogRecord::LOGREC_DELETE):
	s += Chain("DELETE");
	break;
    case (CegoLogRecord::LOGREC_UPDATE):
	s += Chain("UPDATE");
	break;
    case (CegoLogRecord::LOGREC_BEGIN):
	s += Chain("BEGIN");
	break;
    case (CegoLogRecord::LOGREC_COMMIT):
	s += Chain("COMMIT");
	break;
    case (CegoLogRecord::LOGREC_SYNC):
	s += Chain("SYNC");
	break;
    case (CegoLogRecord::LOGREC_BUPAGE):
	s += Chain("BUPAGE");
	break;
    case (CegoLogRecord::LOGREC_BUFBM):
	s += Chain("BUFBM");
	break;
    case (CegoLogRecord::LOGREC_BUFIN):
	s += Chain("BUFIN");
	break;
    case (CegoLogRecord::LOGREC_RENAME):
	s += Chain("RENAME");
	break;
    case (CegoLogRecord::LOGREC_ABORT):
	s += Chain("ABORT");
	break;
    case (CegoLogRecord::LOGREC_ADDCOUNTER):
	s += Chain("ADDCOUNTER");
	break;
    case (CegoLogRecord::LOGREC_DELCOUNTER):
	s += Chain("DELCOUNTER");
	break;
    }
    
    s += Chain(",") + Chain(_dataLen);
    s += Chain(", <data>") + Chain("]");
    return s;
}
