///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoLogRecord.cc
// ----------------
// Cego Log Record class 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: CegoLogRecord
// 
// Description: 
//
// Status: QG-2.6
//
///////////////////////////////////////////////////////////////////////////////

// cego includes
#include "CegoLogRecord.h"

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

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

CegoLogRecord::~CegoLogRecord()
{
}

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

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

int CegoLogRecord::getTID() const
{
    return _tid;
}

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

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

void CegoLogRecord::setTS(int 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;
}

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

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

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

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

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

void CegoLogRecord::setPageId(int pageId)
{
    _pageId = pageId;
}
 
int CegoLogRecord::getEncodingLength() const
{
    int len = sizeof(long) + 2 * sizeof(int) + sizeof(CegoLogRecord::LogAction);

    if ( _logAction == CegoLogRecord::LOGREC_BUPAGE )
	len += 2 * sizeof(int) ;
    else if ( _logAction == CegoLogRecord::LOGREC_BUFBM )
	len += sizeof(int);
    else
    {
	len++; // obj flag
	if ( _encObj )
	    len += _objName.length() + sizeof(CegoObject::ObjectType);
    }

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

    return len;
}

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

    memcpy( lrp, &_tid, sizeof(int));
    lrp = lrp + sizeof(int);

    memcpy( lrp, &_ts, sizeof(int));
    lrp = lrp + sizeof(int);

    memcpy( lrp, &_logAction, sizeof(CegoLogRecord::LogAction));
    lrp = lrp + sizeof(CegoLogRecord::LogAction);
    
    if ( _logAction == CegoLogRecord::LOGREC_BUPAGE )
    {
	memcpy( lrp, &_fileId, sizeof(int));
	lrp = lrp + sizeof(int);
	memcpy( lrp, &_pageId, sizeof(int));
	lrp = lrp + sizeof(int);
	// memcpy(lrp, _data, _dataLen);
    }
    else if ( _logAction == CegoLogRecord::LOGREC_BUFBM )
    {
	memcpy( lrp, &_fileId, sizeof(int));
	lrp = lrp + sizeof(int);

	// memcpy(lrp, _data, _dataLen);
    }
    else 
    {

	if ( _encObj  )
	{
	    char c = 1;
	    memcpy(lrp, (char*)&c, 1);
	    lrp = 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 = lrp ++;	    
	}
    }

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

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

void CegoLogRecord::decode(void* p)
{

    char* lrp = (char*)p;

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

    memcpy( &_tid, lrp, sizeof(int));
    lrp = lrp + sizeof(int);

    memcpy( &_ts, lrp, sizeof(int));
    lrp = lrp + sizeof(int);

    memcpy( &_logAction, lrp, sizeof(CegoLogRecord::LogAction));
    lrp = lrp + sizeof(CegoLogRecord::LogAction);
    
    if ( _logAction == CegoLogRecord::LOGREC_BUPAGE )
    {

	memcpy( &_fileId, lrp, sizeof(int));
	lrp = lrp + sizeof(int);
	
	memcpy( &_pageId, lrp, sizeof(int));
	lrp = lrp + sizeof(int);

	// _data = (char*)malloc(_dataLen);
	// memcpy(_data, lrp, _dataLen);
	
    }
    else if ( _logAction == CegoLogRecord::LOGREC_BUFBM )
    {

	memcpy( &_fileId, lrp, sizeof(int));
	lrp = lrp + sizeof(int);
	
	// _data = (char*)malloc(_dataLen);
	// memcpy(_data, lrp, _dataLen);
	
    }
    else
    {

	char c;
	memcpy(&c, lrp, 1);
	lrp = 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(int));
    lrp = lrp + sizeof(int);

    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(long));
}

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

CegoLogRecord& CegoLogRecord::operator = ( const CegoLogRecord& l)
{
    _lsn = l._lsn;
    _tid = l._tid;
    _ts = l._ts;
    _logAction = l._logAction;
    _objName = l._objName;
    _objType = l._objType;
    _data = l._data;
    _dataLen = l._dataLen;
    _fileId = l._fileId;
    _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(",");
							      							      
    switch (_logAction)
    {
    case (CegoLogRecord::LOGREC_CREATE):
	s += Chain("CREATE");
	break;
    case (CegoLogRecord::LOGREC_DROP):
	s += Chain("DROP");
	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;
    case (CegoLogRecord::LOGREC_DELETE_COMMIT):
	s += Chain("DELETE_COMMIT");
	break;
    case (CegoLogRecord::LOGREC_UPDATE_COMMIT):
	s += Chain("UPDATE_COMMIT");
	break;

    }
    
    s += Chain(",") + Chain(_dataLen);
    s += Chain(", <data>") + Chain("]");
    return s;
}
