////////////////////////////////////////////////////////////////////////////////
//                                                                             /
// 2012-2019 (c) Baical                                                        /
//                                                                             /
// This library is free software; you can redistribute it and/or               /
// modify it under the terms of the GNU Lesser General Public                  /
// License as published by the Free Software Foundation; either                /
// version 3.0 of the License, or (at your option) any later version.          /
//                                                                             /
// This library 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           /
// Lesser General Public License for more details.                             /
//                                                                             /
// You should have received a copy of the GNU Lesser General Public            /
// License along with this library.                                            /
//                                                                             /
////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdarg.h>
#include "GTypes.h"
#include "AList.h"
#include "Length.h"
#include "PString.h"
#include "Predicate.h"
#include "QStringHelper.h"

////////////////////////////////////////////////////////////////////////////////
//sPr_Node
sPr_Node::sPr_Node()
    : m_qwValue(0) //the largest value in union
    , m_bLink(FALSE)
    , m_eOperator(EPR_OP_UNK)
    , m_dwLength(0)
    , m_pVariable(FALSE)
#if defined(PR_USE_REGEXP)
    , m_pRE(NULL)
#endif
{
}//sPr_Node

////////////////////////////////////////////////////////////////////////////////
//~sPr_Node
sPr_Node::~sPr_Node()
{
#if defined(PR_USE_REGEXP)
    if (m_pRE)
    {
        delete m_pRE;
        m_pRE = NULL;
    }
#endif

    if (    (m_bLink)
         && (m_pGroup)
       )
    {
        delete m_pGroup;
        m_pGroup = NULL;
    }
}//~sPr_Node



////////////////////////////////////////////////////////////////////////////////
//CPredicate
CPredicate::CPredicate()
    : m_pPr(NULL)
    , m_dwPr_Max(0)
    , m_dwPr_Len(0)
{
}//Predicate


////////////////////////////////////////////////////////////////////////////////
//~CPredicate
CPredicate::~CPredicate()
{
    if (m_pPr)
    {
        delete [] m_pPr;
        m_pPr = NULL;
    }

    m_cVars.Clear(TRUE);
    m_cEnums.Clear(TRUE);
}//~CPredicate


////////////////////////////////////////////////////////////////////////////////
//Set_Predicate
tBOOL CPredicate::Set_Predicate(const tXCHAR *i_pPr)
{
    tBOOL       l_bReturn   = TRUE;
    tUINT32     l_dwBracket = 0;
    tBOOL       l_bQuote    = FALSE;
    tBOOL       l_bSlash    = FALSE;
    tBOOL       l_bPercent  = FALSE;
    tUINT32     l_dwLength  = (i_pPr) ? PStrLen(i_pPr) : 0;
    tXCHAR     *l_pPr       = NULL;
    pAList_Cell l_pEl       = NULL;
    tUINT32     l_dwOffset  = 0;

    m_cError[0] = 0;

    m_dwPr_Len = 0;

    if (    (0 >= l_dwLength)
         || (0 >= m_cVars.Count())
       )
    {
        l_bReturn = FALSE;
        goto l_lblExit;
    }

    l_pEl = NULL;
    while ((l_pEl = m_cVars.Get_Next(l_pEl)))
    {
        sPr_Var *l_pVar = m_cVars.Get_Data(l_pEl);
        if (l_pVar)
        {
            l_pVar->m_bUsed = FALSE;
        }
    }

    //allocate memory for predicate string if space is not enought
    if (l_dwLength >= m_dwPr_Max)
    {
        if (m_pPr)
        {
            delete [] m_pPr;
        }

        m_dwPr_Max = l_dwLength + 32;
        m_pPr      = new tXCHAR[m_dwPr_Max];

        if (NULL == m_pPr)
        {
            m_dwPr_Max = 0;
        }
    }

    if (NULL == m_pPr)
    {
        l_bReturn = FALSE;
        goto l_lblExit;
    }

    l_pPr = m_pPr;
    //copy predicate and check brakets () count and "" pairs
    //if we get \" inside text constant we replace it by "
    while (0 != *i_pPr)
    {
        *l_pPr = *i_pPr;

        //processing special symbols
        if (l_bSlash)
        {
            if (TM('\"') == *i_pPr)
            {
                l_pPr--; //rewrite prev. symbol
                m_dwPr_Len --;
            }

            l_bSlash = FALSE;
        }
        else //regular symbols
        {
            if (    (FALSE == l_bQuote)
                 && (FALSE == l_bPercent)
                 && (    (TM('(') == *i_pPr)
                      || (TM(')') == *i_pPr)
                    )
               )
            {
                l_dwBracket ++;
            }
            else if (    (FALSE == l_bPercent)
                      && (TM('\"') == *i_pPr)
                    )
            {
                l_bQuote = ! l_bQuote;

                if (FALSE == l_bQuote) 
                {
                    *l_pPr = 0; //set 0 instead closing "
                }
            }
            else if (    (l_bQuote)
                      && (TM('\\') == *i_pPr)
                    )
            {
                l_bSlash = TRUE;
            }
            else if (TM('$') == *i_pPr)
            {
                l_bPercent = ! l_bPercent;
                if (FALSE == l_bPercent) 
                {
                    *l_pPr = 0; //set 0 instead closing $
                }
            }
        }

        if (   (    (0xA  != *i_pPr)
                 && (0xD  != *i_pPr)
                 && (0x9  != *i_pPr)
                 && (0x20 != *i_pPr)
               )
            || (l_bQuote)
            || (l_bPercent)
           )
        {
            l_pPr ++;
            m_dwPr_Len ++;
        }

        i_pPr ++;
    }

    *l_pPr = 0;

    if (0 == PStrLen(m_pPr))
    {
        PStrCpy(m_cError, LENGTH(m_cError), TM("Predicate is empty"));
        l_bReturn = FALSE;
        goto l_lblExit;
    }

    if (l_dwBracket & 1)
    {
        PStrCpy(m_cError, LENGTH(m_cError), TM("Not of all ( or ) has a pair"));
        l_bReturn = FALSE;
        goto l_lblExit;
    }

    if (l_bQuote)
    {
        PStrCpy(m_cError, LENGTH(m_cError), TM("Not of all \" has a pair"));
        l_bReturn = FALSE;
        goto l_lblExit;
    }

    if (l_bPercent)
    {
        PStrCpy(m_cError, LENGTH(m_cError), TM("Not of all $ has a pair"));
        l_bReturn = FALSE;
        goto l_lblExit;
    }

    m_cGroup.m_cOrGroups.Clear(TRUE);

    l_bReturn = Build(&m_cGroup, &l_dwOffset);
l_lblExit:

    return l_bReturn;
}//Set_Predicate


////////////////////////////////////////////////////////////////////////////////
//Get_Error()
tXCHAR *CPredicate::Get_Error()
{
    return m_cError;
}//Get_Error()


////////////////////////////////////////////////////////////////////////////////
//Set_Variables()
tBOOL CPredicate::Set_Variables(tUINT32 i_dwCount, ...) 
{
    m_cVars.Clear(TRUE);

    va_list   l_pParams;
    tXCHAR   *l_pName   = NULL;
    ePr_VType l_eType   = EPR_VTYPE_UNK;

    va_start(l_pParams, i_dwCount);
    while (i_dwCount)
    {
        l_pName = va_arg(l_pParams, tXCHAR*);
        //ePr_VType
        l_eType = (ePr_VType)va_arg(l_pParams, int);

        m_cVars.Add_After(m_cVars.Get_Last(), new sPr_Var(l_pName, l_eType));
        i_dwCount --;
    }
    va_end(l_pParams);


    return TRUE;
}//Set_Variables


////////////////////////////////////////////////////////////////////////////////
//Set_Enum()
tBOOL CPredicate::Set_Enum(tUINT32 i_dwEnum_ID, tUINT32 i_dwCount, ...)
{
    if (    (0 >= i_dwCount)
         || (EPR_VTYPE_ENUM > i_dwEnum_ID)
       )
    {
        return FALSE;
    }

    pAList_Cell l_pEl   = NULL;
    sPr_Enum   *l_pEnum = NULL;
    while ((l_pEl = m_cEnums.Get_Next(l_pEl)))
    {
        l_pEnum = m_cEnums.Get_Data(l_pEl);
        if (    (l_pEnum)
             && (i_dwEnum_ID == l_pEnum->m_dwID)
           )
        {
            m_cEnums.Del(l_pEl, TRUE);
            break;
        }
    }

    l_pEnum = new sPr_Enum(i_dwEnum_ID);
    if (NULL == l_pEnum)
    {
        return FALSE;
    }

    m_cEnums.Add_After(m_cEnums.Get_Last(), l_pEnum);

    va_list  l_pParams;
    tXCHAR  *l_pName   = NULL;
    int      l_iValue  = 0;

    va_start(l_pParams, i_dwCount);
    while (i_dwCount)
    {
        l_pName  = va_arg(l_pParams, tXCHAR*);
        l_iValue = va_arg(l_pParams, int);

        l_pEnum->m_cItems.Add_After(l_pEnum->m_cItems.Get_Last(), 
                                    new sPr_Enum_Item(l_pName, l_iValue)
                                   );
        i_dwCount --;
    }
    va_end(l_pParams);

    return TRUE;
} //Set_Enum



////////////////////////////////////////////////////////////////////////////////
//Check
tBOOL CPredicate::Check(const void *i_pData)
{
    if (FALSE == Fill_Variables(i_pData))
    {
        return FALSE;
    }

    return Check(&m_cGroup);
}//Check


////////////////////////////////////////////////////////////////////////////////
//Check
tBOOL CPredicate::Check(sPr_Group *i_pGroup)
{
    tBOOL l_bResult = TRUE;

    if (    (NULL == i_pGroup)
         || (0 >= i_pGroup->m_cOrGroups.Count()) 
       )
    {
        return TRUE;
    }

    pAList_Cell l_pEl_Or = NULL;
    while ((l_pEl_Or = i_pGroup->m_cOrGroups.Get_Next(l_pEl_Or)))
    {
        sPr_OrGroup *l_pOrGroup = i_pGroup->m_cOrGroups.Get_Data(l_pEl_Or);
        if (l_pOrGroup)
        {
            l_bResult = TRUE; 

            pAList_Cell l_pEl_Node = NULL;
            while ((l_pEl_Node = l_pOrGroup->m_cNodes.Get_Next(l_pEl_Node)))
            {
                sPr_Node *l_pNode = l_pOrGroup->m_cNodes.Get_Data(l_pEl_Node);
                if (l_pNode) 
                {
                    if (FALSE == l_pNode->m_bLink)
                    {
                        //compare
                        l_bResult &= Is_True(l_pNode);
                    }
                    else 
                    {
                        l_bResult &= Check(l_pNode->m_pGroup);
                    }
                }

                if (FALSE == l_bResult)
                {
                    break;
                }
            }

            if (l_bResult)
            {
                break;
            }
        } //if (l_pOrGroup)
    } //while (l_pEl_Or = i_pGroup->m_cOrGroups.Get_Next(l_pEl_Or))

    return l_bResult;
}//Check



////////////////////////////////////////////////////////////////////////////////
//Build
tBOOL CPredicate::Build(sPr_Group *i_pGroup, tUINT32 *io_pOffset)
{
    tBOOL         l_bResult  = TRUE;
    tBOOL         l_bNode    = FALSE;
    const tXCHAR *l_pNext    = TM("($\""); //3 symbols allowed at start of predicate;
    tBOOL         l_bExit    = FALSE;
    sPr_OrGroup *l_pOrGroup = NULL;

    if (    (NULL == i_pGroup)
         || (NULL == io_pOffset) 
       )
    {
        return FALSE;
    }

    l_pOrGroup = new sPr_OrGroup();

    if (NULL == l_pOrGroup)
    {
        return FALSE;
    }

    i_pGroup->m_cOrGroups.Add_After(i_pGroup->m_cOrGroups.Get_Last(), l_pOrGroup);

    for (; (*io_pOffset) < m_dwPr_Len; (*io_pOffset)++)
    {
        if (PStrChr(l_pNext, m_pPr[*io_pOffset]))
        {
            switch (m_pPr[*io_pOffset])
            {
                case TM('('):
                {
                    l_pNext   = TM(")&|");
                    l_bNode   = FALSE;
                    l_bResult = FALSE;

                    sPr_Node *l_pNode = new sPr_Node();
                    if (l_pNode)
                    {
                        l_pNode->m_bLink  = TRUE;
                        l_pNode->m_pGroup = new sPr_Group();
                        if (l_pNode->m_pGroup)
                        {
                            l_pOrGroup->m_cNodes.Add_After(l_pOrGroup->m_cNodes.Get_Last(), l_pNode);
                            (*io_pOffset)++;
                            l_bResult = Build(l_pNode->m_pGroup, io_pOffset);    
                        }
                        else
                        {
                            delete l_pNode;
                            l_pNode = NULL;
                        }
                    }


                    break;
                }
                case TM(')'):
                {
                    //l_pAllow  = TM(""); //not important, we are going to exit
                    l_bExit = TRUE;
                    break;
                }
                case TM('$'):
                case TM('\"'):
                {
                    l_pNext   = TM(")&|");
                    l_bResult = Add_Node(&l_pOrGroup->m_cNodes, io_pOffset);
                    l_bNode   = FALSE;
                    break;
                }
                case TM('&'):
                {
                    l_pNext  = TM("($\"");
                    l_bNode  = TRUE;
                    break;
                }
                case TM('|'):
                {
                    l_pNext  = TM("($\"");
                    l_bNode  = TRUE;
                    l_pOrGroup = new sPr_OrGroup();
                    if (l_pOrGroup)
                    {
                        i_pGroup->m_cOrGroups.Add_After(i_pGroup->m_cOrGroups.Get_Last(), 
                                                        l_pOrGroup
                                                       );
                    }
                    else
                    {
                        l_bResult = FALSE;
                    }

                    break;
                }
            } //switch
        }
        else
        {
            l_bResult = FALSE;
            PSPrint(m_cError, 
                       LENGTH(m_cError), 
                       TM("We are expecting one of the next characters: %s, but found: %c"),
                       l_pNext,
                       m_pPr[*io_pOffset]
                      );
        }


        if (    (FALSE == l_bResult)
             || (TRUE  == l_bExit) 
           )
        {
            break;
        }
    }//for ((*io_pOffset)

    if (    (l_bNode)
         && (l_bResult)
       )
    {
        l_bResult = FALSE;
        PStrCpy(m_cError, LENGTH(m_cError), TM("Expression is not closed"));
    }

    return l_bResult;
}//Build


////////////////////////////////////////////////////////////////////////////////
//Add_Node
tBOOL CPredicate::Add_Node(CBList<sPr_Node*> *i_pNodes, tUINT32 *io_pOffset)
{
    tUINT32    l_dwOper_IDX = LENGTH(g_pOperators);
    tBOOL      l_bResult    = TRUE;
    tBOOL      l_bRevers    = FALSE;
    tXCHAR    *l_pTemp      = NULL; 
    tXCHAR    *l_pVariable  = NULL;
    tXCHAR    *l_pConst     = NULL;
    tXCHAR    *l_pOper      = NULL;
    tUINT32    l_dwOffset   = *io_pOffset;
    sPr_Node  *l_pNode      = NULL;

    if (    (NULL == i_pNodes)
         || (NULL == io_pOffset)
         || ((*io_pOffset) >= m_dwPr_Len)
       )
    {
        return FALSE;
    }

    //get left term
    l_pTemp = m_pPr + (*io_pOffset);
    (*io_pOffset) += PStrLen(l_pTemp) + 1;

    if (    ((*io_pOffset) >= m_dwPr_Len)
         || (0 >= PStrLen(l_pTemp))
       )
    {
        PSPrint(m_cError, 
                LENGTH(m_cError), 
                TM("Parsing error during processing %s, the string is too short"),
                m_pPr + l_dwOffset
               );

        return FALSE;
    }

    //extract variable or const
    if (TM('$') == l_pTemp[0])
    {
        l_pVariable = ++l_pTemp;
    }
    else if (TM('\"') == l_pTemp[0])
    {
        l_pConst  = ++l_pTemp;
        l_bRevers = TRUE;
    }
    else
    {
        PSPrint(m_cError, 
                LENGTH(m_cError), 
                TM("Parsing error during processing %s, term is unknown"),
                l_pTemp
               );

        return FALSE;
    }

    //get operator
    l_pOper = m_pPr + (*io_pOffset);

    for (tUINT32 l_dwI = 0; l_dwI < LENGTH(g_pOperators); l_dwI++)
    {
        if (0 == PStrNiCmp(g_pOperators[l_dwI].pText, l_pOper, g_pOperators[l_dwI].dwLen))
        {
            l_dwOper_IDX   = l_dwI;
            (*io_pOffset) += g_pOperators[l_dwI].dwLen;
            break;
        }
    }

    if (    (LENGTH(g_pOperators) <= l_dwOper_IDX)
         || ((*io_pOffset) >= m_dwPr_Len)
       )
    {
        PSPrint(m_cError, 
                   LENGTH(m_cError), 
                   TM("Parsing error during processing %s, the operator is not recognized"),
                   m_pPr + (*io_pOffset)
                  );
        return FALSE;
    }

    //get operator
    l_pTemp = m_pPr + (*io_pOffset);
    //+1 - we remove, it will be incremented outside
    (*io_pOffset) += PStrLen(l_pTemp); 

    //extract variable or const
    if (TM('$') == l_pTemp[0])
    {
        l_pVariable = ++l_pTemp;
    }
    else if (TM('\"') == l_pTemp[0])
    {
        l_pConst =  ++l_pTemp;
    }
    else
    {
        PSPrint(m_cError, 
                   LENGTH(m_cError), 
                   TM("Parsing error during processing %s, term is unknown"),
                   l_pTemp
                  );

        return FALSE;
    }

    if (    (NULL == l_pVariable)
         || (NULL == l_pConst)
       )
    {
        PSPrint(m_cError, 
                   LENGTH(m_cError), 
                   TM("Parsing error during processing %s, missed variable or constant"),
                   m_pPr + (*io_pOffset)
                  );
        return FALSE;
    }

    l_pNode = new sPr_Node();
    if (NULL == l_pNode)
    {
        return FALSE;
    }

    l_pNode->m_eOperator =  (l_bRevers) 
                           ? g_pOperators[l_dwOper_IDX].eRevers
                           : g_pOperators[l_dwOper_IDX].eType;

    l_bResult = Fill_Node(l_pNode, l_pVariable, l_pConst);

    if (l_bResult)
    {
        if (    (    (EPR_VTYPE_WTEXT == l_pNode->m_pVariable->m_eType)
                  && (TRUE == g_pOperators[l_dwOper_IDX].bDigit)
                )
             || (    (EPR_VTYPE_WTEXT != l_pNode->m_pVariable->m_eType)
                  && (FALSE == g_pOperators[l_dwOper_IDX].bDigit)
                )
           )
        {
            l_bResult = FALSE;
            PSPrint(m_cError, 
                       LENGTH(m_cError), 
                       TM("Operator \"%s\" is not supported for variable %s"),
                       g_pOperators[l_dwOper_IDX].pText,
                       l_pVariable
                      );
        }
    }

#if defined(PR_USE_REGEXP)
    if (    (l_bResult)
         && (EPR_VTYPE_WTEXT == l_pNode->m_pVariable->m_eType)
         && (    (EPR_OP_REG_EXP == g_pOperators[l_dwOper_IDX].eType)
              || (EPR_OP_WILD_CARD == g_pOperators[l_dwOper_IDX].eType)
            )
       )
    {
        l_pNode->m_pRE = new QRegExp(XCHAR_TO_QSTRING(l_pConst),
                                     Qt::CaseInsensitive,
                                       (EPR_OP_REG_EXP == g_pOperators[l_dwOper_IDX].eType)
                                     ? QRegExp::RegExp2
                                     : QRegExp::Wildcard
                                    );

        if (l_pNode->m_pRE)
        {
            if (!l_pNode->m_pRE->isValid())
            {
                l_bResult = FALSE;
                PSPrint(m_cError, 
                           LENGTH(m_cError), 
                           TM("regular expression isn't valid (%S)"),
                           l_pNode->m_pRE->errorString().toLocal8Bit().data()
                          );
            }
        }
        else
        {
            l_bResult = FALSE;
            PSPrint(m_cError, LENGTH(m_cError),  TM("Can't create regular expression"));
        }
    }
#endif

    if (l_bResult)
    {
        i_pNodes->Add_After(i_pNodes->Get_Last(), l_pNode);
    }
    else if (l_pNode)
    {
        delete l_pNode;
        l_pNode = NULL;
    }

    return l_bResult;
}//Add_Node


////////////////////////////////////////////////////////////////////////////////
//Fill_Node
tBOOL CPredicate::Fill_Node(sPr_Node *i_pNode,
                           tXCHAR  *i_pVariable,
                           tXCHAR  *i_pConst
                          )
{
    tBOOL       l_bSuccess = TRUE;
    pAList_Cell l_pEl      = NULL;

    i_pNode->m_pVariable = NULL;

    while ((l_pEl = m_cVars.Get_Next(l_pEl)))
    {
        i_pNode->m_pVariable = m_cVars.Get_Data(l_pEl);
        if (    (i_pNode->m_pVariable)
             && (0 == PStrICmp(i_pNode->m_pVariable->m_pName, i_pVariable))
           )
        {
            i_pNode->m_pVariable->m_bUsed = TRUE;
            break;
        }
        else
        {
            i_pNode->m_pVariable = NULL;
        }
    }

    if (NULL == i_pNode->m_pVariable)
    {
        PSPrint(m_cError, 
                LENGTH(m_cError), 
                TM("Variable %s is not defined"),
                i_pVariable
               );
        return FALSE;
    }


    if (EPR_VTYPE_INT == i_pNode->m_pVariable->m_eType)
    {
        if (    (2 < PStrLen(i_pConst))
             && (0 == PStrNiCmp(i_pConst, TM("0x"), 2))
           )
        {
            l_bSuccess = (1 == PStrScan(i_pConst + 2, TM("%llx"), &i_pNode->m_qwValue));
        }
        else
        {
            l_bSuccess = (1 == PStrScan(i_pConst, TM("%llu"), &i_pNode->m_qwValue));
        }

        if (FALSE == l_bSuccess)
        {
            PSPrint(m_cError, 
                        LENGTH(m_cError), 
                        TM("Not possible to extract digit from %s"),
                        i_pConst
                        );
        }
    }
    else if (EPR_VTYPE_FLOAT == i_pNode->m_pVariable->m_eType)
    {
        float l_fTmp  = 0;
        l_bSuccess = (1 == PStrScan(i_pConst, TM("%f"), &l_fTmp));
        if (FALSE == l_bSuccess)
        {
            PSPrint(m_cError, 
                        LENGTH(m_cError), 
                        TM("Not possible to extract digit from %s"),
                        i_pConst
                        );
        }
        else
        {
            i_pNode->m_dbValue = l_fTmp;
        }
    }
    else if (EPR_VTYPE_DATE == i_pNode->m_pVariable->m_eType)
    {
        tUINT32 l_dwDay    = 0;
        tUINT32 l_dwMonth  = 0;
        tUINT32 l_dwYear   = 0;
        tUINT32 l_dwHour   = 0;
        tUINT32 l_dwMinute = 0;
        tUINT32 l_dwSec    = 0;
        tUINT32 l_dwMSec   = 0;
        l_bSuccess = (4 < PStrScan(i_pConst, 
                                   TM("%02u.%02u.%04u %02u:%02u:%02u.%03u"),
                                   &l_dwDay,
                                   &l_dwMonth,
                                   &l_dwYear,
                                   &l_dwHour,
                                   &l_dwMinute,
                                   &l_dwSec,
                                   &l_dwMSec
                                  )
                    );


        if (l_bSuccess)
        {
            i_pNode->m_qwValue = PackLocalTime(l_dwYear, l_dwMonth, l_dwDay, l_dwHour, 
                                               l_dwMinute, l_dwSec, l_dwMSec, 0, 0);
        }
        else
        {
            PSPrint(m_cError, 
                    LENGTH(m_cError), 
                    TM("Date %s has wrong format"),
                    i_pConst
                   );
        }
    }
    else if (EPR_VTYPE_WTEXT == i_pNode->m_pVariable->m_eType)
    {
        i_pNode->m_pValue   = i_pConst;    
        i_pNode->m_dwLength = PStrLen(i_pConst);
    }
    else if (EPR_VTYPE_ENUM <= i_pNode->m_pVariable->m_eType)
    {
        l_bSuccess = FALSE;
        l_pEl      = NULL;
        while ((l_pEl = m_cEnums.Get_Next(l_pEl)))
        {
            sPr_Enum *l_pEnum = m_cEnums.Get_Data(l_pEl);
            if ((ePr_VType)l_pEnum->m_dwID == i_pNode->m_pVariable->m_eType)
            {
                pAList_Cell l_pItem_El = NULL;
                while ((l_pItem_El = l_pEnum->m_cItems.Get_Next(l_pItem_El)))
                {
                    sPr_Enum_Item *l_pEItem = l_pEnum->m_cItems.Get_Data(l_pItem_El);
                    if (    (l_pEItem)
                         && (0 == PStrICmp(l_pEItem->m_pName, i_pConst))
                       )
                    {
                        i_pNode->m_qwValue = l_pEItem->m_iValue;
                        l_bSuccess = TRUE;
                        break;
                    }
                }
                break;
            }
        }

        if (FALSE == l_bSuccess)
        {
            PSPrint(m_cError, 
                       LENGTH(m_cError), 
                       TM("Enum value %s is unknown"),
                       i_pConst
                      );
        }
    }


    return l_bSuccess;
}//Fill_Node


////////////////////////////////////////////////////////////////////////////////
//Is_True
tBOOL CPredicate::Is_True(sPr_Node *i_pNode)
{
    tBOOL l_bReturn = FALSE;


    if (    (EPR_VTYPE_INT  == i_pNode->m_pVariable->m_eType)
         || (EPR_VTYPE_DATE == i_pNode->m_pVariable->m_eType)
         || (EPR_VTYPE_ENUM == i_pNode->m_pVariable->m_eType)
       )
    {
        if (EPR_OP_EQUAL == i_pNode->m_eOperator)                            //=
        {
            l_bReturn = (i_pNode->m_pVariable->m_qwValue == i_pNode->m_qwValue);
        } 
        else if (EPR_OP_NOT_EQUAL == i_pNode->m_eOperator)                  //!=
        {
            l_bReturn = (i_pNode->m_pVariable->m_qwValue != i_pNode->m_qwValue);
        } 
        else if (EPR_OP_GREATER == i_pNode->m_eOperator)                     //>
        {
            l_bReturn = (i_pNode->m_pVariable->m_qwValue > i_pNode->m_qwValue);
        } 
        else if (EPR_OP_GREATER_OR_EQUAL == i_pNode->m_eOperator)           //>=
        {
            l_bReturn = (i_pNode->m_pVariable->m_qwValue >= i_pNode->m_qwValue);
        } 
        else if (EPR_OP_LESS == i_pNode->m_eOperator)                        //<
        {
            l_bReturn = (i_pNode->m_pVariable->m_qwValue < i_pNode->m_qwValue);
        } 
        else if (EPR_OP_LESS_OR_EQUAL == i_pNode->m_eOperator)              //<=
        {
            l_bReturn = (i_pNode->m_pVariable->m_qwValue <= i_pNode->m_qwValue);
        } 
    }
    else if (EPR_VTYPE_FLOAT  == i_pNode->m_pVariable->m_eType)
    {
        if (EPR_OP_EQUAL == i_pNode->m_eOperator)                            //=
        {
            l_bReturn = (i_pNode->m_pVariable->m_dbValue == i_pNode->m_dbValue);
        } 
        else if (EPR_OP_NOT_EQUAL == i_pNode->m_eOperator)                  //!=
        {
            l_bReturn = (i_pNode->m_pVariable->m_dbValue != i_pNode->m_dbValue);
        } 
        else if (EPR_OP_GREATER == i_pNode->m_eOperator)                     //>
        {
            l_bReturn = (i_pNode->m_pVariable->m_dbValue > i_pNode->m_dbValue);
        } 
        else if (EPR_OP_GREATER_OR_EQUAL == i_pNode->m_eOperator)           //>=
        {
            l_bReturn = (i_pNode->m_pVariable->m_dbValue >= i_pNode->m_dbValue);
        } 
        else if (EPR_OP_LESS == i_pNode->m_eOperator)                       //<
        {
            l_bReturn = (i_pNode->m_pVariable->m_dbValue < i_pNode->m_dbValue);
        } 
        else if (EPR_OP_LESS_OR_EQUAL == i_pNode->m_eOperator)              //<=
        {
            l_bReturn = (i_pNode->m_pVariable->m_dbValue <= i_pNode->m_dbValue);
        } 
    }
    else if (EPR_VTYPE_WTEXT  == i_pNode->m_pVariable->m_eType)
    {
        if (EPR_OP_LEFT_INCLUDE == i_pNode->m_eOperator)                    //<<
        {
            l_bReturn = Is_Sub(i_pNode->m_pVariable->m_pValue, 
                               i_pNode->m_pVariable->m_dwLength,
                               i_pNode->m_pValue,
                               i_pNode->m_dwLength
                              );
        } 
        else if (EPR_OP_RIGHT_INCLUDE == i_pNode->m_eOperator)              //>>
        {
            l_bReturn = Is_Sub(i_pNode->m_pValue,
                               i_pNode->m_dwLength,
                               i_pNode->m_pVariable->m_pValue, 
                               i_pNode->m_pVariable->m_dwLength
                              );
        } 
        else if (EPR_OP_LEFT_NOT_INCLUDE == i_pNode->m_eOperator)           //<!
        {
            l_bReturn = (! Is_Sub(i_pNode->m_pVariable->m_pValue, 
                                  i_pNode->m_pVariable->m_dwLength,
                                  i_pNode->m_pValue,
                                  i_pNode->m_dwLength
                                 )
                        );
        } 
        else if (EPR_OP_RIGHT_NOT_INCLUDE == i_pNode->m_eOperator)          //!>
        {
            l_bReturn = (! Is_Sub(i_pNode->m_pValue,
                                  i_pNode->m_dwLength,
                                  i_pNode->m_pVariable->m_pValue, 
                                  i_pNode->m_pVariable->m_dwLength
                                 )
                        );
        } 
#if defined(PR_USE_REGEXP)                                                  
        else if (    (EPR_OP_REG_EXP   == i_pNode->m_eOperator)             //r=
                  || (EPR_OP_WILD_CARD == i_pNode->m_eOperator)             //w=
                )
        {
            l_bReturn = i_pNode->m_pRE->exactMatch(XCHAR_TO_QSTRING(i_pNode->m_pVariable->m_pValue));
        } 
#endif
    }

    return l_bReturn;
}//Is_True


////////////////////////////////////////////////////////////////////////////////
//Is_Sub
tBOOL CPredicate::Is_Sub(tXCHAR *i_pStr, 
                        tUINT32  i_dwStr_Len, 
                        tXCHAR  *i_pSub,
                        tUINT32  i_dwSub_Len
                       )
{
    if (    (NULL == i_pStr)
         || (NULL == i_pSub)
       )
    {
        return FALSE;
    }

    if (0 == i_dwSub_Len)
    {
        return TRUE;
    }

    if (i_dwSub_Len > i_dwStr_Len)
    {
        return FALSE;
    }

    for (tUINT32 l_dwI = 0; l_dwI <= (i_dwStr_Len - i_dwSub_Len); l_dwI++)
    {
        if (0 == PStrNiCmp(i_pStr + l_dwI, i_pSub, i_dwSub_Len))
        {
            return TRUE;
        }
    }

    return FALSE;
}



