///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoKeyObject.cc 
// ----------------
// Cego key object entry implementation
//     
// Design and Implementation by Bjoern Lemke               
//     
// (C)opyright 2000-2025 Bjoern Lemke
//
// IMPLEMENTATION MODULE
//
// Class: CegoKeyObject
//
// Description: Derived class from CegoObject to use as a container class for foreign key objects
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

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

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

CegoKeyObject::CegoKeyObject()
{
}

CegoKeyObject::CegoKeyObject(const CegoKeyObject& ko)  : CegoDecodableObject(ko)
{
    _refTable = ko._refTable;
    _keySchema = ko._keySchema;
    _refSchema = ko._refSchema;
    _tabName = ko._tabName;
}

CegoKeyObject::CegoKeyObject(ObjectType type, const Chain& objName, unsigned tabSetId) : CegoDecodableObject(type, objName, tabSetId)
{
}

CegoKeyObject::CegoKeyObject(unsigned tabSetId, const Chain& fkey, const Chain& tabName, const ListT<CegoField>& keySchema, const Chain& refTable, const ListT<CegoField>& refSchema) : CegoDecodableObject(CegoObject::FKEY, fkey, tabSetId)
{
    _keySchema = keySchema;
    _refTable = refTable;
    _refSchema = refSchema;
    _tabName = tabName;
}

CegoKeyObject::~CegoKeyObject()
{   
}

void CegoKeyObject::setTabName(const Chain& tabName)
{
    _tabName = tabName;
}

const Chain& CegoKeyObject::getTabName() const
{
    return _tabName;
}

void CegoKeyObject::setKeySchema(const ListT<CegoField>& keySchema)
{
    _keySchema = keySchema;
}

const ListT<CegoField>& CegoKeyObject::getKeySchema() const
{
    return _keySchema;
}

void CegoKeyObject::setRefTable(const Chain& refTable)
{
    _refTable = refTable;
}

const Chain& CegoKeyObject::getRefTable() const
{
    return _refTable;
}

void CegoKeyObject::setRefSchema(const ListT<CegoField>& refSchema)
{
    _refSchema = refSchema;
}

const ListT<CegoField>& CegoKeyObject::getRefSchema() const
{
    return _refSchema;
}

unsigned CegoKeyObject::getEntrySize() const
{
    unsigned entrySize = CegoObject::getBaseSize();

    entrySize += 1; // object tabname size
    entrySize += _tabName.length();

    entrySize += 1; // size of keyList
    CegoField* pK = _keySchema.First();
    while (pK)
    {
	// key information
	entrySize += pK->getAttrName().length();
	pK = _keySchema.Next();
    }
    entrySize += _refTable.length();

    entrySize += 1; // size of refList
    CegoField* pR = _refSchema.First();
    while (pR)
    {
	// key information
	entrySize += pR->getAttrName().length();
	pR = _refSchema.Next();
    }

    return entrySize;
}

void CegoKeyObject::encode(char *buf) const
{
    char* bufPtr = buf;

    unsigned entrySize = getEntrySize();

    CegoObject::encodeBase(bufPtr, entrySize);
    bufPtr += CegoObject::getBaseSize();

    char c;

    c = (char)_tabName.length();
    memcpy (bufPtr, &c , 1);
    bufPtr++;

    memcpy(bufPtr, (char*)_tabName, _tabName.length());    
    bufPtr=bufPtr + _tabName.length();

    char *keyLenPtr = bufPtr;

    // memcpy (bufPtr, &c , 1);
    bufPtr++;
	
    char keyLen = 0;
    CegoField* pK = _keySchema.First();
    while (pK)
    {
	memcpy(bufPtr, (char*)pK->getAttrName(), pK->getAttrName().length());    
	bufPtr=bufPtr + pK->getAttrName().length();
	keyLen += pK->getAttrName().length();
	pK = _keySchema.Next();
    }
    
    memcpy(bufPtr, (char*)_refTable, _refTable.length());    
    bufPtr=bufPtr + _refTable. length();
    
    char* refLenPtr = bufPtr;
    // memcpy (bufPtr, &c , 1);
    bufPtr++;

    char refLen = 0;
    CegoField* pR = _refSchema.First();
    while (pR)
    {
	// key information
	memcpy(bufPtr, (char*)pR->getAttrName(), pR->getAttrName().length());    
	bufPtr=bufPtr + pR->getAttrName().length();
	refLen += pR->getAttrName().length();
	pR = _refSchema.Next();
    }
    
    memcpy (keyLenPtr, &keyLen , 1);
    memcpy (refLenPtr, &refLen , 1);    
}

void CegoKeyObject::decode(char *buf)
{
    char* bufPtr = buf;

    unsigned size;

    CegoObject::decodeBase(bufPtr, size);
    bufPtr += CegoObject::getBaseSize();

    bufPtr++;
    _tabName =  Chain(bufPtr);    
    bufPtr=bufPtr + _tabName.length();
    
    char c;
    memcpy (&c, bufPtr , 1);
    bufPtr++;
    
    unsigned i=0;
    while ( i < c )
    {
	Chain attrName = Chain(bufPtr);
	_keySchema.Insert(CegoField(Chain(), attrName));
	
	bufPtr=bufPtr + attrName.length();
	i=i+attrName.length();
    }
    
    _refTable = Chain(bufPtr);
    bufPtr=bufPtr + _refTable.length();
    
    memcpy (&c, bufPtr , 1);
    bufPtr++;
    
    i=0;
    while ( i < c )
    {
	Chain attrName = Chain(bufPtr);
	_refSchema.Insert(CegoField(Chain(), attrName));
	
	bufPtr=bufPtr + attrName.length();
	i=i+attrName.length();
    }
}

void CegoKeyObject::setEmpty()
{
    _keySchema.Empty();
    _refSchema.Empty();
}

CegoKeyObject& CegoKeyObject::operator = ( const CegoKeyObject& ko)
{
    CegoObject::operator=(ko);

    _refTable = ko._refTable;
    _keySchema = ko._keySchema;
    _refSchema = ko._refSchema;
    _tabName = ko._tabName;

    return (*this);
}

bool CegoKeyObject::operator == ( const CegoKeyObject& oe)
{
    return CegoObject::operator==(oe);
}

Chain CegoKeyObject::getInfo() const
{
    Chain s;

    s += Chain("TabName: ") + _tabName + Chain("\n");
    s += Chain("Key: ");
    CegoField *pK = _keySchema.First();
    while ( pK ) 
    {
	s += pK->getAttrName();
	pK = _keySchema.Next();
	if ( pK )
	    s += Chain(",");
    }
    s += Chain("\n");
    s += Chain("RefTable: ") + _refTable + Chain("\n");
    s += Chain("Ref: ");
    CegoField *pR = _refSchema.First();
    while ( pR ) 
    {
	s += pR->getAttrName();
	pR = _refSchema.Next();
	if ( pR )
	    s += Chain(",");
    }
    s += Chain("\n");
    
    return s;
}

