///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoAttrDesc.cc
// ---------------
// Cego database table attribute description
//      
// Design and Implementation by Bjoern Lemke
//     
// (C)opyright 2000-2025 Bjoern Lemke
//
// IMPLEMENTATION MODULE
//
// Class: CegoAttrDesc
// 
// Description: Table attribute container class
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

// CEGO INCLUDES
#include "CegoAttrDesc.h"
#include "CegoXMLdef.h"
#include "CegoDatabaseFormater.h"

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

CegoAttrDesc::CegoAttrDesc()
{
    _isValid = false;
}

CegoAttrDesc::CegoAttrDesc(const Chain& attrName)
{
    _attrName = attrName;
    _isValid = false;
}

CegoAttrDesc::CegoAttrDesc(char *buf)
{
    decode(buf);
    _isValid = false;
}

CegoAttrDesc::CegoAttrDesc(const Chain& tableName, const Chain& attrName, bool isValid)
{
    _tableName = tableName;
    _attrName = attrName;
    _isValid = isValid;
}
 
CegoAttrDesc::~CegoAttrDesc()
{
}

void CegoAttrDesc::setAttrName(const Chain& attrName)
{
    _attrName = attrName;
}

const Chain& CegoAttrDesc::getAttrName() const
{
    return _attrName;
}

void CegoAttrDesc::setTableName(const Chain& tableName)
{
    _tableName = tableName;
}

const Chain& CegoAttrDesc::getTableName() const
{
    return _tableName;
}

void CegoAttrDesc::setValid(bool isValid)
{
    _isValid = isValid;
}

bool CegoAttrDesc::isValid() const
{
    return _isValid;
}

CegoAttrDesc* CegoAttrDesc::clone() const
{
    return ( new CegoAttrDesc(_tableName, _attrName, _isValid) );
}

CegoAttrDesc& CegoAttrDesc::operator = ( const CegoAttrDesc& ad )
{
    _tableName = ad._tableName;
    _attrName = ad._attrName;
    _isValid = ad._isValid;
    return (*this);
}

bool CegoAttrDesc::operator == ( const CegoAttrDesc& ad) const
{    
    if (_tableName == ad._tableName && _attrName == ad._attrName)
	return true;
    return false;
}

bool CegoAttrDesc::operator != ( const CegoAttrDesc& ad) const
{    
    if (_tableName == ad._tableName && _attrName == ad._attrName)
	return false;
    return true;
}

Chain CegoAttrDesc::getId() const
{
    Chain s;
    if ( _tableName.length() == 0 )
	s = _attrName;
    else
	s = _tableName + "." + _attrName;
    return s;
}

Chain CegoAttrDesc::toChain() const
{
    Chain s;
    if ( _tableName.length() == 0 )
	s = _attrName;
    else
	s = _tableName + "." + _attrName;
    return s;
}

Chain CegoAttrDesc::dbFormat(CegoDatabaseFormater* pForm) const
{
    return pForm->formatAttr(_tableName, _attrName);
}

void CegoAttrDesc::encode(char *buf)
{   
    char* pE = (char*)buf;

    char len = _tableName.length();

    if ( len == 0 )
    {	
	memcpy( pE, &len, sizeof(char));
	pE = pE + sizeof(char);

	len = _attrName.length();

	memcpy( pE, &len, sizeof(char));
	pE = pE + sizeof(char);

	memcpy( pE, (char*)_attrName, len);
	pE = pE + len;
    }
    else
    {
	memcpy( pE, &len, sizeof(char));
	pE = pE + sizeof(char);

	memcpy( pE, (char*)_tableName, len);
	pE = pE + len;

	len = _attrName.length();

	memcpy( pE, &len, sizeof(char));
	pE = pE + sizeof(char);
	
	memcpy( pE, (char*)_attrName, len);
	pE = pE + len;
    }
}

void CegoAttrDesc::decode(char *buf)
{
    char* pE = (char*)buf;
    char len;
    
    memcpy( &len, pE, sizeof(char));
    pE = pE + sizeof(char);

    if ( len == 0 )
    {
	_tableName = Chain();
	memcpy( &len, pE, sizeof(char));
	pE = pE + sizeof(char);
	_attrName = Chain(pE, len-1);
    }
    else
    {
	_tableName = Chain(pE, len-1);
	pE = pE + len;
	memcpy( &len, pE, sizeof(char));
	pE = pE + sizeof(char);
	_attrName = Chain(pE, len-1);
	pE = pE + len;
    }
}

unsigned CegoAttrDesc::getEncodingLength() const
{
    unsigned len = 0;
    
    len += sizeof(char);
    len += _tableName.length();
    
    len += sizeof(char);
    len += _attrName.length();

    return len;
}

unsigned CegoAttrDesc::evalReferences(CegoContentObject *pCO, const ListT<CegoField>& fl)
{
    unsigned refCount = 0;

    if ( pCO->getType() == CegoObject::JOIN )
    {
	CegoContentObject** pSubCO = pCO->getSubCOList().First();
	while ( pSubCO )
	{
	    refCount += evalReferences(*pSubCO, fl);
	    pSubCO = pCO->getSubCOList().Next();
	}
    }
    else if ( pCO->getType() == CegoObject::VIEW || pCO->getType() == CegoObject::TABLE ||  pCO->getType() == CegoObject::ALIAS || pCO->getType() == CegoObject::SYSTEM )
    {
	refCount += evalTableReferences(pCO, fl);
    }
    
    return refCount;
}

unsigned CegoAttrDesc::evalTableReferences(CegoContentObject *pCO, const ListT<CegoField>& fl)
{    
    unsigned refCount = 0;
 
    // if no table referance has been set up, we search for appropriate in field list
    if ( _tableName == Chain() )
    {
	CegoField* pF = fl.First();
	while (pF)
	{
	    if (_attrName == (Chain)pF->getAttrName())
	    {
		_tableName = pF->getTableAlias();
		refCount++;
	    }	
	    pF = fl.Next();	    
	}
    }
   else
   {
       // for alias objects, tablename is not visible for referencing attribute
       // so just in case of non alias objects, we replace tablename with alias name
      
       if ( ( pCO->getType() != CegoObject::ALIAS && _tableName == (Chain)pCO->getTabName() )
	    ||  _tableName == (Chain)pCO->getTabAlias() )
       {
	   // we set tableName in any case
	   _tableName = pCO->getTabAlias();
	   // needed to increase refcount
	   refCount++;
       }
   }
   
    return refCount;
}

ostream& operator << (ostream& s, const CegoAttrDesc& a)
{
    s <<  a._tableName << "." << a._attrName;
    return s;
}
