///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoProcPred.cc  
// -----------------                                                     
// Cego predicate class implementation
//                                                         
// 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: CegoProcPred
// 
// Description:
//
// Status: QG-2.6
//
///////////////////////////////////////////////////////////////////////////////

// base includes
#include <lfc/Chain.h>
#include <lfc/Datetime.h>

// cego includes
#include "CegoProcPred.h"

CegoProcPred::CegoProcPred()
{

}

CegoProcPred::CegoProcPred(CegoExpr* pExpr1, CegoExpr* pExpr2, CegoComparison comp)
{
    _mode = EXPRCOMP;
    _pExpr1 = pExpr1;
    _pExpr2 = pExpr2;
    _comp = comp;
    _pCond = 0;
}

CegoProcPred::CegoProcPred(CegoExpr* pExpr1, bool isNegate)
{
    _mode = NULLCOMP;
    _pExpr1 = pExpr1;
    _pExpr2 = 0;
    _isNegate = isNegate;
    _pCond = 0;
}

CegoProcPred::CegoProcPred(CegoProcCond *pCond)
{
    _mode = CONDITION;
    _pCond = pCond;
    _pExpr1 = 0;
    _pExpr2 = 0;
}

CegoProcPred::~CegoProcPred()  
{
    if ( _pCond ) 
	delete _pCond;
    if ( _pExpr1 )
	delete _pExpr1;
    if ( _pExpr2 )
	delete _pExpr2;
}

void CegoProcPred::setBlock(CegoProcBlock *pBlock)
{

    if ( _mode == CONDITION )
	_pCond->setBlock(pBlock);
    else
    {
	if ( _pExpr1 )
	    _pExpr1->setBlock(pBlock);
	if ( _pExpr2 )
	    _pExpr2->setBlock(pBlock);
    }
}

bool CegoProcPred::eval() const
{
    if ( _mode == CONDITION )
    {
	return _pCond->eval();
    }
    else if ( _mode == EXPRCOMP )
    {
	CegoFieldValue v1;
	CegoFieldValue v2;
	
	if ( _pExpr1 )
	{
		v1 = _pExpr1->evalFieldValue();
	}   
	if ( _pExpr2 ) 
	{
	    v2 = _pExpr2->evalFieldValue();
	}
    
	switch (_comp)
	{
	case EQUAL:
	{
	    if ( v1 == v2 )
		return true;
	    return false;
	}
	
	case LESS_THAN:
	{
	    if ( v1 < v2 )
		return true;
	    return false;
	}	
	case MORE_THAN:
	{
	    if ( v1 > v2 )
		return true;
	    return false;
	}
	case LESS_EQUAL_THAN:
	{
	    if ( v1 <= v2 )
		return true;
	    return false;
	}
	case MORE_EQUAL_THAN:
	{
	    if ( v1 >= v2 )
		return true;
	    return false;
	}
	case NOT_EQUAL:
	{
	    if ( v1 != v2 )
		return true;
	    return false;
	}
	}
    }
    else if ( _mode == NULLCOMP )
    {
	CegoFieldValue v1;

	if ( _pExpr1 )
	{
	    v1 = _pExpr1->evalFieldValue();
	}   
	
	if ( _isNegate )
	    return ! v1.isNull();
	return v1.isNull();
    }
    else
    {
	throw Exception(EXLOC, Chain("Mode not supported"));
    }
}

CegoProcPred& CegoProcPred::operator = (const CegoProcPred& c)
{
    _pExpr1 = c._pExpr1;
    _pExpr2 = c._pExpr2;
    _pCond = c._pCond;
    _comp = c._comp;
    _mode = c._mode;
    _isNegate = c._isNegate;
    return (*this);
}

Chain CegoProcPred::toChain() const
{
    Chain s;
    if ( _mode == CONDITION )
    {
	s = _pCond->toChain();
    }
    else if ( _mode == EXPRCOMP )
    {
	s = _pExpr1->toChain();

	switch (_comp)
	{
	case 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;	    
	}
	case NOT_EQUAL:
	{
	    s += " != ";
	    break;	    
	}
	}

	s += _pExpr2->toChain();
    }
    else if ( _mode == NULLCOMP )
    {
	s = _pExpr1->toChain();
	if ( _isNegate )
	{
	    s += " is not null";
	}
	else
	{
	    s += " is null";
	}
    }
    return s;
}

ostream& operator << (ostream& s, const CegoProcPred& e)
{
    s << e.toChain();
    return s;
}

