///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoPredDesc.cc
// ---------------
// Cego predicate structure class definition
//                                                 
// 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: CegoPredDesc
// 
// Description: 
//
// Status: QG-2.6
//
///////////////////////////////////////////////////////////////////////////////

// cego includes
#include "CegoPredDesc.h"
#include "CegoCondDesc.h"
#include "CegoSelect.h"
#include "CegoXMLdef.h"

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

CegoPredDesc::CegoPredDesc(char* buf, CegoDistManager *pGTM)
{
    _pExpr1 = 0;
    _pExpr2 = 0;
    _pExpr3 = 0;
    _pC = 0;
    _pNotPred = 0;
    _isChecked = false;
    _pSelect = 0;
    decode(buf, pGTM);
}

CegoPredDesc::CegoPredDesc(Element* pPredElement, CegoDistManager *pGTM)
{
    _pExpr1 = 0;
    _pExpr2 = 0;
    _pExpr3 = 0;
    _pC = 0;
    _pNotPred = 0;
    _isChecked = false;
    _pSelect = 0;

    fromElement(pPredElement, pGTM);
}

CegoPredDesc::CegoPredDesc(CegoExpr *pExpr1, CegoExpr* pExpr2, const CegoComparison& comp)
{
    _pExpr1 = pExpr1;
    _pExpr2 = pExpr2;
    _pExpr3 = 0;
    _comp = comp;
    _pC = 0;
    _pNotPred = 0;
    _mode = CegoPredDesc::EXPRCOMP;
    _isChecked = false;
    _pSelect = 0;
}

CegoPredDesc::CegoPredDesc(CegoExpr *pExpr1, CegoExpr* pExpr2, CegoExpr* pExpr3 )
{
    _pExpr1 = pExpr1;
    _pExpr2 = pExpr2;
    _pExpr3 = pExpr3;
    _pC = 0;
    _pNotPred = 0;
    _mode = CegoPredDesc::BETWEEN;
    _isChecked = false;
    _pSelect = 0;
}

CegoPredDesc::CegoPredDesc(CegoExpr *pExpr, const Chain& pattern, bool isNegated)
{

    _pExpr1 = pExpr;
    _pExpr2 = 0;
    _pExpr3 = 0;
    _pattern = pattern;
    Chain sqlPattern = Chain("^") + pattern + Chain("$");
    sqlPattern.replaceAll(Chain("%"), Chain(".*"), sqlPattern);
    sqlPattern.replaceAll(Chain("_"), Chain("."), sqlPattern);

    _pMatcher = new Matcher(sqlPattern);
    _pMatcher->prepare();
    
    if ( isNegated )
	_mode = CegoPredDesc::ISNOTLIKE;
    else
	_mode = CegoPredDesc::ISLIKE;

    _isChecked = false;
    _pSelect = 0;
    _pC = 0;
    _pNotPred = 0;
}

CegoPredDesc::CegoPredDesc(const CegoPredDesc& p)
{
    *this = p;
}

CegoPredDesc::CegoPredDesc(CegoCondDesc *pC)
{
    _pExpr1 = 0;
    _pExpr2 = 0;
    _pExpr3 = 0;    
    _pC = pC;
    _pNotPred = 0;
    _isChecked = false;
    _pSelect = 0;
    _mode = CegoPredDesc::CONDITION;
}

CegoPredDesc::CegoPredDesc(CegoPredDesc *pNotPred)
{
    _pExpr1 = 0;
    _pExpr2 = 0;
    _pExpr3 = 0;    
    _pC = 0;
    _isChecked = false;
    _pSelect = 0;
    _pNotPred = pNotPred;
    _mode = CegoPredDesc::NOTPRED;
}

CegoPredDesc::CegoPredDesc(CegoSelect *pSelect)
{
    _pExpr1 = 0;
    _pExpr2 = 0;
    _pExpr3 = 0;
    _pSelect = pSelect;
    _pC = 0;
    _pNotPred = 0;
    _mode = CegoPredDesc::EXISTSCOMP;
    _isChecked = false;
}

CegoPredDesc::CegoPredDesc(CegoExpr *pExpr, CegoSelect* pSelect, bool isNegated)
{
    _pExpr1 = pExpr;
    _pExpr2 = 0;
    _pExpr3 = 0;
    _pSelect = pSelect;
    _pC = 0;
    _pNotPred = 0;
    if ( isNegated )
	_mode = CegoPredDesc::INSUB;
    else
	_mode = CegoPredDesc::NOTINSUB;
    _isChecked = false;
}

CegoPredDesc::CegoPredDesc(CegoExpr* pExpr, bool isNull)
{
    _pExpr1 = pExpr;
    _pExpr2 = 0;
    _pExpr3 = 0;
    _pSelect = 0;
    _pC = 0;
    _pNotPred = 0;
    if  ( isNull )
	_mode = CegoPredDesc::NULLCOMP;
    else
    	_mode = CegoPredDesc::NOTNULLCOMP;
    _isChecked = false;
}

CegoPredDesc::~CegoPredDesc()
{

    if ( _pExpr1 )
    {
	delete _pExpr1;
    }
    if ( _pExpr2 )
    {
	delete _pExpr2;
    }
    if ( _pExpr3 )
    {
	delete _pExpr3;
    }
    if (_pC)
    {	
	delete _pC;
    }
    if (_pNotPred)
    {	
	delete _pNotPred;
    }
    if (_pSelect)
    {
	delete _pSelect;
    }   
}

void CegoPredDesc::getPlanList(ListT<Element*>& planList)
{

    if (_pSelect)
    {
	planList.Insert( _pSelect->getPlan() );
    }
    if ( _pC )
    {
	_pC->getPlanList(planList);
    }
    if (_pNotPred)
    {
	_pNotPred->getPlanList(planList);
    }
    if ( _pExpr1 )
    {
	_pExpr1->getPlanList(planList);
    }
    if ( _pExpr2 )
    {
	_pExpr2->getPlanList(planList);
    }
    if ( _pExpr3 )
    {
	_pExpr3->getPlanList(planList);
    }
    
}

CegoPredDesc& CegoPredDesc::operator = ( const CegoPredDesc& p)
{
    _pExpr1 = p._pExpr1;
    _pExpr2 = p._pExpr2;
    _pExpr3 = p._pExpr3;
    _pMatcher = p._pMatcher;
    _comp = p._comp;
    _pSelect = p._pSelect;
    _pC = p._pC;
    _pNotPred = p._pNotPred;
    _mode = p._mode;
    _isChecked = p._isChecked;
    return (*this);
}

void CegoPredDesc::analyzeSelect()
{
    if ( _pSelect )
	_pSelect->prepare();
    if ( _pC )
    {
	if ( _pC->Left() )
	    _pC->Left()->analyzeSelect();
	if ( _pC->Right() )
	    _pC->Right()->analyzeSelect();
    }
    if ( _pNotPred )
    {
	_pNotPred->analyzeSelect();
    }
}

CegoSelect* CegoPredDesc::getSelectQuery()
{
    return _pSelect;
}

void CegoPredDesc::getSelectQueryList(ListT<CegoSelect*>& queryList)
{
    
    if ( _pSelect )
	queryList.Insert(_pSelect);

    if ( _pExpr1 )
    {
	_pExpr1->getSelectQueryList(queryList);
    }
    if ( _pExpr2 )
    {
	_pExpr2->getSelectQueryList(queryList);
    }
    if ( _pExpr3 )
    {
	_pExpr3->getSelectQueryList(queryList);
    }

    if ( _pC )
    {
	if ( _pC->Left() )
	    _pC->Left()->getSelectQueryList(queryList);
	if ( _pC->Right() )
	    _pC->Right()->getSelectQueryList(queryList);
    }
    if ( _pNotPred )
    {
	_pNotPred->getSelectQueryList(queryList);
    }

}

CegoCondDesc* CegoPredDesc::getCondition()
{
    return _pC;
}

CegoPredDesc* CegoPredDesc::getNotPred()
{
    return _pNotPred;
}

CegoComparison CegoPredDesc::getComparison()
{
    return _comp;
}

CegoPredDesc::CompMode CegoPredDesc::getMode()
{
    return _mode;
}

CegoExpr* CegoPredDesc::getExpr1()
{
    return _pExpr1;
}

CegoExpr* CegoPredDesc::getExpr2()
{
    return _pExpr2;
}

CegoExpr* CegoPredDesc::getExpr3()
{
    return _pExpr3;
}


void CegoPredDesc::setBlock(CegoProcBlock* pBlock)
{
    if ( _pExpr1 )
    {
	_pExpr1->setBlock(pBlock);
    }
    if ( _pExpr2 )
    {
	_pExpr2->setBlock(pBlock);
    }
    if ( _pExpr3 )
    {
	_pExpr3->setBlock(pBlock);
    }

    if ( _pSelect )
    {
	_pSelect->setProcBlock(pBlock);
    }
    if (_pC)
    {
	_pC->Left()->setBlock(pBlock);
	_pC->Right()->setBlock(pBlock);
    }
    if (_pNotPred)
    {
	_pNotPred->setBlock(pBlock);
    }
}

void CegoPredDesc::setChecked(bool val)
{
    _isChecked = val;
}


void CegoPredDesc::clearAttrCache()
{
    if ( _pExpr1 )
    {
	_pExpr1->clearAttrCache();
    }
    if ( _pExpr2 )
    {
	_pExpr2->clearAttrCache();
    }
    if ( _pExpr3 )
    {
	_pExpr3->clearAttrCache();
    }

    if ( _pC )
    {
	if ( _pC->Left() )
	    _pC->Left()->clearAttrCache();
	if ( _pC->Right() )
	    _pC->Right()->clearAttrCache();
    }
    if ( _pNotPred )
    {
	_pNotPred->clearAttrCache();
    }


}

void CegoPredDesc::cleanUp()
{
    if (_pNotPred)
    {	
	_pNotPred->cleanUp();
    }
    if (_pC)
    {
	_pC->cleanUp();
    }
    if (_pSelect)
    {
	_pSelect->cleanUp();
    }   
}

void CegoPredDesc::setCheckedRec(bool val)
{
    _isChecked = val;
    if ( _pC )
    {
	_pC->Left()->setCheckedRec(val);
	_pC->Right()->setCheckedRec(val);       
    }
    if ( _pNotPred )
    {
	_pNotPred->setChecked(val);
    }
}

bool CegoPredDesc::isChecked() const
{
    return _isChecked;
}


bool CegoPredDesc::hasOrCond() const
{
    
    if (_pC)
    {
	if ( _pC->getCondType() == CegoCondDesc::OR )
	    return true;
	else if ( _pC->getCondType() == CegoCondDesc::AND )
	    return _pC->Left()->hasOrCond() || _pC->Right()->hasOrCond();       
	else if ( _pC->getCondType() == CegoCondDesc::PRED )
	    return _pC->Left()->hasOrCond();
    }

    return false;

}

const Chain& CegoPredDesc::getPattern() const
{
    return _pattern;
}

bool CegoPredDesc::match(const CegoFieldValue& val) const
{
    if ( _pMatcher )
	return _pMatcher->match(val.valAsChain());
    else 
	throw Exception(EXLOC, "Invalid matcher in predicate");
}

void CegoPredDesc::encode(char *buf)
{
    
    char* pP = (char*)buf;

    memcpy( pP, &_mode, sizeof(CegoPredDesc::CompMode));
    pP = pP + sizeof(CegoPredDesc::CompMode);

    switch (_mode )
    {
    case CegoPredDesc::CONDITION:
    {
	_pC->encode(pP);
	pP = pP + _pC->getEncodingLength();
	break;
    }
    case CegoPredDesc::NOTPRED:
    {
	_pNotPred->encode(pP);
	pP = pP + _pNotPred->getEncodingLength();
	break;
    }
    case CegoPredDesc::EXPRCOMP:
    {
	
	memcpy( pP, &_comp, sizeof(CegoComparison));
	pP = pP + sizeof(CegoComparison);
	
	_pExpr1->encode(pP);
	pP = pP + _pExpr1->getEncodingLength();
	
	_pExpr2->encode(pP);
	pP = pP + _pExpr2->getEncodingLength();

	break;
    }
    case CegoPredDesc::BETWEEN:
    {
	
	_pExpr1->encode(pP);
	pP = pP + _pExpr1->getEncodingLength();
	
	_pExpr2->encode(pP);
	pP = pP + _pExpr2->getEncodingLength();

	_pExpr3->encode(pP);
	pP = pP + _pExpr3->getEncodingLength();

	break;
    }
    case CegoPredDesc::NULLCOMP:
    case CegoPredDesc::NOTNULLCOMP:
    {
	_pExpr1->encode(pP);
	pP = pP + _pExpr1->getEncodingLength();
	break;
    }
    case CegoPredDesc::EXISTSCOMP:
    {
	_pSelect->encode(pP);
	pP = pP + _pSelect->getEncodingLength();
	break;
    }
    case CegoPredDesc::INSUB:
    case CegoPredDesc::NOTINSUB:
    {	
	_pExpr1->encode(pP);
	pP = pP + _pExpr1->getEncodingLength();
	_pSelect->encode(pP);
	pP = pP + _pSelect->getEncodingLength();
	break;
    }
    case CegoPredDesc::ISLIKE:
    case CegoPredDesc::ISNOTLIKE:
    {
	_pExpr1->encode(pP);
	pP = pP + _pExpr1->getEncodingLength();

	char len = _pattern.length();

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

	memcpy( pP, (char*)_pattern, len);
	pP = pP + len;

	break;
    }
    }
}

void CegoPredDesc::decode(char *buf, CegoDistManager *pGTM)
{
    char* pP = (char*)buf;

    memcpy( &_mode, pP, sizeof(CegoPredDesc::CompMode));
    pP = pP + sizeof(CegoPredDesc::CompMode);
    
    // init condition and notpred as zero
    _pC = 0;
    _pNotPred = 0;
    _pSelect = 0;
    _pExpr1=0;
    _pExpr2=0;
    _pExpr3=0;

    switch (_mode )
    {
    case CegoPredDesc::CONDITION:
    {
	_pC = new CegoCondDesc(pP, pGTM);
	pP = pP + _pC->getEncodingLength();
	break;
    }
    case CegoPredDesc::NOTPRED:
    {
	_pNotPred = new CegoPredDesc(pP, pGTM);
	pP = pP + _pNotPred->getEncodingLength();
	break;
    }
    case CegoPredDesc::EXPRCOMP:
    {
	
	memcpy( &_comp, pP, sizeof(CegoComparison));
	pP = pP + sizeof(CegoComparison);

	_pExpr1 = new CegoExpr(pP, pGTM);
	pP = pP + _pExpr1->getEncodingLength();

	_pExpr2 = new CegoExpr(pP, pGTM);
	pP = pP + _pExpr2->getEncodingLength();

	break;
    }
    case CegoPredDesc::BETWEEN:
    {
	
	_pExpr1 = new CegoExpr(pP, pGTM);
	pP = pP + _pExpr1->getEncodingLength();

	_pExpr2 = new CegoExpr(pP, pGTM);
	pP = pP + _pExpr2->getEncodingLength();

	_pExpr3 = new CegoExpr(pP, pGTM);
	pP = pP + _pExpr3->getEncodingLength();

	break;
    }
    case CegoPredDesc::NULLCOMP:
    case CegoPredDesc::NOTNULLCOMP:
    {
	_pExpr1 = new CegoExpr(pP, pGTM);
	pP = pP + _pExpr1->getEncodingLength();
	break;
    }
    case CegoPredDesc::EXISTSCOMP:
    {
	_pSelect = new CegoSelect(pP, pGTM);
	pP = pP + _pSelect->getEncodingLength();
	break;
    }
    case CegoPredDesc::INSUB:
    case CegoPredDesc::NOTINSUB:
    {
	
	_pExpr1 = new CegoExpr(pP, pGTM);
	pP = pP + _pExpr1->getEncodingLength();

	_pSelect = new CegoSelect(pP, pGTM);
	pP = pP + _pSelect->getEncodingLength();

	break;
    }
    case CegoPredDesc::ISLIKE:
    case CegoPredDesc::ISNOTLIKE:
    {
	_pExpr1 = new CegoExpr(pP, pGTM);
	pP = pP + _pExpr1->getEncodingLength();
	
	char len;
	memcpy( pP, &len, sizeof(char));
	pP = pP + sizeof(char);

	_pattern = Chain(pP, len);
	pP = pP + len;

	break;
    }
    }
}

int CegoPredDesc::getEncodingLength() const
{

    int len = 0;

    len += sizeof(CegoPredDesc::CompMode);

    switch (_mode )
    {
    case CegoPredDesc::CONDITION:
    {
	len += _pC->getEncodingLength();
	break;
    }
    case CegoPredDesc::NOTPRED:
    {
	len += _pNotPred->getEncodingLength();
	break;
    }
    case CegoPredDesc::EXPRCOMP:
    {
	len += sizeof(CegoComparison);
	len += _pExpr1->getEncodingLength();
	len += _pExpr2->getEncodingLength();
	break;
    }
    case CegoPredDesc::BETWEEN:
    {
	len += _pExpr1->getEncodingLength();
	len += _pExpr2->getEncodingLength();
	len += _pExpr3->getEncodingLength();
	break;
    }

    case CegoPredDesc::ISLIKE:
    case CegoPredDesc::ISNOTLIKE:
    {
	len += _pExpr1->getEncodingLength();
	len += 1; // sizeof pattern
	len += _pattern.length();
    }
    case CegoPredDesc::NULLCOMP:
    case CegoPredDesc::NOTNULLCOMP:
    {
	len += _pExpr1->getEncodingLength();
	break;
    }
    case CegoPredDesc::EXISTSCOMP:
    {
	len += _pSelect->getEncodingLength();
	break;
    }
    case CegoPredDesc::INSUB:
    case CegoPredDesc::NOTINSUB:
    {
	len += _pExpr1->getEncodingLength();
	len += _pSelect->getEncodingLength();
	break;
    }
    }    
    return len;
}

SetT<Chain> CegoPredDesc::getTableRefSet() const
{
    SetT<Chain> tableRefSet;
    ListT<CegoAttrDesc*> adList = getAttrRefList();
    CegoAttrDesc **pAD = adList.First();
    while ( pAD )
    {
	tableRefSet.Insert((*pAD)->getTableName());
	pAD = adList.Next();
    }
    return tableRefSet;
}

ListT<CegoAttrDesc*> CegoPredDesc::getAttrRefList() const
{

    ListT<CegoAttrDesc*> al;

    switch (_mode )
    {

    case CegoPredDesc::CONDITION:
    {
	al = _pC->getAttrRefList();
	break;
    }
    case CegoPredDesc::NOTPRED:
    {
	al = _pNotPred->getAttrRefList();
	break;
    }
    case CegoPredDesc::EXPRCOMP:
    {
	al = _pExpr1->getAttrRefList();
	al += _pExpr2->getAttrRefList();
	break;
    }
    case CegoPredDesc::BETWEEN:
    {
	al = _pExpr1->getAttrRefList();
	al += _pExpr2->getAttrRefList();
	al += _pExpr3->getAttrRefList();
	break;
    }
    case CegoPredDesc::ISLIKE:
    case CegoPredDesc::ISNOTLIKE:
    {
	al += _pExpr1->getAttrRefList();
	break;
    }
    case CegoPredDesc::NULLCOMP:
    case CegoPredDesc::NOTNULLCOMP:
    {
	al += _pExpr1->getAttrRefList();
	break;
    }
    case CegoPredDesc::INSUB:
    case CegoPredDesc::NOTINSUB:
    {
	al = _pExpr1->getAttrRefList();
	al += _pSelect->getAttrRefList();
	break;
    }
    case CegoPredDesc::EXISTSCOMP:
    {
	al = _pSelect->getAttrRefList();
	break;
    }    
    }
    return al; 
}

int CegoPredDesc::evalReferences(CegoContentObject *pCO, const ListT<CegoField>& fl)
{

    int refCount = 0;

    switch (_mode )
    {

    case CegoPredDesc::CONDITION:
    {
	refCount += _pC->evalReferences(pCO, fl);
	break;
    }
    case CegoPredDesc::NOTPRED:
    {
	refCount += _pNotPred->evalReferences(pCO, fl);
	break;
    }
    case CegoPredDesc::EXPRCOMP:
    {
 	refCount += _pExpr1->evalReferences(pCO, fl);
	refCount += _pExpr2->evalReferences(pCO, fl);
	break;
    }
    case CegoPredDesc::BETWEEN:
    {
	refCount += _pExpr1->evalReferences(pCO, fl);
	refCount += _pExpr2->evalReferences(pCO, fl);
	refCount += _pExpr3->evalReferences(pCO, fl);
	break;
    }
    case CegoPredDesc::ISLIKE:
    case CegoPredDesc::ISNOTLIKE:
    {
	refCount += _pExpr1->evalReferences(pCO, fl);
	break;
    }
    case CegoPredDesc::NULLCOMP:
    case CegoPredDesc::NOTNULLCOMP:
    {
	refCount += _pExpr1->evalReferences(pCO, fl);
	break;
    }
    case CegoPredDesc::INSUB:
    case CegoPredDesc::NOTINSUB:
    {
	refCount += _pExpr1->evalReferences(pCO, fl);
	_pSelect->prepare();
	refCount += _pSelect->evalExtTableReferences(pCO, fl);
	break;
    }
    case CegoPredDesc::EXISTSCOMP:
    {
	_pSelect->prepare();
	refCount += _pSelect->evalExtTableReferences(pCO, fl);
	break;
    }    
    }

    return refCount;

}

ListT<CegoField> CegoPredDesc::getFieldList() const
{

    ListT<CegoField> fl;

    switch (_mode )
    {
    case CegoPredDesc::CONDITION:
    {
	fl = _pC->getFieldList();
	break;
    }
    case CegoPredDesc::NOTPRED:
    {
	fl = _pNotPred->getFieldList();
	break;
    }
    case CegoPredDesc::EXPRCOMP:
    {
	fl = _pExpr1->getFieldList();
	fl += _pExpr2->getFieldList();
	break;
    }
    case CegoPredDesc::BETWEEN:
    {
	fl = _pExpr1->getFieldList();
	fl += _pExpr2->getFieldList();
	fl += _pExpr3->getFieldList();
	break;
    }
    case CegoPredDesc::ISLIKE:
    case CegoPredDesc::ISNOTLIKE:
    {
	fl = _pExpr1->getFieldList();
	break;
    }
    case CegoPredDesc::INSUB:
    case CegoPredDesc::NOTINSUB:
    {
	fl = _pExpr1->getFieldList();
	fl += _pSelect->getFieldList();
	break;
    }
    case CegoPredDesc::EXISTSCOMP:
    {
	fl = _pSelect->getFieldList();
	break;
    }
    default:
	break;
    }
    return fl;
}

CegoPredDesc* CegoPredDesc::clone(bool isAttrRef)
{

    if ( _mode == CegoPredDesc::EXPRCOMP )
    {
	return new CegoPredDesc(_pExpr1->clone(isAttrRef), _pExpr2->clone(isAttrRef), _comp);
    }
    else if ( _mode == CegoPredDesc::BETWEEN )
    {
	return new CegoPredDesc(_pExpr1->clone(isAttrRef), _pExpr2->clone(isAttrRef), _pExpr3->clone(isAttrRef));
    }
    else if ( _mode == CegoPredDesc::ISLIKE )
    {
	return new CegoPredDesc(_pExpr1->clone(isAttrRef), _pattern, false);
    }
    else if ( _mode == CegoPredDesc::ISNOTLIKE )
    {
	return new CegoPredDesc(_pExpr1->clone(isAttrRef), _pattern, true);
    }
    else if ( _mode == CegoPredDesc::CONDITION )
    {
	return new CegoPredDesc(_pC->clone(isAttrRef));
    }
    else if ( _mode == CegoPredDesc::NOTPRED )
    {
	return new CegoPredDesc(_pNotPred->clone(isAttrRef));
    }
    else if ( _mode == CegoPredDesc::EXISTSCOMP )
    {
	return new CegoPredDesc(_pSelect->clone(isAttrRef));
    }
    else if ( _mode == CegoPredDesc::INSUB )
    {
	return new CegoPredDesc(_pExpr1->clone(isAttrRef), _pSelect->clone(isAttrRef), false);
    }
    else if ( _mode == CegoPredDesc::NOTINSUB )
    {
	return new CegoPredDesc(_pExpr1->clone(isAttrRef), _pSelect->clone(isAttrRef), true);
    }
    else if ( _mode == CegoPredDesc::NULLCOMP )
    {
	return new CegoPredDesc(_pExpr1->clone(isAttrRef), true);
    }
    else if ( _mode == CegoPredDesc::NOTNULLCOMP )
    {
	return new CegoPredDesc(_pExpr1->clone(isAttrRef), false);
    }
    throw Exception(EXLOC, "Clone not implemented");

}

Chain CegoPredDesc::toChain(const Chain& indent) const
{
    Chain s;

    switch (_mode )
    {
    case CegoPredDesc::CONDITION:
    {

	if (_pC->Left())
	{
	    s = indent + Chain("( ");
	    s += _pC->Left()->toChain();
	    s += Chain("\n");

	    switch(_pC->getCondType())
	    {
	    case CegoCondDesc::AND:
		s += indent + Chain(" and") + Chain("\n");
		break;
	    case CegoCondDesc::OR:
		s += indent + Chain(" or") + Chain("\n");
		break;
	    default:
		break;
	    }
	    s += indent + _pC->Right()->toChain();
	    s += Chain(" )");
	}
	break;
    }
    case CegoPredDesc::NOTPRED:
    {
	s = indent + Chain("not\n") + _pNotPred->toChain(indent);
	break;
    }
    case CegoPredDesc::EXPRCOMP:
    {
	
	s = indent + _pExpr1->toChain();
	
	switch (_comp)
	{
	case EQUAL:
	    s += " = ";
	    break;
	case NOT_EQUAL:
	    s += " != ";
	    break;
	case LESS_THAN:
	    s += " < ";
	    break;
	case MORE_THAN:
	    s += " > ";
	    break;
	case LESS_EQUAL_THAN:
	    s += " <= ";
	    break;
	case MORE_EQUAL_THAN:
	    s += " >= ";
	    break;
	}
	
	s +=  _pExpr2->toChain();
	break;
    }
    case CegoPredDesc::BETWEEN:
    {
	
	s = indent + _pExpr2->toChain();
	s += Chain(" between ");
	s +=  _pExpr1->toChain();
	s += Chain(" and ");
	s +=  _pExpr3->toChain();

	break;
    }
    case CegoPredDesc::ISLIKE:
    {
	s = indent + _pExpr1->toChain();
	s += Chain(" like ");
	s += Chain("'") + _pattern + Chain("'");
	break;
    }
    case CegoPredDesc::ISNOTLIKE:
    {
	s = indent + _pExpr1->toChain();
	s += Chain(" not like ");
	s += Chain("'") + _pattern + Chain("'");
	break;
    }
    case CegoPredDesc::NULLCOMP:
    {
	s = indent + _pExpr1->toChain();
	s += Chain(" is null ");
	break;
    }
    case CegoPredDesc::NOTNULLCOMP:
    {
	s = indent + _pExpr1->toChain();
	s += Chain(" is not null ");
	break;
    }
    case CegoPredDesc::EXISTSCOMP:
    {
	s = indent + Chain("exists (\n");
	s += indent + _pSelect->toChain(indent) + ")";
	break;
    }
    case CegoPredDesc::INSUB:
    {
	s = indent + _pExpr1->toChain();
	s += Chain(" in ");
	s += Chain("(") + _pSelect->toChain(indent) + Chain(")");   
	break;
    }
    case CegoPredDesc::NOTINSUB:
    {
	s = indent + _pExpr1->toChain();
	s += Chain(" not in ");
	s += Chain("(") + _pSelect->toChain(indent) + Chain(")");   
	break;
    }  
    }
    return s;
}

Element* CegoPredDesc::toElement() const
{

    Element *pPredElement = new Element(XML_PRED_ELEMENT);

    switch (_mode )
    {
    case CegoPredDesc::CONDITION:
    {
	pPredElement->setAttribute( XML_PRED_ATTR, XML_COND_VALUE );
	pPredElement->addContent(  _pC->toElement() );	
	break;
    }
    case CegoPredDesc::NOTPRED:
    {
	pPredElement->setAttribute( XML_PRED_ATTR, XML_NOTPRED_VALUE );
	pPredElement->addContent(  _pNotPred->toElement() );	
	break;
    }
    case CegoPredDesc::EXPRCOMP:
    {
	pPredElement->addContent(  _pExpr1->toElement() );
	pPredElement->addContent(  _pExpr2->toElement() );
	pPredElement->setAttribute( XML_PRED_ATTR, XML_EXPRCOMP_VALUE );
    
	switch (_comp)
	{
	case EQUAL:
	    pPredElement->setAttribute( XML_COMP_ATTR, XML_EQUAL_VALUE );    
	    break;
	case NOT_EQUAL:
	    pPredElement->setAttribute( XML_COMP_ATTR, XML_NOTEQUAL_VALUE ); 
	    break;
	case LESS_THAN:
	    pPredElement->setAttribute( XML_COMP_ATTR, XML_LESSTHAN_VALUE ); 
	    break;
	case MORE_THAN:
	    pPredElement->setAttribute( XML_COMP_ATTR, XML_MORETHAN_VALUE ); 
	    break;
	case LESS_EQUAL_THAN:
	    pPredElement->setAttribute( XML_COMP_ATTR, XML_LESSEQUALTHAN_VALUE ); 
	    break;
	case MORE_EQUAL_THAN:
	    pPredElement->setAttribute( XML_COMP_ATTR, XML_MOREEQUALTHAN_VALUE );
	    break;
	}
	
	break;
    }
    case CegoPredDesc::BETWEEN:
    {
	pPredElement->addContent(  _pExpr1->toElement() );
	pPredElement->addContent(  _pExpr2->toElement() );
	pPredElement->addContent(  _pExpr3->toElement() );
	pPredElement->setAttribute( XML_PRED_ATTR, XML_BETWEEN_VALUE );
	break;
    }
    case CegoPredDesc::ISLIKE:
    {
	pPredElement->setAttribute( XML_PRED_ATTR, XML_ISLIKE_VALUE ); 
	pPredElement->addContent(  _pExpr1->toElement() );
	pPredElement->setAttribute( XML_PATTERN_ATTR, _pattern );
	break;
    }
    case CegoPredDesc::ISNOTLIKE:
    {
	pPredElement->setAttribute( XML_PRED_ATTR, XML_ISLIKE_VALUE ); 
	pPredElement->addContent(  _pExpr1->toElement() );
	pPredElement->setAttribute( XML_PATTERN_ATTR, _pattern ); 
	break;
    }
    case CegoPredDesc::NULLCOMP:
    {
	pPredElement->setAttribute( XML_PRED_ATTR, XML_NULLCOMP_VALUE ); 
	pPredElement->addContent ( _pExpr1->toElement() );
	break;
    }
    case CegoPredDesc::NOTNULLCOMP:
    {
	pPredElement->setAttribute( XML_PRED_ATTR, XML_NOTNULLCOMP_VALUE ); 
	pPredElement->addContent ( _pExpr1->toElement() );
	break;
    }
    case CegoPredDesc::EXISTSCOMP:
    {
	pPredElement->setAttribute( XML_PRED_ATTR, XML_EXISTS_VALUE ); 
	pPredElement->addContent( _pSelect->toElement() );
	break;
    }
    case CegoPredDesc::INSUB:
    {
	pPredElement->setAttribute( XML_PRED_ATTR, XML_INCOMP_VALUE ); 
	pPredElement->addContent ( _pExpr1->toElement() );
	pPredElement->addContent( _pSelect->toElement() );
	break;
    }
    case CegoPredDesc::NOTINSUB:
    {
	pPredElement->setAttribute( XML_PRED_ATTR, XML_NOTINCOMP_VALUE ); 
	pPredElement->addContent ( _pExpr1->toElement() );
	pPredElement->addContent( _pSelect->toElement() );
	break;
    }       
    }
    return pPredElement;
}

void CegoPredDesc::fromElement(Element* pPredElement, CegoDistManager *pGTM)
{

    if ( _pExpr1 )
	delete _pExpr1;
    if ( _pExpr2 )
	delete _pExpr2;
    if ( _pExpr3 )
	delete _pExpr3;

    if ( _pC )
	delete _pC;
    if ( _pNotPred )
	delete _pNotPred;
    if ( _pSelect )
	delete _pSelect;

    _pExpr1 = 0;
    _pExpr2 = 0;
    _pExpr3 = 0;
    _pC = 0;
    _pNotPred = 0;
    _isChecked = false;
    _pSelect = 0;

    Chain mode = pPredElement->getAttributeValue( XML_PRED_ATTR );

    if ( mode == Chain(XML_COND_VALUE) )
    {
	_mode = CegoPredDesc::CONDITION;

	ListT<Element*> cel = pPredElement->getChildren(XML_COND_ELEMENT);
	Element **pCE = cel.First();
	if ( pCE ) 
	{
	    _pC = new CegoCondDesc(*pCE, pGTM);
	}
	else
	{
	    throw Exception(EXLOC, "Invalid element");
	} 
    }
    else if ( mode == Chain(XML_NOTPRED_VALUE) )
    {
	_mode = CegoPredDesc::NOTPRED;
	
	ListT<Element*> npl = pPredElement->getChildren(XML_PRED_ELEMENT);
	Element **pNPE = npl.First();
	if ( pNPE ) 
	{
	    _pNotPred = new CegoPredDesc(*pNPE, pGTM);
	}
	else
	{
	    throw Exception(EXLOC, "Invalid element");
	} 
    }
    else if ( mode == Chain(XML_EXPRCOMP_VALUE) )
    {
	

	_mode = CegoPredDesc::EXPRCOMP;

	ListT<Element*> el = pPredElement->getChildren(XML_EXPR_ELEMENT);
	Element **pEE = el.First();
	if ( pEE )
	{
	    _pExpr1 = new CegoExpr(*pEE, pGTM);
	}
	pEE = el.Next();
	if ( pEE )
	{
	    _pExpr2 = new CegoExpr(*pEE, pGTM);
	}

	Chain compString = pPredElement->getAttributeValue( XML_COMP_ATTR );    

	if ( compString == Chain(XML_EQUAL_VALUE) )
	{
	    _comp = EQUAL;
	}
	else if ( compString == Chain(XML_NOTEQUAL_VALUE) )
	{
	    _comp = NOT_EQUAL;
	}
	else if ( compString == Chain(XML_LESSTHAN_VALUE) )
	{
	    _comp = LESS_THAN;
	}
	else if ( compString == Chain(XML_MORETHAN_VALUE) )
	{
	    _comp = MORE_THAN;
	}
	else if ( compString == Chain(XML_LESSEQUALTHAN_VALUE) )
	{
	    _comp = LESS_EQUAL_THAN;
	}
	else if ( compString == Chain(XML_MOREEQUALTHAN_VALUE) )
	{
	    _comp = MORE_EQUAL_THAN;
	}
	
    }
    else if ( mode == Chain(XML_BETWEEN_VALUE) )
    {
	

	_mode = CegoPredDesc::BETWEEN;

	ListT<Element*> el = pPredElement->getChildren(XML_EXPR_ELEMENT);
	Element **pEE = el.First();
	if ( pEE )
	{
	    _pExpr1 = new CegoExpr(*pEE, pGTM);
	}
	pEE = el.Next();
	if ( pEE )
	{
	    _pExpr2 = new CegoExpr(*pEE, pGTM);
	}
	pEE = el.Next();
	if ( pEE )
	{
	    _pExpr3 = new CegoExpr(*pEE, pGTM);
	}
    }
    else if ( mode == Chain(XML_ISLIKE_VALUE) )
    {
	_mode = CegoPredDesc::ISLIKE;
	ListT<Element*> el = pPredElement->getChildren(XML_EXPR_ELEMENT);
	Element **pEE = el.First();
	if ( pEE )
	{
	    _pExpr1 = new CegoExpr(*pEE, pGTM);
	}

	_pattern = pPredElement->getAttributeValue( XML_PATTERN_ATTR );    	
	
    }
    else if ( mode == Chain(XML_ISNOTLIKE_VALUE) )
    {
	_mode = CegoPredDesc::ISNOTLIKE;
	ListT<Element*> el = pPredElement->getChildren(XML_EXPR_ELEMENT);
	Element **pEE = el.First();
	if ( pEE )
	{
	    _pExpr1 = new CegoExpr(*pEE, pGTM);
	}

	_pattern = pPredElement->getAttributeValue( XML_PATTERN_ATTR );    	

    }
    else if ( mode == Chain(XML_NULLCOMP_VALUE) )
    {

	_mode = CegoPredDesc::NULLCOMP;
	ListT<Element*> el = pPredElement->getChildren(XML_EXPR_ELEMENT);
	Element **pEE = el.First();
	if ( pEE )
	{
	    _pExpr1 = new CegoExpr(*pEE, pGTM);
	}
	
    }
    else if ( mode == Chain(XML_NOTNULLCOMP_VALUE) )
    {
	_mode = CegoPredDesc::NOTNULLCOMP;
	ListT<Element*> el = pPredElement->getChildren(XML_EXPR_ELEMENT);
	Element **pEE = el.First();
	if ( pEE )
	{
	    _pExpr1 = new CegoExpr(*pEE, pGTM);
	}
    }
    else if ( mode == Chain(XML_EXISTS_VALUE) )
    {
	_mode = CegoPredDesc::EXISTSCOMP;
	ListT<Element*> sl = pPredElement->getChildren(XML_SELECT_ELEMENT);
	Element **pSE = sl.First();
	if ( pSE )
	{
	    _pSelect = new CegoSelect(*pSE, pGTM);
	}
    }
    else if ( mode == Chain(XML_INCOMP_VALUE) )
    {
	_mode = CegoPredDesc::INSUB;

	ListT<Element*> el = pPredElement->getChildren(XML_EXPR_ELEMENT);
	Element **pEE = el.First();
	if ( pEE )
	{
	    _pExpr1 = new CegoExpr(*pEE, pGTM);
	}

	ListT<Element*> sl = pPredElement->getChildren(XML_SELECT_ELEMENT);
	Element **pSE = sl.First();
	if ( pSE )
	{
	    _pSelect = new CegoSelect(*pSE, pGTM);
	}
    }
    else if ( mode == Chain(XML_NOTINCOMP_VALUE) )
    {
	_mode = CegoPredDesc::NOTINSUB;

	ListT<Element*> el = pPredElement->getChildren(XML_EXPR_ELEMENT);
	Element **pEE = el.First();
	if ( pEE )
	{
	    _pExpr1 = new CegoExpr(*pEE, pGTM);
	}

	ListT<Element*> sl = pPredElement->getChildren(XML_SELECT_ELEMENT);
	Element **pSE = sl.First();
	if ( pSE )
	{
	    _pSelect = new CegoSelect(*pSE, pGTM);
	}
    }
}  

ostream& operator << (ostream& s, const CegoPredDesc& p)
{
    s << p.toChain();
    return s;
}
