///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoCondition.cc
// ----------------
// Cego condition description
//
// Design and Implementation by Bjoern Lemke
//     
// (C)opyright 2000-2025 Bjoern Lemke
//
// IMPLEMENTATION MODULE
//
// Class: CegoCondDesc
// 
// Description: Condition container class used for queries and stores procedures
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

// CEGO INCLUDES
#include "CegoCondition.h"
#include "CegoXMLdef.h"
#include "CegoQueryHelper.h"
#include "CegoDatabaseFormater.h"

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

CegoCondition::CegoCondition(char *buf)
{
    _pLeft=0;
    _pRight=0;
    decode(buf);
}

CegoCondition::CegoCondition(CegoCondition::CondType ct)
{
    _condType=ct;
    _pLeft=0;
    _pRight=0;
}

CegoCondition::CegoCondition(CegoCondition::CondType ct, CegoPredicate* pLeft, CegoPredicate* pRight)
{
    _condType=ct;
    _pLeft=pLeft;
    _pRight=pRight;
}

CegoCondition::~CegoCondition()
{
    if (_pLeft)
    {
	delete _pLeft;
    }
    if (_pRight)
    {
	delete _pRight;
    }
}

void CegoCondition::setQueryManager(CegoQueryManager* pTabMng)
{
    if (_pLeft)
    {
	_pLeft->setQueryManager(pTabMng);
    }
    if (_pRight)
    {
	_pRight->setQueryManager(pTabMng);
    }
}

void CegoCondition::setTabSetId(unsigned tabSetId)
{
    if (_pLeft)
    {
	_pLeft->setTabSetId(tabSetId);
    }
    if (_pRight)
    {
	_pRight->setTabSetId(tabSetId);
    }
}

void CegoCondition::getPlanList(ListT<Element*>& planList)
{
    if (_pLeft)
    {
	_pLeft->getPlanList(planList);
    }
    if (_pRight)
    {
	_pRight->getPlanList(planList);
    }
}

void CegoCondition::cleanUp()
{
    if (_pLeft)
    {
	_pLeft->cleanUp();
    }
    if (_pRight)
    {
	_pRight->cleanUp();
    }
}

CegoPredicate* CegoCondition::Left()
{
    return _pLeft;
}

CegoPredicate* CegoCondition::Right()
{
    return _pRight;
}

void CegoCondition::setLeft(CegoPredicate* pP)
{
    _pLeft = pP;
}

void CegoCondition::setRight(CegoPredicate* pP)
{
    _pRight = pP;
}

void CegoCondition::setCondType(CegoCondition::CondType ct)
{
    _condType = ct;
}

CegoCondition::CondType CegoCondition::getCondType()
{
    return _condType;
}

void CegoCondition::encode(char *buf, CegoProcBlock* pBlock)
{
    char* pP = (char*)buf;

    memcpy( pP, &_condType, sizeof(CegoCondition::CondType));
    pP = pP + sizeof(CegoCondition::CondType);

    switch (_condType )
    {
    case CegoCondition::AND:
    case CegoCondition::OR:
    {
	_pLeft->encode(pP, pBlock);
	pP = pP + _pLeft->getEncodingLength(pBlock);
	_pRight->encode(pP, pBlock);
	pP = pP + _pRight->getEncodingLength(pBlock);
	break;
    }
    case CegoCondition::PRED:
    {
	_pLeft->encode(pP, pBlock);
	pP = pP + _pLeft->getEncodingLength(pBlock);	
	break;
    }
    }
}

void CegoCondition::decode(char *buf)
{
    if ( _pLeft ) 
	delete _pLeft;
    if ( _pRight ) 
	delete _pRight;
    
    char* pP = (char*)buf;

    memcpy( &_condType, pP, sizeof(CegoCondition::CondType));
    pP = pP + sizeof(CegoCondition::CondType);
    
    switch (_condType )
    {
    case CegoCondition::AND:
    case CegoCondition::OR:
    {
	_pLeft = new CegoPredicate(pP);
	pP = pP + _pLeft->getEncodingLength();
	_pRight = new CegoPredicate(pP);
	pP = pP + _pRight->getEncodingLength();
	break;
    }
    case CegoCondition::PRED:
    {
	_pLeft = new CegoPredicate(pP);
	pP = pP + _pLeft->getEncodingLength();
	break;
    }
    }
}

unsigned CegoCondition::getEncodingLength(CegoProcBlock* pBlock) const
{
    unsigned len = 0;

    len += sizeof(CegoCondition::CondType);
    
    switch (_condType )
    {
    case CegoCondition::AND:
    case CegoCondition::OR:
    {
	len += _pLeft->getEncodingLength(pBlock);
	len += _pRight->getEncodingLength(pBlock);
	break;
    }
    case CegoCondition::PRED:
    {
	len += _pLeft->getEncodingLength(pBlock);
	break;
    }
    }
    return len;
}

void CegoCondition::clearAttrCache()
{    
    switch (_condType )
    {
    case CegoCondition::AND:
    case CegoCondition::OR:
    {
	_pLeft->clearAttrCache();
	_pRight->clearAttrCache();
	break;
    }
    case CegoCondition::PRED:
    {
	_pLeft->clearAttrCache();
	break;
    }
    }
}

ListT<CegoAttrDesc*> CegoCondition::getAttrRefList() const
{
    ListT<CegoAttrDesc*> al;

    switch( _condType )
    {
    case CegoCondition::AND:
    case CegoCondition::OR:
    {
	al = _pLeft->getAttrRefList();
	al += _pRight->getAttrRefList();
	break;
    }
    case CegoCondition::PRED:
    {
	al += _pLeft->getAttrRefList();
	break;
    }
    }

    return al;
}

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

    switch( _condType )
    {
    case CegoCondition::AND:
    case CegoCondition::OR:
    {
	refCount += _pLeft->evalReferences(pCO, fl);
	refCount += _pRight->evalReferences(pCO, fl);
	break;
    }
    case CegoCondition::PRED:
    {
	refCount += _pLeft->evalReferences(pCO, fl);
	break;
    }
    }

    return refCount;
}

ListT<CegoAggregation*> CegoCondition::getAggregationList()
{
    ListT<CegoAggregation*> aggList;	

    if (_pLeft)
    {
	aggList = aggList + _pLeft->getAggregationList();
    }
    if (_pRight)
    {
	aggList = aggList + _pRight->getAggregationList();
    }

    return aggList;
}

void CegoCondition::getFieldList(ListT<CegoField>& fl, ListT<CegoField>** pFLA) const
{    
    switch( _condType )
    {
    case CegoCondition::AND:
    case CegoCondition::OR:
    {
	_pLeft->getFieldList(fl, pFLA);
	_pRight->getFieldList(fl, pFLA);
	break;
    }
    case CegoCondition::PRED:
    {
	_pLeft->getFieldList(fl, pFLA);
	break;
    }
    }
}

CegoField CegoCondition::evalField(const ListT<CegoField>& fl, bool graceful) const
{

    CegoField f; 
    switch( _condType )
    {
    case CegoCondition::AND:
    {
	f = CegoField( Chain("AND"), Chain("AND"), Chain("AND"), BOOL_TYPE, sizeof(char));
	break;
    }
    case CegoCondition::OR:
    {
	f = CegoField( Chain("OR"), Chain("OR"), Chain("OR"), BOOL_TYPE, sizeof(char));
	break;
    }
    case CegoCondition::PRED:
    {
	f = _pLeft->evalField(fl, graceful);
	break;
    }
    }
    return f;
}

CegoFieldValue CegoCondition::evalFieldValue(ListT<CegoField>** pFLA, CegoProcBlock *pBlock) const
{
    bool isTrue=false;
    switch( _condType )
    {
    case CegoCondition::AND:
    {
	isTrue = ( _pLeft->eval(0, 0, pFLA, 0, pBlock)
		 && _pRight->eval(0, 0, pFLA, 0, pBlock));
	break;
    }
    case CegoCondition::OR:
    {
	isTrue = ( _pLeft->eval(0, 0, pFLA, 0, pBlock)
		 || _pRight->eval(0, 0, pFLA, 0, pBlock));
	break;
    }
    case CegoCondition::PRED:
    {
	isTrue = _pLeft->eval(0, 0, pFLA, 0, pBlock);

	if ( _pLeft->getMode() == CegoPredicate::EXPRONLY )
	{
	    return _pLeft->getExprOnlyValue();
	}	
	break;
    }
    }

    if ( isTrue )
	return CegoFieldValue(BOOL_TYPE, Chain("true"));
    return CegoFieldValue(BOOL_TYPE, Chain("false"));
}

void CegoCondition::getSelectQueryList(ListT<CegoSelect*>& queryList)
{
    if (_pLeft)
    {
	_pLeft->getSelectQueryList(queryList);
    }
    if (_pRight)
    {
	_pRight->getSelectQueryList(queryList);
    }
}	

void CegoCondition::setAggregationValue(ListT<CegoField>& jfl)
{
    if (_pLeft)
    {
	_pLeft->setAggregationValue(jfl);
    }
    if (_pRight)
    {
	_pRight->setAggregationValue(jfl);
    }
}

CegoCondition* CegoCondition::clone(bool isAttrRef)
{
    CegoCondition* pCD = new CegoCondition(_condType);
    
    if ( _pLeft )
	pCD->setLeft(_pLeft->clone(isAttrRef));
    else
	pCD->setLeft(0);

    if ( _pRight )
	pCD->setRight(_pRight->clone(isAttrRef));
    else
	pCD->setRight(0);
    
    return pCD;
}

Chain CegoCondition::getId(CegoProcBlock *pBlock) const
{
    Chain s;
    s = Chain("c:");

    switch( _condType )
    {
    case CegoCondition::AND:
    {
	s += _pLeft->getId(pBlock) + Chain("&") + _pRight->getId(pBlock);
	break;
    }
    case CegoCondition::OR:
    {
	s += _pLeft->getId(pBlock) + Chain("|") + _pRight->getId(pBlock);
	break;
    }
    case CegoCondition::PRED:
    {
	s += _pLeft->getId(pBlock);
	break;
    }
    }
    return s;
}


Chain CegoCondition::dbFormat(CegoDatabaseFormater *pForm)
{
    return pForm->formatCondition(_condType, _pLeft, _pRight);
}


Chain CegoCondition::toChain(unsigned defTabSetId, const Chain& indent) const
{
    Chain s;

    switch( _condType )
    {
    case CegoCondition::AND:
    {
	s = _pLeft->toChain(defTabSetId, indent) + Chain(" and ") + _pRight->toChain(defTabSetId, indent);
	break;
    }
    case CegoCondition::OR:
    {
	s = _pLeft->toChain(defTabSetId, indent) + Chain(" or ") + _pRight->toChain(defTabSetId, indent);
	break;
    }
    case CegoCondition::PRED:
    {
	s = _pLeft->toChain(defTabSetId, indent);
	break;
    }
    }
    return s;
}

CegoCondition* CegoCondition::map(const Chain& viewAlias, const ListT<CegoExpr*>& exprList) const
{

    bool doMap = true;

    CegoPredicate* pMapLeft = 0;
    CegoPredicate* pMapRight = 0;
    
    if ( _pLeft )
    {
	pMapLeft = _pLeft->map(viewAlias, exprList);
	if ( pMapLeft == 0 )
	    doMap=false;
    }
    
    if ( _pRight )
    {
	pMapRight = _pRight->map(viewAlias, exprList);
	if ( pMapRight == 0 )
	    doMap=false;
    }

    if ( doMap == false )
    {
	if ( pMapLeft )
	    delete pMapLeft;
	if ( pMapRight )
	    delete pMapRight;
    }    
    return new CegoCondition(_condType, pMapLeft, pMapRight);
    
}

bool CegoCondition::isCursorPred() const
{
    bool isPred = false;
    
    switch( _condType )
    {
    case CegoCondition::AND:
    {
	isPred = _pLeft->isCursorPred() &&  _pRight->isCursorPred();
	break;
    }
    case CegoCondition::OR:
    {
	isPred = false;
	break;
    }
    case CegoCondition::PRED:
    {
        isPred = _pLeft->isCursorPred();
	break;
    }
    }
    return isPred;
}
