///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoAggregation.cc
// ------------------
// Cego aggregation structure class implementation                                    
//
// Design and Implementation by Bjoern Lemke               
//                                                         
// (C)opyright 2000-2025 Bjoern Lemke 
//
// IMPLEMENTATION MODULE
//
// Class: CegoAggregation
//
// Description: Query aggregation utility class
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

// CEGO INCLUDES
#include "CegoAggregation.h"
#include "CegoExpr.h"
#include "CegoXMLdef.h"
#include "CegoDatabaseFormater.h"

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

CegoAggregation::CegoAggregation(bool isDistinct)
{
    _type = COUNT;
    _pExpr = 0;
    _isDistinct = isDistinct;
}

CegoAggregation::CegoAggregation(char* buf)
{
    _pExpr = 0;
    decode(buf);
}

CegoAggregation::CegoAggregation(AggType type, CegoExpr* pExpr, bool isDistinct)
{
    _type = type;
    _pExpr = pExpr;
    _isDistinct = isDistinct;
}

CegoAggregation::~CegoAggregation()
{
    if ( _pExpr )
	delete _pExpr;
}

void CegoAggregation::cleanUp()
{
    if ( _pExpr )
	_pExpr->cleanUp();
}

void CegoAggregation::setQueryManager(CegoQueryManager* pTabMng)
{
    if ( _pExpr )
    {
	_pExpr->setQueryManager(pTabMng);
    }
}

void CegoAggregation::setTabSetId(unsigned tabSetId)
{
    if ( _pExpr )
    {
	_pExpr->setTabSetId(tabSetId);
    }
}

void CegoAggregation::setAggregationId(unsigned aid)
{
    _aid = aid;
}

const unsigned CegoAggregation::getAggregationId() const
{
    return _aid;
}

void CegoAggregation::clearAttrCache()
{
    if ( _pExpr )
	_pExpr->clearAttrCache();
}

CegoFieldValue& CegoAggregation::getFieldValue()
{
    return _fv;
}

void CegoAggregation::setFieldValue(const CegoFieldValue& fv)
{
    _fv = fv;
}

CegoAggregation& CegoAggregation::operator = ( const CegoAggregation& ag)
{
    _type = ag._type;
    _pExpr = ag._pExpr;
    _aid = ag._aid;
    return (*this);
}
   
const CegoAggregation::AggType& CegoAggregation::getType() const
{
    return _type;
}

CegoExpr* CegoAggregation::getExpr() const
{
    return _pExpr;
}

bool CegoAggregation::isDistinct() const
{
    return _isDistinct;
}

CegoAggregation* CegoAggregation::clone(bool isAttrRef)
{
    CegoAggregation *pAgg;
    if ( _pExpr )
	pAgg = new  CegoAggregation(_type, _pExpr->clone(isAttrRef), _isDistinct );
    else
	pAgg = new  CegoAggregation(_isDistinct);

    pAgg->setAggregationId ( _aid );
    return ( pAgg ) ; 
}

ListT<CegoAttrDesc*> CegoAggregation::getAttrRefList() const
{
    ListT<CegoAttrDesc*> attrList;

    if ( _pExpr )
    {
	attrList = _pExpr->getAttrRefList();
    }
    
    return attrList;
}

void CegoAggregation::encode(char *buf, CegoProcBlock* pBlock)
{
    char* pBuf = (char*)buf;
    
    memcpy( pBuf, &_type, sizeof(CegoAggregation::AggType));
    pBuf = pBuf + sizeof(CegoAggregation::AggType);

    char c = 0;
    if ( _pExpr )
    {
	c = 1;
    }
    memcpy( pBuf, &c, sizeof(char));
    pBuf = pBuf + sizeof(char);
    
    if ( _pExpr )
    {
	_pExpr->encode(pBuf, pBlock);
	pBuf = pBuf + _pExpr->getEncodingLength(pBlock);
    }
}

void CegoAggregation::decode(char *buf)
{   
    if ( _pExpr )
    {
	delete _pExpr;
	_pExpr = 0;
    }

    char* pBuf = (char*)buf;
    
    memcpy( &_type, pBuf,  sizeof(CegoAggregation::AggType));
    pBuf = pBuf + sizeof(CegoAggregation::AggType);
    
    char c = 0;
    memcpy( &c, pBuf, sizeof(char));
    pBuf = pBuf + sizeof(char);
    
    if ( c == 1 )
    {
	_pExpr = new CegoExpr(pBuf);
    }
}

unsigned CegoAggregation::getEncodingLength(CegoProcBlock* pBlock) const
{
    int size = sizeof(CegoAggregation::AggType);
    size += sizeof(char);
    if ( _pExpr )
	size += _pExpr->getEncodingLength(pBlock);
    return size;
}

Chain CegoAggregation::getId(CegoProcBlock *pBlock) const
{
    Chain s;
    switch (_type)
    {
    case CegoAggregation::MIN:
	s =  Chain("min(") + _pExpr->getId(pBlock) + Chain(")");
	break;
    case CegoAggregation::MAX:
	s =  Chain("max(") + _pExpr->getId(pBlock) + Chain(")");
	break;
    case CegoAggregation::AVG:
	s =  Chain("avg(") + _pExpr->getId(pBlock) + Chain(")");
	break;
    case CegoAggregation::SUM:
	s =  Chain("sum(") + _pExpr->getId(pBlock) + Chain(")");
	break;
    case CegoAggregation::COUNT:
    {       
	Chain distOpt;
	if ( _isDistinct )
	    distOpt = Chain("d");	    
	
	if ( _pExpr )
	{ 
	    s = distOpt + Chain("count(") + _pExpr->getId(pBlock) + Chain(")");
	}
	else
	    s = distOpt + Chain("count(*)");
    }
    }
    return s;
}

Chain CegoAggregation::toChain(int defTabSetId) const
{
    Chain s;
    switch (_type)
    {
    case CegoAggregation::MIN:
	s =  Chain("min(") + _pExpr->toChain(defTabSetId) + Chain(")");
	break;
    case CegoAggregation::MAX:
	s =  Chain("max(") + _pExpr->toChain(defTabSetId) + Chain(")");
	break;
    case CegoAggregation::AVG:
	s =  Chain("avg(") + _pExpr->toChain(defTabSetId) + Chain(")");
	break;
    case CegoAggregation::SUM:
	s =  Chain("sum(") + _pExpr->toChain(defTabSetId) + Chain(")");
	break;
    case CegoAggregation::COUNT:
    {       
	Chain distOpt;
	if ( _isDistinct )
	    distOpt = Chain(" distinct ");	    
	
	if ( _pExpr )
	{ 
	    s = distOpt + Chain("count(") + _pExpr->toChain(defTabSetId) + Chain(")");
	}
	else
	    s = distOpt + Chain("count(*)");
    }
    }
    return s;
}

Chain CegoAggregation::dbFormat(CegoDatabaseFormater *pForm) const
{
    return pForm->formatAggregation(_type, _pExpr, _isDistinct);
}

ostream& operator << (ostream& s, const CegoAggregation& ag)
{
    s << ag.toChain(0);
    return s;
}
