/******************************************************************************
 * $Id: ods_formula_node.cpp 27741 2014-09-26 19:20:02Z goatbar $
 *
 * Component: ODS formula Engine
 * Purpose: Implementation of the ods_formula_node class used to represent a
 *          node in a ODS expression.
 * Author: Even Rouault <even dot rouault at mines dash paris dot org>
 * 
 ******************************************************************************
 * Copyright (C) 2010 Frank Warmerdam <warmerdam@pobox.com>
 * Copyright (c) 2012-2013, Even Rouault <even dot rouault at mines-paris dot org>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 ****************************************************************************/

#include "cpl_conv.h"
#include "ods_formula.h"

#ifndef PI
#define PI  3.14159265358979323846
#endif

/************************************************************************/
/*                          ods_formula_node()                          */
/************************************************************************/

ods_formula_node::ods_formula_node()

{
    Initialize();
}

/************************************************************************/
/*                         ods_formula_node(int)                        */
/************************************************************************/

ods_formula_node::ods_formula_node( int nValueIn )

{
    Initialize();

    field_type = ODS_FIELD_TYPE_INTEGER;
    int_value = nValueIn;
}

/************************************************************************/
/*                      ods_formula_node(double)                        */
/************************************************************************/

ods_formula_node::ods_formula_node( double dfValueIn )

{
    Initialize();

    field_type = ODS_FIELD_TYPE_FLOAT;
    float_value = dfValueIn;
}

/************************************************************************/
/*                       ods_formula_node(const char*)                  */
/************************************************************************/

ods_formula_node::ods_formula_node( const char *pszValueIn,
                                    ods_formula_field_type field_type_in )

{
    Initialize();

    field_type = field_type_in;
    string_value = CPLStrdup( pszValueIn ? pszValueIn : "" );
}

/************************************************************************/
/*                        ods_formula_node(ods_formula_op)              */
/************************************************************************/

ods_formula_node::ods_formula_node( ods_formula_op eOpIn )

{
    Initialize();

    eNodeType = SNT_OPERATION;

    eOp = eOpIn;
}

/************************************************************************/
/*              ods_formula_node(const ods_formula_node&)               */
/************************************************************************/

ods_formula_node::ods_formula_node( const ods_formula_node& other )
{
    eNodeType = other.eNodeType;
    eOp = other.eOp;
    field_type = other.field_type;
    int_value = other.int_value;
    float_value = other.float_value;
    string_value = other.string_value ? CPLStrdup(other.string_value) : NULL;
    nSubExprCount = other.nSubExprCount;
    if (nSubExprCount)
    {
        papoSubExpr = (ods_formula_node **)
            CPLMalloc( sizeof(void*) * nSubExprCount );
        for(int i=0;i<nSubExprCount;i++)
        {
            papoSubExpr[i] = new ods_formula_node( *(other.papoSubExpr[i]) );
        }
    }
    else
        papoSubExpr = NULL;
}

/************************************************************************/
/*                             Initialize()                             */
/************************************************************************/

void ods_formula_node::Initialize()

{
    eNodeType = SNT_CONSTANT;
    field_type = ODS_FIELD_TYPE_EMPTY;
    int_value = 0;
    float_value = 0;
    string_value = NULL;
    papoSubExpr = NULL;
    nSubExprCount = 0;
}

/************************************************************************/
/*                          ~ods_formula_node()                         */
/************************************************************************/

ods_formula_node::~ods_formula_node()

{
    CPLFree( string_value );
    FreeSubExpr();
}

/************************************************************************/
/*                         PushSubExpression()                          */
/************************************************************************/

void ods_formula_node::PushSubExpression( ods_formula_node *child )

{
    nSubExprCount++;
    papoSubExpr = (ods_formula_node **)
        CPLRealloc( papoSubExpr, sizeof(void*) * nSubExprCount );

    papoSubExpr[nSubExprCount-1] = child;
}

/************************************************************************/
/*                       ReverseSubExpressions()                        */
/************************************************************************/

void ods_formula_node::ReverseSubExpressions()

{
    int i;
    for( i = 0; i < nSubExprCount / 2; i++ )
    {
        ods_formula_node *temp;

        temp = papoSubExpr[i];
        papoSubExpr[i] = papoSubExpr[nSubExprCount - i - 1];
        papoSubExpr[nSubExprCount - i - 1] = temp;
    }
}

/************************************************************************/
/*                        GetOperatorName()                             */
/************************************************************************/

static const char* ODSGetOperatorName( ods_formula_op eOp )
{
    switch (eOp)
    {
        case ODS_OR : return "OR";
        case ODS_AND : return "AND";
        case ODS_NOT : return "NOT";
        case ODS_IF : return "IF";

        case ODS_PI : return "PI";

        //case ODS_T : return "T";
        case ODS_LEN : return "LEN";
        case ODS_LEFT : return "LEFT";
        case ODS_RIGHT : return "RIGHT";
        case ODS_MID : return "MID";

        case ODS_SUM : return "SUM";
        case ODS_AVERAGE : return "AVERAGE";
        case ODS_MIN : return "MIN";
        case ODS_MAX : return "MAX";
        case ODS_COUNT : return "COUNT";
        case ODS_COUNTA : return "COUNTA";

        case ODS_EQ : return "=";
        case ODS_NE : return "<>";
        case ODS_GE : return ">=";
        case ODS_LE : return "<=";
        case ODS_LT : return "<";
        case ODS_GT : return ">";

        case ODS_ADD : return "+";
        case ODS_SUBTRACT : return "-";
        case ODS_MULTIPLY : return "*";
        case ODS_DIVIDE : return "/";
        case ODS_MODULUS : return "MOD";
        case ODS_CONCAT : return "&";

        case ODS_LIST : return "*list*";
        case ODS_CELL : return "*cell*";
        case ODS_CELL_RANGE : return "*cell_range*";
        default:
        {
            const SingleOpStruct* psSingleOp = ODSGetSingleOpEntry(eOp);
            if (psSingleOp != NULL)
                return psSingleOp->pszName;
            return "*unknown*";
        }
    }
}

/************************************************************************/
/*                                Dump()                                */
/************************************************************************/

void ods_formula_node::Dump( FILE * fp, int depth )

{
    char        spaces[60];
    int         i;

    for( i = 0; i < depth*2 && i < (int) sizeof(spaces) - 1; i++ )
        spaces[i] = ' ';
    spaces[i] = '\0';

    if( eNodeType == SNT_CONSTANT )
    {
        if( field_type == ODS_FIELD_TYPE_INTEGER )
            fprintf( fp, "%s  %d\n", spaces, int_value );
        else if( field_type == ODS_FIELD_TYPE_FLOAT )
            fprintf( fp, "%s  %.15g\n", spaces, float_value );
        else
            fprintf( fp, "%s  \"%s\"\n", spaces, string_value );
        return;
    }

    CPLAssert( eNodeType == SNT_OPERATION );

    fprintf( fp, "%s%s\n", spaces, ODSGetOperatorName(eOp) );

    for( i = 0; i < nSubExprCount; i++ )
        papoSubExpr[i]->Dump( fp, depth+1 );
}

/************************************************************************/
/*                             FreeSubExpr()                            */
/************************************************************************/

void  ods_formula_node::FreeSubExpr()
{
    int i;
    for( i = 0; i < nSubExprCount; i++ )
        delete papoSubExpr[i];
    CPLFree( papoSubExpr );

    nSubExprCount = 0;
    papoSubExpr = NULL;
}

/************************************************************************/
/*                              Evaluate()                              */
/************************************************************************/

int ods_formula_node::Evaluate(IODSCellEvaluator* poEvaluator)
{
    if (eNodeType == SNT_CONSTANT)
        return TRUE;

    CPLAssert( eNodeType == SNT_OPERATION );

    switch (eOp)
    {
        case ODS_OR: return EvaluateOR(poEvaluator);
        case ODS_AND: return EvaluateAND(poEvaluator);
        case ODS_NOT: return EvaluateNOT(poEvaluator);
        case ODS_IF: return EvaluateIF(poEvaluator);

        case ODS_PI:
            eNodeType = SNT_CONSTANT;
            field_type = ODS_FIELD_TYPE_FLOAT;
            float_value = PI;
            return TRUE;

        case ODS_LEN : return EvaluateLEN(poEvaluator);
        case ODS_LEFT : return EvaluateLEFT(poEvaluator);
        case ODS_RIGHT : return EvaluateRIGHT(poEvaluator);
        case ODS_MID : return EvaluateMID(poEvaluator);

        case ODS_SUM:
        case ODS_AVERAGE:
        case ODS_MIN:
        case ODS_MAX:
        case ODS_COUNT:
        case ODS_COUNTA:
            return EvaluateListArgOp(poEvaluator);

        case ODS_ABS:
        case ODS_SQRT:
        case ODS_COS:
        case ODS_SIN:
        case ODS_TAN:
        case ODS_ACOS:
        case ODS_ASIN:
        case ODS_ATAN:
        case ODS_EXP:
        case ODS_LN:
        case ODS_LOG:
            return EvaluateSingleArgOp(poEvaluator);


        case ODS_EQ: return EvaluateEQ(poEvaluator);
        case ODS_NE: return EvaluateNE(poEvaluator);
        case ODS_LE: return EvaluateLE(poEvaluator);
        case ODS_GE: return EvaluateGE(poEvaluator);
        case ODS_LT: return EvaluateLT(poEvaluator);
        case ODS_GT: return EvaluateGT(poEvaluator);

        case ODS_ADD:
        case ODS_SUBTRACT:
        case ODS_MULTIPLY:
        case ODS_DIVIDE:
        case ODS_MODULUS:
            return EvaluateBinaryArithmetic(poEvaluator);

        case ODS_CONCAT: return EvaluateCONCAT(poEvaluator);

        case ODS_CELL: return EvaluateCELL(poEvaluator);

        default:
        {
            CPLError(CE_Failure, CPLE_AppDefined,
                     "Unhandled case in Evaluate() for %s",
                     ODSGetOperatorName(eOp));
            return FALSE;
        }
    }
}

/************************************************************************/
/*                             EvaluateOR()                             */
/************************************************************************/

int ods_formula_node::EvaluateOR(IODSCellEvaluator* poEvaluator)
{
    CPLAssert( eNodeType == SNT_OPERATION );
    CPLAssert( eOp == ODS_OR );

    CPLAssert(nSubExprCount == 1);
    CPLAssert(papoSubExpr[0]->eNodeType == SNT_OPERATION );
    CPLAssert(papoSubExpr[0]->eOp == ODS_LIST );
    int bVal = FALSE;
    for(int i = 0; i < papoSubExpr[0]->nSubExprCount; i++)
    {
        if (!(papoSubExpr[0]->papoSubExpr[i]->Evaluate(poEvaluator)))
            return FALSE;
        CPLAssert(papoSubExpr[0]->papoSubExpr[i]->eNodeType == SNT_CONSTANT );
        if (papoSubExpr[0]->papoSubExpr[i]->field_type == ODS_FIELD_TYPE_INTEGER)
        {
            bVal |= (papoSubExpr[0]->papoSubExpr[i]->int_value != 0);
        }
        else if (papoSubExpr[0]->papoSubExpr[i]->field_type == ODS_FIELD_TYPE_FLOAT)
        {
            bVal |= (papoSubExpr[0]->papoSubExpr[i]->float_value != 0);
        }
        else
        {
            CPLError(CE_Failure, CPLE_NotSupported,
                     "Bad argument type for %s", ODSGetOperatorName(eOp));
            return FALSE;
        }
    }

    FreeSubExpr();

    eNodeType = SNT_CONSTANT;
    field_type = ODS_FIELD_TYPE_INTEGER;
    int_value = bVal;

    return TRUE;
}

/************************************************************************/
/*                            EvaluateAND()                             */
/************************************************************************/

int ods_formula_node::EvaluateAND(IODSCellEvaluator* poEvaluator)
{
    CPLAssert( eNodeType == SNT_OPERATION );
    CPLAssert( eOp == ODS_AND );

    CPLAssert(nSubExprCount == 1);
    CPLAssert(papoSubExpr[0]->eNodeType == SNT_OPERATION );
    CPLAssert(papoSubExpr[0]->eOp == ODS_LIST );
    int bVal = TRUE;
    for(int i = 0; i < papoSubExpr[0]->nSubExprCount; i++)
    {
        if (!(papoSubExpr[0]->papoSubExpr[i]->Evaluate(poEvaluator)))
            return FALSE;
        CPLAssert(papoSubExpr[0]->papoSubExpr[i]->eNodeType == SNT_CONSTANT );
        if (papoSubExpr[0]->papoSubExpr[i]->field_type == ODS_FIELD_TYPE_INTEGER)
        {
            bVal &= (papoSubExpr[0]->papoSubExpr[i]->int_value != 0);
        }
        else if (papoSubExpr[0]->papoSubExpr[i]->field_type == ODS_FIELD_TYPE_FLOAT)
        {
            bVal &= (papoSubExpr[0]->papoSubExpr[i]->float_value != 0);
        }
        else
        {
            CPLError(CE_Failure, CPLE_NotSupported,
                     "Bad argument type for %s", ODSGetOperatorName(eOp));
            return FALSE;
        }
    }

    FreeSubExpr();

    eNodeType = SNT_CONSTANT;
    field_type = ODS_FIELD_TYPE_INTEGER;
    int_value = bVal;

    return TRUE;
}

/************************************************************************/
/*                            EvaluateNOT()                             */
/************************************************************************/

int ods_formula_node::EvaluateNOT(IODSCellEvaluator* poEvaluator)
{
    CPLAssert( eNodeType == SNT_OPERATION );
    CPLAssert( eOp == ODS_NOT );

    CPLAssert(nSubExprCount == 1);
    if (!(papoSubExpr[0]->Evaluate(poEvaluator)))
        return FALSE;
    CPLAssert(papoSubExpr[0]->eNodeType == SNT_CONSTANT );

    int bVal = FALSE;
    if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_INTEGER)
    {
        bVal = !(papoSubExpr[0]->int_value != 0);
    }
    else if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_FLOAT)
    {
        bVal = !(papoSubExpr[0]->float_value != 0);
    }
    else
    {
        CPLError(CE_Failure, CPLE_NotSupported,
                 "Bad argument type for %s", ODSGetOperatorName(eOp));
        return FALSE;
    }

    FreeSubExpr();

    eNodeType = SNT_CONSTANT;
    field_type = ODS_FIELD_TYPE_INTEGER;
    int_value = bVal;

    return TRUE;
}

/************************************************************************/
/*                            EvaluateIF()                              */
/************************************************************************/

int ods_formula_node::EvaluateIF(IODSCellEvaluator* poEvaluator)
{
    CPLAssert( eNodeType == SNT_OPERATION );
    CPLAssert( eOp == ODS_IF );

    CPLAssert(nSubExprCount == 2 || nSubExprCount == 3);
    if (!(papoSubExpr[0]->Evaluate(poEvaluator)))
        return FALSE;
    if (!(papoSubExpr[1]->Evaluate(poEvaluator)))
        return FALSE;
    if (nSubExprCount == 3 && !(papoSubExpr[2]->Evaluate(poEvaluator)))
        return FALSE;

    CPLAssert(papoSubExpr[0]->eNodeType == SNT_CONSTANT );
    CPLAssert(papoSubExpr[1]->eNodeType == SNT_CONSTANT );
    if (nSubExprCount == 3)
    {
        CPLAssert(papoSubExpr[2]->eNodeType == SNT_CONSTANT );
    }
    int bCond = FALSE;
    if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_INTEGER)
    {
        bCond = (papoSubExpr[0]->int_value != 0);
    }
    else if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_FLOAT)
    {
        bCond = (papoSubExpr[0]->float_value != 0);
    }
    else
    {
        CPLError(CE_Failure, CPLE_NotSupported,
                 "Bad argument type for %s", ODSGetOperatorName(eOp));
        return FALSE;
    }

    if (bCond)
    {
        eNodeType = SNT_CONSTANT;
        field_type = papoSubExpr[1]->field_type;
        if (field_type == ODS_FIELD_TYPE_INTEGER)
            int_value = papoSubExpr[1]->int_value;
        else if (field_type == ODS_FIELD_TYPE_FLOAT)
            float_value = papoSubExpr[1]->float_value;
        else if (field_type == ODS_FIELD_TYPE_STRING)
        {
            string_value = papoSubExpr[1]->string_value;
            papoSubExpr[1]->string_value = NULL;
        }
    }
    else if (nSubExprCount == 3)
    {
        eNodeType = SNT_CONSTANT;
        field_type = papoSubExpr[2]->field_type;
        if (field_type == ODS_FIELD_TYPE_INTEGER)
            int_value = papoSubExpr[2]->int_value;
        else if (field_type == ODS_FIELD_TYPE_FLOAT)
            float_value = papoSubExpr[2]->float_value;
        else if (field_type == ODS_FIELD_TYPE_STRING)
        {
            string_value = papoSubExpr[2]->string_value;
            papoSubExpr[2]->string_value = NULL;
        }
    }
    else
    {
        eNodeType = SNT_CONSTANT;
        field_type = ODS_FIELD_TYPE_INTEGER;
        int_value = FALSE;
    }

    FreeSubExpr();

    return TRUE;
}

/************************************************************************/
/*                            EvaluateEQ()                              */
/************************************************************************/

int ods_formula_node::EvaluateEQ(IODSCellEvaluator* poEvaluator)
{
    CPLAssert( eNodeType == SNT_OPERATION );
    CPLAssert( eOp == ODS_EQ );

    CPLAssert(nSubExprCount == 2);
    if (!(papoSubExpr[0]->Evaluate(poEvaluator)))
        return FALSE;
    if (!(papoSubExpr[1]->Evaluate(poEvaluator)))
        return FALSE;

    CPLAssert(papoSubExpr[0]->eNodeType == SNT_CONSTANT );
    CPLAssert(papoSubExpr[1]->eNodeType == SNT_CONSTANT );

    int bVal = FALSE;
    if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_INTEGER)
    {
        if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_INTEGER)
        {
            bVal = (papoSubExpr[0]->int_value == papoSubExpr[1]->int_value);
        }
        else if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_FLOAT)
        {
            bVal = (papoSubExpr[0]->int_value == papoSubExpr[1]->float_value);
        }
    }
    else if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_FLOAT)
    {
        if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_INTEGER)
        {
            bVal = (papoSubExpr[0]->float_value == papoSubExpr[1]->int_value);
        }
        else if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_FLOAT)
        {
            bVal = (papoSubExpr[0]->float_value == papoSubExpr[1]->float_value);
        }
    }
    else if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_STRING)
    {
        if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_STRING)
        {
            bVal = (strcmp(papoSubExpr[0]->string_value,
                           papoSubExpr[1]->string_value) == 0);
        }
    }
    else
    {
        CPLError(CE_Failure, CPLE_NotSupported,
                 "Bad argument type for %s", ODSGetOperatorName(eOp));
        return FALSE;
    }

    eNodeType = SNT_CONSTANT;
    field_type = ODS_FIELD_TYPE_INTEGER;
    int_value = bVal;

    FreeSubExpr();

    return TRUE;
}

/************************************************************************/
/*                           EvaluateNE()                               */
/************************************************************************/

int ods_formula_node::EvaluateNE(IODSCellEvaluator* poEvaluator)
{
    CPLAssert( eNodeType == SNT_OPERATION );
    CPLAssert( eOp == ODS_NE );

    eOp = ODS_EQ;
    if (!EvaluateEQ(poEvaluator))
        return FALSE;

    int_value = !int_value;
    return TRUE;
}

/************************************************************************/
/*                              GetCase()                               */
/************************************************************************/

typedef enum
{
    CASE_LOWER,
    CASE_UPPER,
    CASE_UNKNOWN,
} CaseType;

static CaseType GetCase(const char* pszStr)
{
    int bInit = TRUE;
    char ch;
    CaseType eCase = CASE_UNKNOWN;
    while((ch = *(pszStr++)) != '\0')
    {
        if (bInit)
        {
            if (ch >= 'a' && ch <= 'z')
                eCase = CASE_LOWER;
            else if (ch >= 'A' && ch <= 'Z')
                eCase = CASE_UPPER;
            else
                return CASE_UNKNOWN;
        }
        else if (ch >= 'a' && ch <= 'z' && eCase == CASE_LOWER)
            ;
        else if (ch >= 'A' && ch <= 'Z' && eCase == CASE_UPPER)
            ;
        else
            return CASE_UNKNOWN;
    }
    return eCase;
}

/************************************************************************/
/*                            EvaluateLE()                              */
/************************************************************************/

int ods_formula_node::EvaluateLE(IODSCellEvaluator* poEvaluator)
{
    CPLAssert( eNodeType == SNT_OPERATION );
    CPLAssert( eOp == ODS_LE );

    CPLAssert(nSubExprCount == 2);
    if (!(papoSubExpr[0]->Evaluate(poEvaluator)))
        return FALSE;
    if (!(papoSubExpr[1]->Evaluate(poEvaluator)))
        return FALSE;

    CPLAssert(papoSubExpr[0]->eNodeType == SNT_CONSTANT );
    CPLAssert(papoSubExpr[1]->eNodeType == SNT_CONSTANT );

    int bVal = FALSE;
    if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_INTEGER)
    {
        if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_INTEGER)
        {
            bVal = (papoSubExpr[0]->int_value <= papoSubExpr[1]->int_value);
        }
        else if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_FLOAT)
        {
            bVal = (papoSubExpr[0]->int_value <= papoSubExpr[1]->float_value);
        }
        else
            bVal = TRUE;
    }
    else if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_FLOAT)
    {
        if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_INTEGER)
        {
            bVal = (papoSubExpr[0]->float_value <= papoSubExpr[1]->int_value);
        }
        else if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_FLOAT)
        {
            bVal = (papoSubExpr[0]->float_value <= papoSubExpr[1]->float_value);
        }
        else
            bVal = TRUE;
    }
    else if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_STRING)
    {
        if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_STRING)
        {
            if (GetCase(papoSubExpr[0]->string_value) ==
                GetCase(papoSubExpr[1]->string_value))
                bVal = (strcmp(papoSubExpr[0]->string_value,
                               papoSubExpr[1]->string_value) <= 0);
            else
                bVal = (strcasecmp(papoSubExpr[0]->string_value,
                                   papoSubExpr[1]->string_value) <= 0);
        }
    }
    else
    {
        CPLError(CE_Failure, CPLE_NotSupported,
                 "Bad argument type for %s", ODSGetOperatorName(eOp));
        return FALSE;
    }

    eNodeType = SNT_CONSTANT;
    field_type = ODS_FIELD_TYPE_INTEGER;
    int_value = bVal;

    FreeSubExpr();

    return TRUE;
}

/************************************************************************/
/*                            EvaluateGE()                              */
/************************************************************************/

int ods_formula_node::EvaluateGE(IODSCellEvaluator* poEvaluator)
{
    CPLAssert( eNodeType == SNT_OPERATION );
    CPLAssert( eOp == ODS_GE );

    CPLAssert(nSubExprCount == 2);
    if (!(papoSubExpr[0]->Evaluate(poEvaluator)))
        return FALSE;
    if (!(papoSubExpr[1]->Evaluate(poEvaluator)))
        return FALSE;

    CPLAssert(papoSubExpr[0]->eNodeType == SNT_CONSTANT );
    CPLAssert(papoSubExpr[1]->eNodeType == SNT_CONSTANT );

    int bVal = FALSE;
    if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_INTEGER)
    {
        if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_INTEGER)
        {
            bVal = (papoSubExpr[0]->int_value >= papoSubExpr[1]->int_value);
        }
        else if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_FLOAT)
        {
            bVal = (papoSubExpr[0]->int_value >= papoSubExpr[1]->float_value);
        }
    }
    else if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_FLOAT)
    {
        if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_INTEGER)
        {
            bVal = (papoSubExpr[0]->float_value >= papoSubExpr[1]->int_value);
        }
        else if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_FLOAT)
        {
            bVal = (papoSubExpr[0]->float_value >= papoSubExpr[1]->float_value);
        }
    }
    else if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_STRING)
    {
        if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_STRING)
        {
            if (GetCase(papoSubExpr[0]->string_value) ==
                GetCase(papoSubExpr[1]->string_value))
                bVal = (strcmp(papoSubExpr[0]->string_value,
                               papoSubExpr[1]->string_value) >= 0);
            else
                bVal = (strcasecmp(papoSubExpr[0]->string_value,
                                   papoSubExpr[1]->string_value) >= 0);
        }
        else
            bVal = TRUE;
    }
    else
    {
        CPLError(CE_Failure, CPLE_NotSupported,
                 "Bad argument type for %s", ODSGetOperatorName(eOp));
        return FALSE;
    }

    eNodeType = SNT_CONSTANT;
    field_type = ODS_FIELD_TYPE_INTEGER;
    int_value = bVal;

    FreeSubExpr();

    return TRUE;
}

/************************************************************************/
/*                            EvaluateLT()                              */
/************************************************************************/

int ods_formula_node::EvaluateLT(IODSCellEvaluator* poEvaluator)
{
    CPLAssert( eNodeType == SNT_OPERATION );
    CPLAssert( eOp == ODS_LT );

    CPLAssert(nSubExprCount == 2);
    if (!(papoSubExpr[0]->Evaluate(poEvaluator)))
        return FALSE;
    if (!(papoSubExpr[1]->Evaluate(poEvaluator)))
        return FALSE;

    CPLAssert(papoSubExpr[0]->eNodeType == SNT_CONSTANT );
    CPLAssert(papoSubExpr[1]->eNodeType == SNT_CONSTANT );

    int bVal = FALSE;
    if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_INTEGER)
    {
        if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_INTEGER)
        {
            bVal = (papoSubExpr[0]->int_value < papoSubExpr[1]->int_value);
        }
        else if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_FLOAT)
        {
            bVal = (papoSubExpr[0]->int_value < papoSubExpr[1]->float_value);
        }
        else
            bVal = TRUE;
    }
    else if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_FLOAT)
    {
        if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_INTEGER)
        {
            bVal = (papoSubExpr[0]->float_value < papoSubExpr[1]->int_value);
        }
        else if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_FLOAT)
        {
            bVal = (papoSubExpr[0]->float_value < papoSubExpr[1]->float_value);
        }
        else
            bVal = TRUE;
    }
    else if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_STRING)
    {
        if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_STRING)
        {
            if (GetCase(papoSubExpr[0]->string_value) ==
                GetCase(papoSubExpr[1]->string_value))
                bVal = (strcmp(papoSubExpr[0]->string_value,
                               papoSubExpr[1]->string_value) < 0);
            else
                bVal = (strcasecmp(papoSubExpr[0]->string_value,
                                   papoSubExpr[1]->string_value) < 0);
        }
    }
    else
    {
        CPLError(CE_Failure, CPLE_NotSupported,
                 "Bad argument type for %s", ODSGetOperatorName(eOp));
        return FALSE;
    }

    eNodeType = SNT_CONSTANT;
    field_type = ODS_FIELD_TYPE_INTEGER;
    int_value = bVal;

    FreeSubExpr();

    return TRUE;
}

/************************************************************************/
/*                            EvaluateGT()                              */
/************************************************************************/

int ods_formula_node::EvaluateGT(IODSCellEvaluator* poEvaluator)
{
    CPLAssert( eNodeType == SNT_OPERATION );
    CPLAssert( eOp == ODS_GT );

    CPLAssert(nSubExprCount == 2);
    if (!(papoSubExpr[0]->Evaluate(poEvaluator)))
        return FALSE;
    if (!(papoSubExpr[1]->Evaluate(poEvaluator)))
        return FALSE;

    CPLAssert(papoSubExpr[0]->eNodeType == SNT_CONSTANT );
    CPLAssert(papoSubExpr[1]->eNodeType == SNT_CONSTANT );

    int bVal = FALSE;
    if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_INTEGER)
    {
        if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_INTEGER)
        {
            bVal = (papoSubExpr[0]->int_value > papoSubExpr[1]->int_value);
        }
        else if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_FLOAT)
        {
            bVal = (papoSubExpr[0]->int_value > papoSubExpr[1]->float_value);
        }
    }
    else if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_FLOAT)
    {
        if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_INTEGER)
        {
            bVal = (papoSubExpr[0]->float_value > papoSubExpr[1]->int_value);
        }
        else if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_FLOAT)
        {
            bVal = (papoSubExpr[0]->float_value > papoSubExpr[1]->float_value);
        }
    }
    else if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_STRING)
    {
        if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_STRING)
        {
            if (GetCase(papoSubExpr[0]->string_value) ==
                GetCase(papoSubExpr[1]->string_value))
                bVal = (strcmp(papoSubExpr[0]->string_value,
                               papoSubExpr[1]->string_value) > 0);
            else
                bVal = (strcasecmp(papoSubExpr[0]->string_value,
                                   papoSubExpr[1]->string_value) > 0);
        }
        else
            bVal = TRUE;
    }
    else
    {
        CPLError(CE_Failure, CPLE_NotSupported,
                 "Bad argument type for %s", ODSGetOperatorName(eOp));
        return FALSE;
    }

    eNodeType = SNT_CONSTANT;
    field_type = ODS_FIELD_TYPE_INTEGER;
    int_value = bVal;

    FreeSubExpr();

    return TRUE;
}

/************************************************************************/
/*                         EvaluateSingleArgOp()                        */
/************************************************************************/

int ods_formula_node::EvaluateSingleArgOp(IODSCellEvaluator* poEvaluator)
{
    CPLAssert( eNodeType == SNT_OPERATION );

    const SingleOpStruct* psSingleOp = ODSGetSingleOpEntry(eOp);
    CPLAssert(psSingleOp);

    CPLAssert(nSubExprCount == 1);
    if (!(papoSubExpr[0]->Evaluate(poEvaluator)))
        return FALSE;

    CPLAssert(papoSubExpr[0]->eNodeType == SNT_CONSTANT );
    double dfVal = 0;

    if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_INTEGER)
    {
        dfVal = psSingleOp->pfnEval(papoSubExpr[0]->int_value);
    }
    else if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_FLOAT)
    {
        dfVal = psSingleOp->pfnEval(papoSubExpr[0]->float_value);
    }
    else
    {
        CPLError(CE_Failure, CPLE_NotSupported, "Bad argument type for %s",
                 psSingleOp->pszName);
        return FALSE;
    }

    eNodeType = SNT_CONSTANT;
    field_type = ODS_FIELD_TYPE_FLOAT;
    float_value = dfVal;

    FreeSubExpr();

    return TRUE;
}

/************************************************************************/
/*                       EvaluateBinaryArithmetic()                     */
/************************************************************************/

int ods_formula_node::EvaluateBinaryArithmetic(IODSCellEvaluator* poEvaluator)
{
    CPLAssert( eNodeType == SNT_OPERATION );
    CPLAssert( eOp >= ODS_ADD && eOp<= ODS_MODULUS );

    CPLAssert(nSubExprCount == 2);
    if (!(papoSubExpr[0]->Evaluate(poEvaluator)))
        return FALSE;
    if (!(papoSubExpr[1]->Evaluate(poEvaluator)))
        return FALSE;

    CPLAssert(papoSubExpr[0]->eNodeType == SNT_CONSTANT );
    CPLAssert(papoSubExpr[1]->eNodeType == SNT_CONSTANT );

    if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_INTEGER)
    {
        if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_INTEGER)
        {
            int nVal;
            switch (eOp)
            {
                case ODS_ADD      : nVal = (papoSubExpr[0]->int_value + papoSubExpr[1]->int_value); break;
                case ODS_SUBTRACT : nVal = (papoSubExpr[0]->int_value - papoSubExpr[1]->int_value); break;
                case ODS_MULTIPLY : nVal = (papoSubExpr[0]->int_value * papoSubExpr[1]->int_value); break;
                case ODS_DIVIDE   :
                    if (papoSubExpr[1]->int_value != 0)
                        nVal = (papoSubExpr[0]->int_value / papoSubExpr[1]->int_value);
                    else
                        return FALSE;
                    break;
                case ODS_MODULUS  :
                    if (papoSubExpr[1]->int_value != 0)
                        nVal = (papoSubExpr[0]->int_value % papoSubExpr[1]->int_value);
                    else
                        return FALSE;
                    break;
                default: nVal = 0; CPLAssert(0);
            }

            eNodeType = SNT_CONSTANT;
            field_type = ODS_FIELD_TYPE_INTEGER;
            int_value = nVal;

            FreeSubExpr();

            return TRUE;
        }
        else if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_FLOAT)
        {
            papoSubExpr[0]->field_type = ODS_FIELD_TYPE_FLOAT;
            papoSubExpr[0]->float_value = papoSubExpr[0]->int_value;
        }
        else
        {
            CPLError(CE_Failure, CPLE_NotSupported,
                     "Bad argument type for %s", ODSGetOperatorName(eOp));
            return FALSE;
        }
    }

    if (papoSubExpr[0]->field_type == ODS_FIELD_TYPE_FLOAT)
    {
        if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_INTEGER)
        {
            papoSubExpr[1]->field_type = ODS_FIELD_TYPE_FLOAT;
            papoSubExpr[1]->float_value = papoSubExpr[1]->int_value;
        }

        if (papoSubExpr[1]->field_type == ODS_FIELD_TYPE_FLOAT)
        {
            float dfVal;
            switch (eOp)
            {
                case ODS_ADD      : dfVal = (papoSubExpr[0]->float_value + papoSubExpr[1]->float_value); break;
                case ODS_SUBTRACT : dfVal = (papoSubExpr[0]->float_value - papoSubExpr[1]->float_value); break;
                case ODS_MULTIPLY : dfVal = (papoSubExpr[0]->float_value * papoSubExpr[1]->float_value); break;
                case ODS_DIVIDE   :
                    if (papoSubExpr[1]->float_value != 0)
                        dfVal = (papoSubExpr[0]->float_value / papoSubExpr[1]->float_value);
                    else
                        return FALSE;
                    break;
                case ODS_MODULUS  :
                    if (papoSubExpr[1]->float_value != 0)
                        dfVal = fmod(papoSubExpr[0]->float_value, papoSubExpr[1]->float_value);
                    else
                        return FALSE;
                    break;
                default: dfVal = 0.0; CPLAssert(0);
            }

            eNodeType = SNT_CONSTANT;
            field_type = ODS_FIELD_TYPE_FLOAT;
            float_value = dfVal;

            FreeSubExpr();

            return TRUE;
        }
        else
        {
            CPLError(CE_Failure, CPLE_NotSupported,
                     "Bad argument type for %s", ODSGetOperatorName(eOp));
            return FALSE;
        }
    }
    else
    {
        CPLError(CE_Failure, CPLE_NotSupported,
                 "Bad argument type for %s", ODSGetOperatorName(eOp));
        return FALSE;
    }
}


/************************************************************************/
/*                         TransformToString()                          */
/************************************************************************/

std::string ods_formula_node::TransformToString() const
{
    char szTmp[128];
    if (field_type == ODS_FIELD_TYPE_INTEGER)
    {
        snprintf(szTmp, sizeof(szTmp), "%d", int_value);
        return szTmp;
    }
    else if (field_type == ODS_FIELD_TYPE_FLOAT)
    {
        snprintf(szTmp, sizeof(szTmp), "%.16g", float_value);
        return szTmp;
    }
    else if (field_type == ODS_FIELD_TYPE_STRING)
    {
        return string_value;
    }
    else
    {
        return "";
    }
}

/************************************************************************/
/*                           EvaluateCONCAT()                           */
/************************************************************************/

int ods_formula_node::EvaluateCONCAT(IODSCellEvaluator* poEvaluator)
{
    CPLAssert( eNodeType == SNT_OPERATION );
    CPLAssert( eOp == ODS_CONCAT );

    CPLAssert(nSubExprCount == 2);
    if (!(papoSubExpr[0]->Evaluate(poEvaluator)))
        return FALSE;
    if (!(papoSubExpr[1]->Evaluate(poEvaluator)))
        return FALSE;

    CPLAssert(papoSubExpr[0]->eNodeType == SNT_CONSTANT );
    CPLAssert(papoSubExpr[1]->eNodeType == SNT_CONSTANT );

    std::string osLeft(papoSubExpr[0]->TransformToString());
    std::string osRight(papoSubExpr[1]->TransformToString());

    eNodeType = SNT_CONSTANT;
    field_type = ODS_FIELD_TYPE_STRING;
    string_value = CPLStrdup((osLeft + osRight).c_str());

    FreeSubExpr();

    return TRUE;
}

/************************************************************************/
/*                             GetRowCol()                              */
/************************************************************************/

static int GetRowCol(const char* pszCell, int& nRow, int& nCol)
{
    int i;

    if (pszCell[0] != '.')
    {
        CPLError(CE_Failure, CPLE_AppDefined,
                 "Invalid cell %s", pszCell);
        return FALSE;
    }

    nCol = 0;
    for(i=1; pszCell[i]>='A' && pszCell[i]<='Z';i++)
    {
        nCol = nCol * 26 + (pszCell[i] - 'A');
    }
    nRow = atoi(pszCell + i) - 1;

    return TRUE;
}

/************************************************************************/
/*                         EvaluateListArgOp()                          */
/************************************************************************/

int ods_formula_node::EvaluateListArgOp(IODSCellEvaluator* poEvaluator)
{
    CPLAssert( eNodeType == SNT_OPERATION );
    CPLAssert( eOp >= ODS_SUM && eOp <= ODS_COUNTA );

    CPLAssert(nSubExprCount == 1);
    CPLAssert(papoSubExpr[0]->eNodeType == SNT_OPERATION );
    CPLAssert(papoSubExpr[0]->eOp == ODS_LIST );

    std::vector<double> adfVal;
    int i;

    int nCount = 0, nCountA = 0;

    for(i=0;i<papoSubExpr[0]->nSubExprCount;i++)
    {
        if (papoSubExpr[0]->papoSubExpr[i]->eNodeType == SNT_OPERATION &&
            papoSubExpr[0]->papoSubExpr[i]->eOp == ODS_CELL_RANGE)
        {
            CPLAssert (papoSubExpr[0]->papoSubExpr[i]->nSubExprCount == 2);
            CPLAssert (papoSubExpr[0]->papoSubExpr[i]->papoSubExpr[0]->eNodeType == SNT_CONSTANT);
            CPLAssert (papoSubExpr[0]->papoSubExpr[i]->papoSubExpr[0]->field_type == ODS_FIELD_TYPE_STRING);
            CPLAssert (papoSubExpr[0]->papoSubExpr[i]->papoSubExpr[1]->eNodeType == SNT_CONSTANT);
            CPLAssert (papoSubExpr[0]->papoSubExpr[i]->papoSubExpr[1]->field_type == ODS_FIELD_TYPE_STRING);

            if (poEvaluator == NULL)
            {
                CPLError(CE_Failure, CPLE_AppDefined, "No cell evaluator provided");
                return FALSE;
            }

            const char* psz1 = papoSubExpr[0]->papoSubExpr[i]->papoSubExpr[0]->string_value;
            const char* psz2 = papoSubExpr[0]->papoSubExpr[i]->papoSubExpr[1]->string_value;
            int nRow1 = 0,nCol1 = 0;
            if (!GetRowCol(psz1, nRow1, nCol1))
                return FALSE;
            int nRow2 = 0,nCol2 = 0;
            if (!GetRowCol(psz2, nRow2, nCol2))
                return FALSE;

            std::vector<ods_formula_node> aoOutValues;
            if (poEvaluator->EvaluateRange(nRow1, nCol1, nRow2, nCol2, aoOutValues))
            {
                for(size_t j = 0; j < aoOutValues.size(); j++)
                {
                    if (aoOutValues[j].eNodeType == SNT_CONSTANT)
                    {
                        if (aoOutValues[j].field_type == ODS_FIELD_TYPE_INTEGER)
                        {
                            adfVal.push_back(aoOutValues[j].int_value);
                            nCount ++;
                            nCountA ++;
                        }
                        else if (aoOutValues[j].field_type == ODS_FIELD_TYPE_FLOAT)
                        {
                            adfVal.push_back(aoOutValues[j].float_value);
                            nCount ++;
                            nCountA ++;
                        }
                        else if (aoOutValues[j].field_type == ODS_FIELD_TYPE_STRING)
                        {
                            nCountA ++;
                        }
                    }
                }
            }
        }
        else
        {
            if (!(papoSubExpr[0]->papoSubExpr[i]->Evaluate(poEvaluator)))
                return FALSE;

            CPLAssert (papoSubExpr[0]->papoSubExpr[i]->eNodeType == SNT_CONSTANT );
            if (papoSubExpr[0]->papoSubExpr[i]->field_type == ODS_FIELD_TYPE_INTEGER)
            {
                adfVal.push_back(papoSubExpr[0]->papoSubExpr[i]->int_value);
                nCount ++;
                nCountA ++;
            }
            else if (papoSubExpr[0]->papoSubExpr[i]->field_type == ODS_FIELD_TYPE_FLOAT)
            {
                adfVal.push_back(papoSubExpr[0]->papoSubExpr[i]->float_value);
                nCount ++;
                nCountA ++;
            }
            else if (eOp == ODS_COUNT || eOp == ODS_COUNTA)
            {
                if (papoSubExpr[0]->papoSubExpr[i]->field_type == ODS_FIELD_TYPE_STRING)
                    nCountA ++;
            }
            else
            {

                CPLError(CE_Failure, CPLE_NotSupported,
                         "Bad argument type for %s", ODSGetOperatorName(eOp));
                return FALSE;
            }
        }
    }

    if (eOp == ODS_COUNT)
    {
        eNodeType = SNT_CONSTANT;
        field_type = ODS_FIELD_TYPE_INTEGER;
        int_value = nCount;

        FreeSubExpr();
        return TRUE;
    }

    if (eOp == ODS_COUNTA)
    {
        eNodeType = SNT_CONSTANT;
        field_type = ODS_FIELD_TYPE_INTEGER;
        int_value = nCountA;

        FreeSubExpr();
        return TRUE;
    }

    double dfVal = 0;

    switch(eOp)
    {
        case ODS_SUM:
        {
            for(i=0;i<(int)adfVal.size();i++)
            {
                dfVal += adfVal[i];
            }
            break;
        }

        case ODS_AVERAGE:
        {
            for(i=0;i<(int)adfVal.size();i++)
            {
                dfVal += adfVal[i];
            }
            dfVal /= adfVal.size();
            break;
        }

        case ODS_MIN:
        {
            dfVal = (adfVal.size() == 0) ? 0 :adfVal[0];
            for(i=1;i<(int)adfVal.size();i++)
            {
                if (adfVal[i] < dfVal) dfVal = adfVal[i];
            }
            break;
        }

        case ODS_MAX:
        {
            dfVal = (adfVal.size() == 0) ? 0 :adfVal[0];
            for(i=1;i<(int)adfVal.size();i++)
            {
                if (adfVal[i] > dfVal) dfVal = adfVal[i];
            }
            break;
        }

        default:
            break;
    }

    eNodeType = SNT_CONSTANT;
    field_type = ODS_FIELD_TYPE_FLOAT;
    float_value = dfVal;

    FreeSubExpr();

    return TRUE;
}

/************************************************************************/
/*                           EvaluateCELL()                             */
/************************************************************************/

int ods_formula_node::EvaluateCELL(IODSCellEvaluator* poEvaluator)
{
    CPLAssert( eNodeType == SNT_OPERATION );
    CPLAssert( eOp == ODS_CELL );

    CPLAssert(nSubExprCount == 1);
    CPLAssert(papoSubExpr[0]->eNodeType == SNT_CONSTANT );
    CPLAssert(papoSubExpr[0]->field_type == ODS_FIELD_TYPE_STRING );

    if (poEvaluator == NULL)
    {
        CPLError(CE_Failure, CPLE_AppDefined, "No cell evaluator provided");
        return FALSE;
    }

    int nRow = 0,nCol = 0;
    if (!GetRowCol(papoSubExpr[0]->string_value, nRow, nCol))
        return FALSE;

    std::vector<ods_formula_node> aoOutValues;
    if (poEvaluator->EvaluateRange(nRow, nCol, nRow, nCol, aoOutValues) &&
        aoOutValues.size() == 1)
    {
        if (aoOutValues[0].eNodeType == SNT_CONSTANT)
        {
            FreeSubExpr();

            eNodeType = aoOutValues[0].eNodeType;
            field_type = aoOutValues[0].field_type;
            int_value = aoOutValues[0].int_value;
            float_value = aoOutValues[0].float_value;
            string_value = aoOutValues[0].string_value ? CPLStrdup(aoOutValues[0].string_value) : NULL;

            return TRUE;
        }
    }

    return FALSE;
}

/************************************************************************/
/*                           EvaluateLEN()                              */
/************************************************************************/

int ods_formula_node::EvaluateLEN(IODSCellEvaluator* poEvaluator)
{
    CPLAssert( eNodeType == SNT_OPERATION );

    CPLAssert(nSubExprCount == 1);
    if (!(papoSubExpr[0]->Evaluate(poEvaluator)))
        return FALSE;

    CPLAssert(papoSubExpr[0]->eNodeType == SNT_CONSTANT );

    std::string osVal = papoSubExpr[0]->TransformToString();

    eNodeType = SNT_CONSTANT;
    field_type = ODS_FIELD_TYPE_INTEGER;
    int_value = strlen(osVal.c_str()); // FIXME : UTF8 support

    FreeSubExpr();

    return TRUE;
}

/************************************************************************/
/*                           EvaluateLEFT()                             */
/************************************************************************/

int ods_formula_node::EvaluateLEFT(IODSCellEvaluator* poEvaluator)
{
    CPLAssert( eNodeType == SNT_OPERATION );

    CPLAssert(nSubExprCount == 2);
    if (!(papoSubExpr[0]->Evaluate(poEvaluator)))
        return FALSE;
    if (!(papoSubExpr[1]->Evaluate(poEvaluator)))
        return FALSE;

    CPLAssert(papoSubExpr[0]->eNodeType == SNT_CONSTANT );
    CPLAssert(papoSubExpr[1]->eNodeType == SNT_CONSTANT );

    std::string osVal = papoSubExpr[0]->TransformToString();

    if (papoSubExpr[1]->field_type != ODS_FIELD_TYPE_INTEGER)
        return FALSE;

    // FIXME : UTF8 support
    int nVal = papoSubExpr[1]->int_value;
    if (nVal < 0)
        return FALSE;

    osVal = osVal.substr(0,nVal);

    eNodeType = SNT_CONSTANT;
    field_type = ODS_FIELD_TYPE_STRING;
    string_value = CPLStrdup(osVal.c_str());

    FreeSubExpr();

    return TRUE;
}

/************************************************************************/
/*                           EvaluateRIGHT()                            */
/************************************************************************/

int ods_formula_node::EvaluateRIGHT(IODSCellEvaluator* poEvaluator)
{
    CPLAssert( eNodeType == SNT_OPERATION );

    CPLAssert(nSubExprCount == 2);
    if (!(papoSubExpr[0]->Evaluate(poEvaluator)))
        return FALSE;
    if (!(papoSubExpr[1]->Evaluate(poEvaluator)))
        return FALSE;

    CPLAssert(papoSubExpr[0]->eNodeType == SNT_CONSTANT );
    CPLAssert(papoSubExpr[1]->eNodeType == SNT_CONSTANT );

    std::string osVal = papoSubExpr[0]->TransformToString();

    if (papoSubExpr[1]->field_type != ODS_FIELD_TYPE_INTEGER)
        return FALSE;

    // FIXME : UTF8 support
    size_t nLen = osVal.size();
    int nVal = papoSubExpr[1]->int_value;
    if (nVal < 0)
        return FALSE;

    if (nLen > (size_t) nVal)
        osVal = osVal.substr(nLen-nVal);

    eNodeType = SNT_CONSTANT;
    field_type = ODS_FIELD_TYPE_STRING;
    string_value = CPLStrdup(osVal.c_str());

    FreeSubExpr();

    return TRUE;
}

/************************************************************************/
/*                           EvaluateMID()                             */
/************************************************************************/

int ods_formula_node::EvaluateMID(IODSCellEvaluator* poEvaluator)
{
    CPLAssert( eNodeType == SNT_OPERATION );

    CPLAssert(nSubExprCount == 3);
    if (!(papoSubExpr[0]->Evaluate(poEvaluator)))
        return FALSE;
    if (!(papoSubExpr[1]->Evaluate(poEvaluator)))
        return FALSE;
    if (!(papoSubExpr[2]->Evaluate(poEvaluator)))
        return FALSE;

    CPLAssert(papoSubExpr[0]->eNodeType == SNT_CONSTANT );
    CPLAssert(papoSubExpr[1]->eNodeType == SNT_CONSTANT );
    CPLAssert(papoSubExpr[2]->eNodeType == SNT_CONSTANT );

    std::string osVal = papoSubExpr[0]->TransformToString();

    if (papoSubExpr[1]->field_type != ODS_FIELD_TYPE_INTEGER)
        return FALSE;

    if (papoSubExpr[2]->field_type != ODS_FIELD_TYPE_INTEGER)
        return FALSE;

    // FIXME : UTF8 support
    size_t nLen = osVal.size();
    int nStart = papoSubExpr[1]->int_value;
    int nExtractLen = papoSubExpr[2]->int_value;
    if (nStart <= 0)
        return FALSE;
    if (nExtractLen < 0)
        return FALSE;

    if ((size_t)nStart <= nLen)
    {
        if (nStart-1 + nExtractLen >= (int)nLen)
            osVal = osVal.substr(nStart - 1);
        else
            osVal = osVal.substr(nStart - 1, nExtractLen);
    }
    else
        osVal = "";

    eNodeType = SNT_CONSTANT;
    field_type = ODS_FIELD_TYPE_STRING;
    string_value = CPLStrdup(osVal.c_str());

    FreeSubExpr();

    return TRUE;
}
