///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoCondDesc.cc
// ---------------
// Cego condition description
//
// 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: CegoCondDesc
// 
// Description: 
//
// Status: QG-2.6
//
///////////////////////////////////////////////////////////////////////////////

#include "CegoCondDesc.h"
#include "CegoXMLdef.h"

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

CegoCondDesc::CegoCondDesc(char *buf, CegoDistManager *pGTM)
{
    _pLeft=0;
    _pRight=0;
    
    decode(buf, pGTM);
}

CegoCondDesc::CegoCondDesc(Element *pCondElement, CegoDistManager *pGTM)
{
    _pLeft=0;
    _pRight=0;

    fromElement(pCondElement, pGTM);
}

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

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

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

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

CegoPredDesc* CegoCondDesc::Left()
{
    return _pLeft;
}


CegoPredDesc* CegoCondDesc::Right()
{
    return _pRight;
}


void CegoCondDesc::setLeft(CegoPredDesc* pP)
{
    _pLeft = pP;
}

void CegoCondDesc::setRight(CegoPredDesc* pP)
{
    _pRight = pP;
}

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

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


void CegoCondDesc::setBlock(CegoProcBlock* pBlock)
{
    if (_pLeft)
    {
	_pLeft->setBlock(pBlock);
    }
    if (_pRight)
    {
	_pRight->setBlock(pBlock);
    }
}

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

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

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

void CegoCondDesc::decode(char *buf, CegoDistManager *pGTM)
{

    if ( _pLeft ) 
	delete _pLeft;
    if ( _pRight ) 
	delete _pRight;
    
    char* pP = (char*)buf;

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

int CegoCondDesc::getEncodingLength() const
{

    int len = 0;

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

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

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

    return al;

}

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

    int refCount = 0;

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

    return refCount;
    
}

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

    ListT<CegoField> fl;
    
    switch( _condType )
    {
    case CegoCondDesc::AND:
    case CegoCondDesc::OR:
    {
	fl += _pLeft->getFieldList();
	fl += _pRight->getFieldList();
	break;
    }
    case CegoCondDesc::PRED:
    {
	fl += _pLeft->getFieldList();
	break;
    }
    }
    return fl;
}

Element* CegoCondDesc::toElement() const
{

    Element *pCondElement = new Element(XML_COND_ELEMENT);

    
    switch( _condType )
    {
    case CegoCondDesc::AND:
    {
	pCondElement->setAttribute( XML_COND_ATTR, XML_AND_VALUE );
	pCondElement->addContent( _pLeft->toElement() );
	pCondElement->addContent( _pRight->toElement() );
	break;
    }
    case CegoCondDesc::OR:
    {
	pCondElement->setAttribute( XML_COND_ATTR, XML_OR_VALUE );
	pCondElement->addContent( _pLeft->toElement() );
	pCondElement->addContent( _pRight->toElement() );
	break;
    }
    case CegoCondDesc::PRED:
    {
	pCondElement->setAttribute( XML_COND_ATTR, XML_PRED_VALUE );
	pCondElement->addContent( _pLeft->toElement() );
	break;
    }
    }
    
    return pCondElement;
}

void CegoCondDesc::fromElement(Element* pCondElement, CegoDistManager *pGTM)
{

    if (_pLeft)
	delete _pLeft;
    
    if (_pRight)
	delete _pRight;

    Chain mode = pCondElement->getAttributeValue( XML_COND_ATTR );

    if ( mode == Chain(XML_AND_VALUE) )
    {
	_condType = CegoCondDesc::AND;

	ListT<Element*> pl = pCondElement->getChildren(XML_PRED_ELEMENT);
	Element **pPE = pl.First();
	if ( pPE ) 
	{
	    _pLeft = new CegoPredDesc(*pPE, pGTM);
	}
	pPE = pl.Next();
	if ( pPE ) 
	{
	    _pRight = new CegoPredDesc(*pPE, pGTM);
	}
    }
    else if ( mode == Chain(XML_OR_VALUE) )
    {
	_condType = CegoCondDesc::OR;

	ListT<Element*> pl = pCondElement->getChildren(XML_PRED_ELEMENT);
	Element **pPE = pl.First();
	if ( pPE ) 
	{
	    _pLeft = new CegoPredDesc(*pPE, pGTM);
	}
	pPE = pl.Next();
	if ( pPE ) 
	{
	    _pRight = new CegoPredDesc(*pPE, pGTM);
	}
    }
    else if ( mode == Chain(XML_PRED_VALUE) )
    {
	_condType = CegoCondDesc::PRED;
	ListT<Element*> pl = pCondElement->getChildren(XML_PRED_ELEMENT);
	Element **pPE = pl.First();
	if ( pPE ) 
	{
	    _pLeft = new CegoPredDesc(*pPE, pGTM);
	}
    }
}

CegoCondDesc* CegoCondDesc::clone(bool isAttrRef)
{
    CegoCondDesc* pCD = new CegoCondDesc(_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;;
}
