///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoHavingDesc.cc
// -----------------
// Cego having clause 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: CegoHavingDesc
// 
// Description: 
//
// Status: QG-2.6
//
///////////////////////////////////////////////////////////////////////////////

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

CegoHavingDesc::CegoHavingDesc(CegoExpr* pAggExpr, CegoExpr* pExpr, const CegoComparison& comp)
{
    _pAggExpr = pAggExpr;    
    _pExpr = pExpr;
    _comp = comp;
}

CegoHavingDesc::CegoHavingDesc(char* buf, CegoDistManager *pGTM)
{
    _pAggExpr = 0;
    _pExpr = 0;
    decode(buf, pGTM);
}

CegoHavingDesc::CegoHavingDesc(Element* pHE, CegoDistManager *pGTM)
{
    _pAggExpr = 0;
    _pExpr = 0;
    fromElement(pHE, pGTM);
}

CegoHavingDesc::~CegoHavingDesc()
{
    if ( _pAggExpr )
	delete _pAggExpr;
    if ( _pExpr )
	delete _pExpr;
}

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

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

    attrList = _pExpr->getAttrRefList();
    attrList += _pAggExpr->getAttrRefList();
    
    return attrList;
}

void CegoHavingDesc::encode(char *buf)
{

    char* pBuf = (char*)buf;

    _pAggExpr->encode(pBuf);
    pBuf = pBuf + _pAggExpr->getEncodingLength();

    _pExpr->encode(pBuf);
    pBuf = pBuf + _pExpr->getEncodingLength();
}

void CegoHavingDesc::decode(char *buf, CegoDistManager *pGTM)
{
    if ( _pAggExpr )
	delete _pAggExpr;
    if ( _pExpr )
	delete _pExpr;

    char* pBuf = (char*)buf;

    _pAggExpr = new CegoExpr(pBuf, pGTM);
    pBuf = pBuf + _pAggExpr->getEncodingLength();

    _pExpr = new CegoExpr(pBuf, pGTM);
    pBuf = pBuf + _pExpr->getEncodingLength();

}

int CegoHavingDesc::getEncodingLength() const
{
    return _pAggExpr->getEncodingLength() + _pExpr->getEncodingLength();
}


CegoExpr* CegoHavingDesc::getAggExpr()
{
    return _pAggExpr;
}

CegoExpr* CegoHavingDesc::getExpr()
{
    return _pExpr;
}

Element* CegoHavingDesc::toElement() const
{
    Element *pHavingElement = new Element( XML_HAVING_ELEMENT );
    
    pHavingElement->addContent( _pAggExpr->toElement() );
    pHavingElement->addContent( _pExpr->toElement() );
    
    switch (_comp)
    {
    case EQUAL:
	pHavingElement->setAttribute(XML_COMP_ATTR, XML_EQUAL_VALUE);
	break;
    case NOT_EQUAL:
	pHavingElement->setAttribute(XML_COMP_ATTR, XML_NOTEQUAL_VALUE);
	break;
    case LESS_THAN:
	pHavingElement->setAttribute(XML_COMP_ATTR, XML_LESSTHAN_VALUE);
	break;
    case MORE_THAN:
	pHavingElement->setAttribute(XML_COMP_ATTR, XML_MORETHAN_VALUE);
	break;
    case LESS_EQUAL_THAN:
	pHavingElement->setAttribute(XML_COMP_ATTR, XML_LESSEQUALTHAN_VALUE);
	break;
    case MORE_EQUAL_THAN:
	pHavingElement->setAttribute(XML_COMP_ATTR, XML_MOREEQUALTHAN_VALUE);
	break;
    }
    
    return pHavingElement;

}

void CegoHavingDesc::fromElement(Element *pHavingElement, CegoDistManager *pGTM)
{

    if ( _pAggExpr )
	delete _pAggExpr;
    if ( _pExpr )
	delete _pExpr;

    
    ListT<Element*> el = pHavingElement->getChildren(XML_EXPR_ELEMENT);
    Element **pEE = el.First();
    if ( pEE )
    {
	_pExpr = new CegoExpr(*pEE, pGTM);
    }
    ListT<Element*> al = pHavingElement->getChildren(XML_AGGREGATION_ELEMENT);
    Element **pAE = al.First();
    if ( pAE )
    {
	_pAggExpr = new CegoExpr(*pAE, pGTM);
    }

    Chain compString = pHavingElement->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;

}

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

    s += indent + _pAggExpr->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 += _pExpr->toChain();

    return s;
}

CegoHavingDesc* CegoHavingDesc::clone(bool isAttrRef)
{
    return new CegoHavingDesc(_pAggExpr->clone(isAttrRef), _pExpr->clone(isAttrRef), _comp);
}

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