///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoFunction.cc
// ---------------
// Cego internal sql function 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: CegoFunction
// 
// Description: 
//
// Status: QG-2.6
//
///////////////////////////////////////////////////////////////////////////////

#include <lfc/Datetime.h>
#include <lfc/Tokenizer.h>

#include "CegoFunction.h"
#include "CegoExpr.h"
#include "CegoProcedure.h"
#include "CegoDistManager.h"
#include "CegoXMLdef.h"

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

CegoFunction::CegoFunction(char* buf, CegoDistManager *pGTM)
{
    decode(buf, pGTM);
}

CegoFunction::CegoFunction(CegoFunction::FunctionType type)
{
    _pTabMng = 0;
    _type = type;
}

CegoFunction::CegoFunction(CegoFunction::FunctionType type, ListT<CegoExpr*>& exprList)
{
    _pTabMng = 0;
    _exprList = exprList;
    _type = type;
}

CegoFunction::CegoFunction(CegoDistManager* pTabMng, int tabSetId, CegoFunction::FunctionType type)
{
    _pTabMng = pTabMng;
    _tabSetId = tabSetId;
    _type = type;
}

CegoFunction::CegoFunction(CegoDistManager* pTabMng, int tabSetId, const Chain& funcName, ListT<CegoExpr*>& exprList)
{
    _pTabMng = pTabMng;
    _exprList = exprList;
    _funcName = funcName;
    _tabSetId = tabSetId;
    _type = CegoFunction::USERDEFINED;
}

CegoFunction::CegoFunction(Element* pFunctionElement, CegoDistManager *pGTM)
{
    fromElement(pFunctionElement, pGTM);
}

CegoFunction::~CegoFunction()
{
}
    
const CegoFunction::FunctionType CegoFunction::getType() const
{
    return _type;
}

void CegoFunction::setExprList(ListT<CegoExpr*>& exprList)
{
    
    if ( _type == TRIM && exprList.Size() != 2)
	throw Exception(EXLOC, Chain("Invalid parameter count for trim function"));
    if ( _type == LTRIM && exprList.Size() != 2)
	throw Exception(EXLOC, Chain("Invalid parameter count for ltrim function"));
    if ( _type == RTRIM && exprList.Size() != 2)
	throw Exception(EXLOC, Chain("Invalid parameter count for rtrim function"));
    if ( _type == ROUND && ( exprList.Size() < 1 || exprList.Size() > 2) )
	throw Exception(EXLOC, Chain("Invalid parameter count for round function"));
    if ( _type == DATE2STR && exprList.Size() != 2)
	throw Exception(EXLOC, Chain("Invalid parameter count for date2str function"));
    if ( _type == DATE2INT && exprList.Size() != 1)
	throw Exception(EXLOC, Chain("Invalid parameter count for date2int function"));
    if ( _type == INT2DATE && exprList.Size() != 1)
	throw Exception(EXLOC, Chain("Invalid parameter count for int2date function"));
    if ( _type == LOWER && exprList.Size() != 1)
	throw Exception(EXLOC, Chain("Invalid parameter count for lower function"));
    if ( _type == UPPER && exprList.Size() != 1)
	throw Exception(EXLOC, Chain("Invalid parameter count for upper function"));
    if ( _type == LEFT && exprList.Size() != 2)
	throw Exception(EXLOC, Chain("Invalid parameter count for left function"));
    if ( _type == RIGHT && exprList.Size() != 2)
	throw Exception(EXLOC, Chain("Invalid parameter count for right function"));
    if ( _type == GETPOS && ( exprList.Size() < 2 || exprList.Size() > 4 ) )
	throw Exception(EXLOC, Chain("Invalid parameter count for getpos function"));
    if ( _type == SUBSTR && ( exprList.Size() < 2 || exprList.Size() > 3 ) )
	throw Exception(EXLOC, Chain("Invalid parameter count for substr function"));
    if ( _type == REPLACE && exprList.Size() != 3)
	throw Exception(EXLOC, Chain("Invalid parameter count for replace function"));
    if ( _type == LENGTH && exprList.Size() != 1)
	throw Exception(EXLOC, Chain("Invalid parameter count for length function"));
    if ( _type == TRUNC && exprList.Size() != 1)
	throw Exception(EXLOC, Chain("Invalid parameter count for trunc function"));
    if ( _type == STR2INT && exprList.Size() != 1)
	throw Exception(EXLOC, Chain("Invalid parameter count for str2int function"));
    if ( _type == STR2LONG && exprList.Size() != 1)
	throw Exception(EXLOC, "Invalid parameter count for trim str2long");
    if ( _type == RANDSTR && exprList.Size() != 1)
	throw Exception(EXLOC, "Invalid parameter count for randstr function");
    if ( _type == RANDINT && exprList.Size() != 1)
	throw Exception(EXLOC, "Invalid parameter count for randint function");
    if ( _type == MOD && exprList.Size() != 2)
	throw Exception(EXLOC, "Invalid parameter count for mod function");
    if ( _type == DIV && exprList.Size() != 2)
	throw Exception(EXLOC, "Invalid parameter count for div function");
    if ( _type == POWER && exprList.Size() != 2)
	throw Exception(EXLOC, "Invalid parameter count for power function");
    if ( _type == BITAND && exprList.Size() != 2)
	throw Exception(EXLOC, "Invalid parameter count for bitand function");
    if ( _type == BITOR && exprList.Size() != 2)
	throw Exception(EXLOC, "Invalid parameter count for bitor function");
    if ( _type == BITXOR && exprList.Size() != 2)
	throw Exception(EXLOC, "Invalid parameter count for bitxor function");

    
    _exprList = exprList;
}


ListT<CegoExpr*>& CegoFunction::getExprList()
{
    return _exprList;
}

ListT<CegoField> CegoFunction::getFieldList() const
{
    ListT<CegoField> fl;

    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	fl += (*pExpr)->getFieldList();
	pExpr = _exprList.Next();
    }

    return fl;
}

void CegoFunction::setFieldListArray(ListT<CegoField> *fla, int size)
{
    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	(*pExpr)->setFieldListArray(fla, size);	    
	pExpr = _exprList.Next();
    }
}

void CegoFunction::setBlock(CegoProcBlock *pBlock)
{
    _pBlock = pBlock;
    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	(*pExpr)->setBlock(pBlock);	    
	pExpr = _exprList.Next();
    }
}

void CegoFunction::clearAttrCache()
{
    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	(*pExpr)->clearAttrCache();	    
	pExpr = _exprList.Next();
    }
}

void CegoFunction::setCounterId(const Chain& counterId)
{
    _counterId = counterId;
}

void CegoFunction::setCounterExpr(CegoExpr *pExpr)
{
    _exprList.Insert(pExpr);
}

ListT<CegoAttrDesc*> CegoFunction::getAttrRefList() const
{
    ListT<CegoAttrDesc*> attrList;
    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	attrList += (*pExpr)->getAttrRefList();
	pExpr = _exprList.Next();
    }
    return attrList;
}

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

    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	refCount += (*pExpr)->evalReferences(pCO, fl);
	pExpr = _exprList.Next();
    }

    return refCount;

}

CegoFieldValue CegoFunction::evalFieldValue() const
{

    switch ( _type ) 
    {
    case CegoFunction::ROUND:
    {
	
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	int precision = 0;

	if ( pExpr2 != 0 )
	{
	    CegoFieldValue pv = (*pExpr2)->evalFieldValue();
	    
	    if ( pv.getType() != INT_TYPE )
	    {
		Chain msg = Chain("Invalid precision in function round"); 
		throw Exception(EXLOC, msg);
	    }
	    if ( pv.getValue() != 0 )
		memcpy(&precision, pv.getValue(), sizeof(int));
	    // precision = *((int*)pv.getValue());
	}
	
	CegoFieldValue fv;
	
	fv = (*pExpr1)->evalFieldValue();
	
	Tokenizer tok(fv.valAsChain(), Chain("."));

	Chain lpart;
	tok.nextToken(lpart);
	Chain rpart;
	tok.nextToken(rpart);
	
	CegoFieldValue retVal;
	if ( precision > 0 )
	{	    
	    retVal = CegoFieldValue(VARCHAR_TYPE, lpart + Chain(".") + rpart.subChain(1, precision));
	}
	else
	{
	    retVal = CegoFieldValue(INT_TYPE, lpart);
	}
	return retVal;
    }
    case CegoFunction::DATE2STR:
    {		
	
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue();
	fv2 = (*pExpr2)->evalFieldValue();

	int val = 0; 
	if ( fv1.getValue() != 0 )
	    memcpy(&val, fv1.getValue(), sizeof(int));

	CegoFieldValue fv;

	if ( val > 0 )
	{
	    Datetime dt;
	    dt = Datetime(val);
	    fv = CegoFieldValue(VARCHAR_TYPE, dt.asChain(fv2.valAsChain()));
	}
	
	return fv;
	
    }
    case CegoFunction::DATE2INT:
    {		
	
	CegoExpr** pExpr1 = _exprList.First();
	
	CegoFieldValue fv1;
	
	fv1 = (*pExpr1)->evalFieldValue();

	int val = 0; 
	if ( fv1.getValue() != 0 )
	    memcpy(&val, fv1.getValue(), sizeof(int));
	if ( val == 0 )
	{
	    Datetime dt;
	    val = dt.asInt();
	}
	
	CegoFieldValue fv(INT_TYPE, val);
	return fv;	
    }
    case CegoFunction::INT2DATE:
    {			
	CegoExpr** pExpr1 = _exprList.First();
	
	CegoFieldValue fv1;
	
	fv1 = (*pExpr1)->evalFieldValue();

	int *pVal = new int;
	if ( fv1.getValue() != 0 )
	    memcpy(pVal, fv1.getValue(), sizeof(int));

	CegoFieldValue fv(DATETIME_TYPE, pVal, sizeof(int), true);
	return fv;
    }

    case CegoFunction::TRUNC:
    {
	
	CegoExpr** pExpr = _exprList.First();
	
	CegoFieldValue fv;

	fv = (*pExpr)->evalFieldValue();
	
	Tokenizer t(fv.valAsChain(), ".");
	Chain truncVal;
	t.nextToken(truncVal);
	CegoFieldValue retVal(INT_TYPE, truncVal);
	return retVal;
    }
    case CegoFunction::LOWER:
    {
	
	CegoExpr** pExpr = _exprList.First();
	
	CegoFieldValue fv;
	
	fv = (*pExpr)->evalFieldValue();
	
	CegoFieldValue retVal(VARCHAR_TYPE, fv.valAsChain().toLower());
	return retVal;
    }
    case CegoFunction::UPPER:
    {
	
	CegoExpr** pExpr = _exprList.First();
	
	CegoFieldValue fv;
	
	fv = (*pExpr)->evalFieldValue();
	
	CegoFieldValue retVal(VARCHAR_TYPE, fv.valAsChain().toUpper());
	return retVal;
    }
    case CegoFunction::RIGHT:
    {
	
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue();
	fv2 = (*pExpr2)->evalFieldValue();

	if ( fv2.getType() != INT_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function right"); 
	    throw Exception(EXLOC, msg);
	}
	int len; 
	if ( fv2.getValue() != 0 )
	    memcpy(&len, fv2.getValue(), sizeof(int));
	// len = *((int*)fv2.getValue());
			
	Chain right;
	if ( len < fv1.valAsChain().length() )
	    right = fv1.valAsChain().subChain(fv1.valAsChain().length() - len, fv1.valAsChain().length());
	else
	    right = fv1.valAsChain();
	
	CegoFieldValue fv(VARCHAR_TYPE, right);
	return fv;
    }
    case CegoFunction::LEFT:
    {
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue();
	fv2 = (*pExpr2)->evalFieldValue();

	if ( fv2.getType() != INT_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function right"); 
	    throw Exception(EXLOC, msg);
	}

	int len; 
	if ( fv2.getValue() != 0 )
	    memcpy(&len, fv2.getValue(), sizeof(int));
	// len = *((int*)fv2.getValue());
	
	Chain left;
	if ( len < fv1.valAsChain().length() )
	    left = fv1.valAsChain().subChain(1, len);
	else
	    left = fv1.valAsChain();
	
	CegoFieldValue fv(VARCHAR_TYPE, left);
	return fv;;
    }
    case CegoFunction::GETPOS:
    {    

	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	CegoExpr** pExpr3 = _exprList.Next();
	CegoExpr** pExpr4 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	int start = 0;
	int occ = 1;
	
	fv1 = (*pExpr1)->evalFieldValue();
	fv2 = (*pExpr2)->evalFieldValue();

	if ( pExpr3 )
	{
	    CegoFieldValue fv = (*pExpr3)->evalFieldValue();
	    start = fv.valAsChain().asInteger();    
	}
	if ( pExpr4 )
	{
	    CegoFieldValue fv = (*pExpr4)->evalFieldValue();
	    occ = fv.valAsChain().asInteger();    
	}

	Chain s = fv1.valAsChain();
			
	int pos;
	if ( s.posStr(fv2.valAsChain(), pos, start, occ) )
	{		
	    CegoFieldValue fv(INT_TYPE, pos);
	    return fv;
	}
	
	CegoFieldValue nullField;	
	return nullField;
    }
    case CegoFunction::SUBSTR:
    {	   

	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	CegoExpr** pExpr3 = _exprList.Next();
	
	CegoFieldValue fv1, fv2, fv3;
	
	fv1 = (*pExpr1)->evalFieldValue();
	fv2 = (*pExpr2)->evalFieldValue();
	
	Chain s = fv1.valAsChain();
	int start = fv2.valAsChain().asInteger();
		
	int len=0;
	
	if ( pExpr3 )
	{
	    fv3 = (*pExpr3)->evalFieldValue();
	    len=fv3.valAsChain().asInteger();
	}
	
	Chain sub;
	if ( len > 0 )
	{
	    sub = s.subChain(start, start+len-1);
	}
	else
	{
	    sub = s.subChain(start, s.length());
	}
	
	CegoFieldValue fv(VARCHAR_TYPE, sub);
	return fv;
    }
    case CegoFunction::REPLACE:
    {    

	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	CegoExpr** pExpr3 = _exprList.Next();
	
	CegoFieldValue fv1, fv2, fv3;
	
	fv1 = (*pExpr1)->evalFieldValue();
	fv2 = (*pExpr2)->evalFieldValue();
	fv3 = (*pExpr3)->evalFieldValue();
	
	Chain src = fv1.valAsChain();
	Chain search = fv2.valAsChain();
	Chain replace = fv3.valAsChain();
	
	Chain res;
	src.replaceAll(search, replace, res);
	
	CegoFieldValue fv(VARCHAR_TYPE, res);
	return fv;	

    }
    case CegoFunction::LENGTH:
    {    
	
	CegoExpr** pExpr1 = _exprList.First();

	CegoFieldValue fv1;
	fv1 = (*pExpr1)->evalFieldValue();

	Chain s = fv1.valAsChain();
	
	CegoFieldValue fv(INT_TYPE, s.length() - 1);
	return fv;
    }
    case CegoFunction::TRIM:
    {
	
	CegoExpr** pExpr1 = _exprList.First();

	CegoFieldValue fv1;
	fv1 = (*pExpr1)->evalFieldValue();
	
	CegoExpr** pExpr2 = _exprList.Next();

	CegoFieldValue fv2;
	fv2 = (*pExpr2)->evalFieldValue();
	
	Chain s = fv1.valAsChain();
		
	Chain t = s.cutTrailing(fv2.valAsChain());
				    
	CegoFieldValue fv(VARCHAR_TYPE, t);
	return fv;
    }
    case CegoFunction::RTRIM:
    {
	
	CegoExpr** pExpr1 = _exprList.First();

	CegoFieldValue fv1;
	fv1 = (*pExpr1)->evalFieldValue();
	
	CegoExpr** pExpr2 = _exprList.Next();

	CegoFieldValue fv2;
	fv2 = (*pExpr2)->evalFieldValue();
	
	Chain s = fv1.valAsChain();
		
	Chain t = s.truncRight(fv2.valAsChain());
				    
	CegoFieldValue fv(VARCHAR_TYPE, t);
	return fv;
    }
    case CegoFunction::LTRIM:
    {
	
	CegoExpr** pExpr1 = _exprList.First();

	CegoFieldValue fv1;
	fv1 = (*pExpr1)->evalFieldValue();
	
	CegoExpr** pExpr2 = _exprList.Next();

	CegoFieldValue fv2;
	fv2 = (*pExpr2)->evalFieldValue();
	
	Chain s = fv1.valAsChain();
		
	Chain t = s.truncLeft(fv2.valAsChain());
				    
	CegoFieldValue fv(VARCHAR_TYPE, t);
	return fv;
    }
    case CegoFunction::STR2INT:
    {
	
	CegoExpr** pExpr = _exprList.First();
	
	CegoFieldValue fv;

	fv = (*pExpr)->evalFieldValue();
	
	CegoFieldValue retVal(INT_TYPE, fv.valAsChain());
	return retVal;
    }
    case CegoFunction::STR2LONG:
    {
	
	CegoExpr** pExpr = _exprList.First();
	
	CegoFieldValue fv;

	fv = (*pExpr)->evalFieldValue();
	
	CegoFieldValue retVal(LONG_TYPE, fv.valAsChain());
	return retVal;
    }
    case CegoFunction::RANDSTR:
    {
	
	CegoExpr** pExpr = _exprList.First();
	
	CegoFieldValue fv;

	fv = (*pExpr)->evalFieldValue();

	int l = rand() % fv.valAsChain().asInteger();
	if ( l == 0 )
	    l = fv.valAsChain().asInteger();
	
	Chain rs;
	for ( int j=0; j<l; j++ ) 
	{ 
	    rs += Chain((char)(65 + (rand()%26))); 
	}
	
	CegoFieldValue retVal(VARCHAR_TYPE, rs);
	return retVal;
    }
    case CegoFunction::RANDINT:
    {
	
	CegoExpr** pExpr = _exprList.First();
	
	CegoFieldValue fv;

	fv = (*pExpr)->evalFieldValue();
	
	int l = fv.valAsChain().asInteger();

	CegoFieldValue retVal(INT_TYPE, rand() % l);  
	return retVal;
    }
    case CegoFunction::MOD:
    {
	
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue();
	fv2 = (*pExpr2)->evalFieldValue();
	
	if ( fv1.getType() != INT_TYPE || fv2.getType() != INT_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function mod"); 
	    throw Exception(EXLOC, msg);
	}
	
	int op1;
	if ( fv1.getValue() != 0 )
	    memcpy(&op1, fv1.getValue(), sizeof(int));
	
	int op2;
	if ( fv2.getValue() != 0 )
	    memcpy(&op2, fv2.getValue(), sizeof(int));
	
	int modval = op1 % op2;
	
	CegoFieldValue fv(INT_TYPE, modval);
	return fv;
    }
    case CegoFunction::DIV:
    {
	
	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue();
	fv2 = (*pExpr2)->evalFieldValue();
	
	if ( fv1.getType() != INT_TYPE || fv2.getType() != INT_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function mod"); 
	    throw Exception(EXLOC, msg);
	}

	int op1;
	if ( fv1.getValue() != 0 )
	    memcpy(&op1, fv1.getValue(), sizeof(int));
	
	int op2;
	if ( fv2.getValue() != 0 )
	    memcpy(&op2, fv2.getValue(), sizeof(int));

	if ( op1 == 0 )
	    throw Exception(EXLOC, "Division by zero");
	
	int divval = op1 / op2;
	
	CegoFieldValue fv(INT_TYPE, divval);
	return fv;
	
    }
    case CegoFunction::POWER:
    {

	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue();
	fv2 = (*pExpr2)->evalFieldValue();

	if ( fv1.getType() != INT_TYPE || fv2.getType() != INT_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function power"); 
	    throw Exception(EXLOC, msg);
	}
	
	int op1;
	if ( fv1.getValue() != 0 )
	    memcpy(&op1, fv1.getValue(), sizeof(int));
	
	int op2;
	if ( fv2.getValue() != 0 )
	    memcpy(&op2, fv2.getValue(), sizeof(int));
	
	int i,p;
	p = 1;
	for (i = 1; i <= op2; ++i)
	    p *= op1;
	
	CegoFieldValue fv(INT_TYPE, p);
	return fv;
	
    }
    case CegoFunction::BITAND:
    {

	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue();
	fv2 = (*pExpr2)->evalFieldValue();

	if ( fv1.getType() != INT_TYPE || fv2.getType() != INT_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function power"); 
	    throw Exception(EXLOC, msg);
	}
	
	int op1;
	if ( fv1.getValue() != 0 )
	    memcpy(&op1, fv1.getValue(), sizeof(int));
	
	int op2;
	if ( fv2.getValue() != 0 )
	    memcpy(&op2, fv2.getValue(), sizeof(int));
	
	int a = op1 & op2;

	CegoFieldValue fv(INT_TYPE, a);
	return fv;
	
    }
    case CegoFunction::BITOR:
    {

	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue();
	fv2 = (*pExpr2)->evalFieldValue();

	if ( fv1.getType() != INT_TYPE || fv2.getType() != INT_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function power"); 
	    throw Exception(EXLOC, msg);
	}
	
	int op1;
	if ( fv1.getValue() != 0 )
	    memcpy(&op1, fv1.getValue(), sizeof(int));
	
	int op2;
	if ( fv2.getValue() != 0 )
	    memcpy(&op2, fv2.getValue(), sizeof(int));
	
	int o = op1 | op2;

	CegoFieldValue fv(INT_TYPE, o);
	return fv;
	
    }
    case CegoFunction::BITXOR:
    {

	CegoExpr** pExpr1 = _exprList.First();
	CegoExpr** pExpr2 = _exprList.Next();
	
	CegoFieldValue fv1, fv2;
	
	fv1 = (*pExpr1)->evalFieldValue();
	fv2 = (*pExpr2)->evalFieldValue();

	if ( fv1.getType() != INT_TYPE || fv2.getType() != INT_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function power"); 
	    throw Exception(EXLOC, msg);
	}
	
	int op1;
	if ( fv1.getValue() != 0 )
	    memcpy(&op1, fv1.getValue(), sizeof(int));
	
	int op2;
	if ( fv2.getValue() != 0 )
	    memcpy(&op2, fv2.getValue(), sizeof(int));
	
	int xo = op1 ^ op2;

	CegoFieldValue fv(INT_TYPE, xo);
	return fv;
	
    }
    case CegoFunction::NEXTCOUNT:
    {       		
	long v = _pTabMng->getDBMng()->getCounterValue(_tabSetId, _counterId, 1);
	CegoFieldValue retVal(LONG_TYPE, Chain(v));
	return retVal;
    }
    case CegoFunction::SETCOUNT:
    {
	CegoFieldValue fv;
	CegoExpr** pCounterExpr = _exprList.First();		
	fv = (*pCounterExpr)->evalFieldValue();	
	fv.castTo(LONG_TYPE);

	if ( fv.getType() != LONG_TYPE )
	{
	    Chain msg = Chain("Invalid datatype in function setcount"); 
	    throw Exception(EXLOC, msg);
	}

	long l = fv.valAsChain().asLong();

	long v = _pTabMng->getDBMng()->getCounterValue(_tabSetId, _counterId, 0);

	_pTabMng->getDBMng()->setCounterValue(_tabSetId, _counterId, l);

	CegoFieldValue retVal(LONG_TYPE, Chain(v));
	return retVal;

    }
    case CegoFunction::USERDEFINED:
    {

	CegoFieldValue retVal;
		
	try 
	{

	    _pTabMng->getDBMng()->useObject(_tabSetId, _funcName, CegoObject::PROCEDURE, CegoDatabaseManager::SHARED, _pTabMng->getThreadId());    

	    CegoProcedure* pProc = _pTabMng->getProcedure(_tabSetId, _funcName);
	    
	    pProc->setMasterBlock(_pBlock);
	    
	    ListT<CegoProcVar> argList;
	    pProc->getArgList(argList);
	    
	    CegoProcVar *pVar = argList.First();
	    CegoExpr **pExpr = _exprList.First();
	    while ( pVar && pExpr ) 
	    {
		
		(*pExpr)->setBlock(_pBlock);
		
		if ( pVar->getVarType() == CegoProcVar::OUTVAR )
		{
		    Chain outVar;
		    (*pExpr)->checkVar(outVar);
		    
		    CegoProcVar *pCheckVar = _pBlock->getVarList().Find(CegoProcVar(outVar));
		    if ( pCheckVar == 0 )
		    {
			CegoFieldValue nullVal;
			_pBlock->getVarList().Insert(CegoProcVar(outVar, CegoProcVar::BLOCKVAR, NULL_TYPE, 0, nullVal));
		    }	       
		}
		pExpr = _exprList.Next();
		pVar = argList.Next();
	    }
	    
	    
	    pProc->execute(_exprList);
	    
	    retVal = pProc->getRetVal();
	    
	}
	catch ( Exception e )
	{
	    _pTabMng->getDBMng()->unuseObject(_tabSetId, _funcName, CegoObject::PROCEDURE, CegoDatabaseManager::SHARED);    	    
	    throw e;
	}

	_pTabMng->getDBMng()->unuseObject(_tabSetId, _funcName, CegoObject::PROCEDURE, CegoDatabaseManager::SHARED);    	    
	return retVal;
	
    }
    }
}

CegoFunction* CegoFunction::clone(bool isAttrRef)
{

    if ( _exprList.isEmpty() )
	return ( new CegoFunction(_type ) );

    ListT<CegoExpr*> cloneList;
    
    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	cloneList.Insert( (*pExpr)->clone(isAttrRef));	    
	pExpr = _exprList.Next();
    }
    
    return ( new CegoFunction(_type, cloneList) );
}

Chain CegoFunction::toChain(const Chain& indent) const
{
    Chain argString;


    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	argString += (*pExpr)->toChain();	    
	pExpr = _exprList.Next();
	if ( pExpr )
	    argString += Chain(",") + indent;
    }

    Chain funcString;

    switch (_type)
    {

    case CegoFunction::TRIM:
    {
	funcString = Chain("trim");
	break;	
    }
    case CegoFunction::RTRIM:
    {
	funcString = Chain("rtrim");
	break;	
    }
    case CegoFunction::LTRIM:
    {
	funcString = Chain("ltrim");
	break;	
    }
    case CegoFunction::ROUND:
    {
	funcString = Chain("round");
	break;	
    }
    case CegoFunction::TRUNC:
    {
	funcString = Chain("trunc");
	break;	
    }
    case CegoFunction::DATE2STR:
    {
	funcString = Chain("date2str");
	break;	
    }
    case CegoFunction::DATE2INT:
    {
	funcString = Chain("date2int");
	break;	
    }
    case CegoFunction::INT2DATE:
    {
	funcString = Chain("int2date");
	break;	
    }
    case CegoFunction::LOWER:
    {
	funcString = Chain("lower");
	break;	
    }
    case CegoFunction::UPPER:
    {
	funcString = Chain("upper");
	break;	
    }
    case CegoFunction::LEFT:
    {
	funcString = Chain("left");
	break;	
    }
    case CegoFunction::RIGHT:
    {
	funcString = Chain("right");
	break;	
    }
    case CegoFunction::SUBSTR:
    {
	funcString = Chain("substr");
	break;	
    }
    case CegoFunction::GETPOS:
    {
	funcString = Chain("getpos");
	break;		
    }
    case CegoFunction::STR2INT:
    {
	funcString = Chain("str2int");
	break;		
    }
    case CegoFunction::STR2LONG:
    {
	funcString = Chain("str2long");
	break;		
    }
    case CegoFunction::RANDSTR:
    {
	funcString = Chain("randstr");
	break;		
    }
    case CegoFunction::RANDINT:
    {
	funcString = Chain("randint");
	break;		
    }
    case CegoFunction::MOD:
    {
	funcString = Chain("mod");
	break;		
    }
    case CegoFunction::DIV:
    {
	funcString = Chain("div");
	break;		
    }
    case CegoFunction::POWER:
    {
	funcString = Chain("power");
	break;		
    }
    case CegoFunction::BITAND:
    {
	funcString = Chain("bitand");
	break;		
    }
    case CegoFunction::BITOR:
    {
	funcString = Chain("bitor");
	break;		
    }
    case CegoFunction::BITXOR:
    {
	funcString = Chain("bitxor");
	break;		
    }
    case CegoFunction::REPLACE:
    {
	funcString = Chain("replace");
	break;	
    }
    case CegoFunction::LENGTH:
    {
	funcString = Chain("length");
	break;	
    }
    case CegoFunction::NEXTCOUNT:
    {
	funcString = Chain("nextcount");
	argString = _counterId;
	break;	
    }
    case CegoFunction::SETCOUNT:
    {
	funcString = Chain("setcount");
	argString = _counterId + Chain(",") + argString;
	break;	
    }
    case CegoFunction::USERDEFINED:
    {
	funcString = _funcName;
	break;	
    }
    }

    Chain s = indent + funcString + Chain("(") + argString + Chain(")");

    return s;
    
}

Element* CegoFunction::toElement() const
{
    Element* pFunctionElement = new Element(XML_FUNCTION_ELEMENT);

    switch (_type)
    {
    case CegoFunction::TRIM:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_TRIMFUNC_VALUE );
	break;	
    }
    case CegoFunction::RTRIM:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_RTRIMFUNC_VALUE );
	break;	
    }
    case CegoFunction::LTRIM:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_LTRIMFUNC_VALUE );
	break;	
    }
    case CegoFunction::ROUND:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_ROUNDFUNC_VALUE );
	break;	
    }
    case CegoFunction::TRUNC:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_TRUNCFUNC_VALUE);
	break;
    }
    case CegoFunction::DATE2STR:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_DATE2STRFUNC_VALUE);
	break;
    }
    case CegoFunction::DATE2INT:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_DATE2INTFUNC_VALUE);
	break;
    }
    case CegoFunction::INT2DATE:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_INT2DATEFUNC_VALUE);
	break;
    }
    case CegoFunction::LOWER:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_LOWERFUNC_VALUE);
	break;
    }
    case CegoFunction::UPPER:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_UPPERFUNC_VALUE);
	break;
    }
    case CegoFunction::LEFT:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_LEFTFUNC_VALUE);
	break;
    }
    case CegoFunction::RIGHT:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_RIGHTFUNC_VALUE);
	break;
    }
    case CegoFunction::SUBSTR:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_SUBSTRFUNC_VALUE);
	break;
    }
    case CegoFunction::GETPOS:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_GETPOSFUNC_VALUE);
	break;
    }
    case CegoFunction::STR2INT:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_STR2INTFUNC_VALUE);
	break;
    }
    case CegoFunction::STR2LONG:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_STR2LONGFUNC_VALUE);
	break;
    }
    case CegoFunction::RANDSTR:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_RANDSTRFUNC_VALUE);
	break;
    }
    case CegoFunction::RANDINT:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_RANDINTFUNC_VALUE);
	break;
    }
    case CegoFunction::REPLACE:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_REPLACEFUNC_VALUE);
	break;
    }
    case CegoFunction::MOD:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_MODFUNC_VALUE);
	break;
    }
    case CegoFunction::DIV:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_DIVFUNC_VALUE);
	break;
    }
    case CegoFunction::POWER:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_POWERFUNC_VALUE);
	break;
    }
    case CegoFunction::BITAND:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_BITANDFUNC_VALUE);
	break;
    }
    case CegoFunction::BITOR:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_BITORFUNC_VALUE);
	break;
    }
    case CegoFunction::BITXOR:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_BITXORFUNC_VALUE);
	break;
    }
    case CegoFunction::LENGTH:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_LENGTHFUNC_VALUE);
	break;
    }
    case CegoFunction::NEXTCOUNT:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_NEXTCOUNTFUNC_VALUE);
	break;
    }
    case CegoFunction::SETCOUNT:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_SETCOUNTFUNC_VALUE);
	break;
    }
    case CegoFunction::USERDEFINED:
    {
	pFunctionElement->setAttribute( XML_FUNCTYPE_ATTR, XML_USERDEFINEDFUNC_VALUE);
	break;
    }
    }

    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	pFunctionElement->addContent((*pExpr)->toElement());	    
	pExpr = _exprList.Next();
    }

    return pFunctionElement;
}

void CegoFunction::fromElement(Element *pFunctionElement, CegoDistManager *pGTM)
{

    Chain functionTypeString = pFunctionElement->getAttributeValue( XML_FUNCTYPE_ATTR );

    if ( functionTypeString == Chain(XML_TRIMFUNC_VALUE) )
    {
	_type = CegoFunction::TRIM;
    }
    else if ( functionTypeString == Chain(XML_RTRIMFUNC_VALUE) )
    {
	_type = CegoFunction::RTRIM;
    }
    else if ( functionTypeString == Chain(XML_LTRIMFUNC_VALUE) )
    {
	_type = CegoFunction::LTRIM;
    }
    else if ( functionTypeString == Chain(XML_ROUNDFUNC_VALUE) )
    {
	_type = CegoFunction::ROUND;
    }
    else if ( functionTypeString == Chain(XML_TRUNCFUNC_VALUE) )
    {
	_type = CegoFunction::TRUNC;
    }
    else if ( functionTypeString == Chain(XML_DATE2STRFUNC_VALUE) )
    {
	_type = CegoFunction::DATE2STR;
    }
    else if ( functionTypeString == Chain(XML_DATE2INTFUNC_VALUE) )
    {
	_type = CegoFunction::DATE2INT;
    }
    else if ( functionTypeString == Chain(XML_INT2DATEFUNC_VALUE) )
    {
	_type = CegoFunction::INT2DATE;
    }
    else if ( functionTypeString == Chain(XML_LOWERFUNC_VALUE) )
    {
	_type = CegoFunction::LOWER;
    }
    else if ( functionTypeString == Chain(XML_UPPERFUNC_VALUE) )
    {
	_type = CegoFunction::UPPER;
    }
    else if ( functionTypeString == Chain(XML_LEFTFUNC_VALUE) )
    {
	_type = CegoFunction::LEFT;
    }
    else if ( functionTypeString == Chain(XML_RIGHTFUNC_VALUE) )
    {
	_type = CegoFunction::RIGHT;
    }
    else if ( functionTypeString == Chain(XML_SUBSTRFUNC_VALUE) )
    {
	_type = CegoFunction::SUBSTR;
    }
    else if ( functionTypeString == Chain(XML_GETPOSFUNC_VALUE) )
    {
	_type = CegoFunction::GETPOS;
    }
    else if ( functionTypeString == Chain(XML_STR2INTFUNC_VALUE) )
    {
	_type = CegoFunction::STR2INT;
    }
    else if ( functionTypeString == Chain(XML_STR2LONGFUNC_VALUE) )
    {
	_type = CegoFunction::STR2LONG;
    }
    else if ( functionTypeString == Chain(XML_RANDSTRFUNC_VALUE) )
    {
	_type = CegoFunction::RANDSTR;
    }
    else if ( functionTypeString == Chain(XML_RANDINTFUNC_VALUE) )
    {
	_type = CegoFunction::RANDINT;
    }
    else if ( functionTypeString == Chain(XML_REPLACEFUNC_VALUE) )
    {
	_type = CegoFunction::REPLACE;
    }
    else if ( functionTypeString == Chain(XML_MODFUNC_VALUE) )
    {
	_type = CegoFunction::MOD;
    }
    else if ( functionTypeString == Chain(XML_DIVFUNC_VALUE) )
    {
	_type = CegoFunction::DIV;
    }
    else if ( functionTypeString == Chain(XML_POWERFUNC_VALUE) )
    {
	_type = CegoFunction::POWER;
    }
    else if ( functionTypeString == Chain(XML_BITANDFUNC_VALUE) )
    {
	_type = CegoFunction::BITAND;
    }
    else if ( functionTypeString == Chain(XML_BITORFUNC_VALUE) )
    {
	_type = CegoFunction::BITOR;
    }
    else if ( functionTypeString == Chain(XML_BITXORFUNC_VALUE) )
    {
	_type = CegoFunction::BITXOR;
    }
    else if ( functionTypeString == Chain(XML_LENGTHFUNC_VALUE) )
    {
	_type = CegoFunction::LENGTH;
    }
    else if ( functionTypeString == Chain(XML_NEXTCOUNTFUNC_VALUE) )
    {
	_type = CegoFunction::NEXTCOUNT;
    }
    else if ( functionTypeString == Chain(XML_SETCOUNTFUNC_VALUE) )
    {
	_type = CegoFunction::SETCOUNT;
    }
    else if ( functionTypeString == Chain(XML_USERDEFINEDFUNC_VALUE) )
    {
	_type = CegoFunction::USERDEFINED;
    }
    
    ListT<Element*> el = pFunctionElement->getChildren(XML_EXPR_ELEMENT);
    Element **pEE = el.First();
    while ( pEE )
    {
	CegoExpr *pExpr = new CegoExpr(*pEE, pGTM);
	_exprList.Insert (pExpr);
	pEE = el.Next();
    }
}

void CegoFunction::encode(char *buf)
{
    char* pE = (char*)buf;

    memcpy( pE, &_type, sizeof(CegoFunction::FunctionType));
    pE = pE + sizeof(CegoFunction::FunctionType);

    int numExpr = _exprList.Size();

    memcpy( pE, &numExpr, sizeof(int));
    pE = pE + sizeof(int);
        
    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	(*pExpr)->encode(pE);
	pE = pE + (*pExpr)->getEncodingLength();
	pExpr = _exprList.Next();
    }
    

}

void CegoFunction::decode(char *buf, CegoDistManager* pGTM)
{
    char* pE = (char*)buf;

    memcpy( &_type, pE, sizeof(CegoFunction::FunctionType));
    pE = pE + sizeof(CegoFunction::FunctionType);

    int numExpr;
    memcpy( &numExpr, pE, sizeof(int));
    pE = pE + sizeof(int);

    int i=0;
    while ( i < numExpr )
    {
	CegoExpr *pExpr = new CegoExpr(pE, pGTM);
	pE = pE + pExpr->getEncodingLength();
	_exprList.Insert(pExpr);
	i++;
    } 
    
}

int CegoFunction::getEncodingLength() const
{

    int len = 0;
    
    len += sizeof(CegoFunction::FunctionType);
    len += sizeof(int); // numExpr
    
    CegoExpr** pExpr = _exprList.First();
    while ( pExpr )
    {
	len += (*pExpr)->getEncodingLength();
	pExpr = _exprList.Next();
    }

    return len;
}

CegoFunction& CegoFunction::operator = ( const CegoFunction& f)
{
    _type = f._type;
    _exprList = f._exprList;
    _tabSetId = f._tabSetId;
    return (*this);
}

ostream& operator << (ostream& s, const CegoFunction& f)
{
    s << f.toChain();
    return s;
}


