/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * $Id: ElemStack.hpp 568078 2007-08-21 11:43:25Z amassari $
 */

#if !defined(ELEMSTACK_HPP)
#define ELEMSTACK_HPP

#include <xercesc/util/StringPool.hpp>
#include <xercesc/util/QName.hpp>
#include <xercesc/util/ValueVectorOf.hpp>

XERCES_CPP_NAMESPACE_BEGIN

class XMLElementDecl;
class Grammar;

struct PrefMapElem : public XMemory
{
    unsigned int        fPrefId;
    unsigned int        fURIId;
};

//
//  During the scan of content, we have to keep up with the nesting of
//  elements (for validation and wellformedness purposes) and we have to
//  have places to remember namespace (prefix to URI) mappings.
//
//  We only have to keep a stack of the current path down through the tree
//  that we are currently scanning, and keep track of any children of any
//  elements along that path.
//
//  So, this data structure is a stack, which represents the current path
//  through the tree that we've worked our way down to. For each node in
//  the stack, there is an array of element ids that represent the ids of
//  the child elements scanned so far. Upon exit from that element, its
//  array of child elements is validated.
//
//  Since we have the actual XMLElementDecl in the stack nodes, when its time
//  to validate, we just extract the content model from that element decl
//  and validate. All the required data falls easily to hand. Note that we
//  actually have some derivative of XMLElementDecl, which is specific to
//  the validator used, but the abstract API is sufficient for the needs of
//  the scanner.
//
//  Since the namespace support also requires the storage of information on
//  a nested element basis, this structure also holds the namespace info. For
//  each level, the prefixes defined at that level (and the namespaces that
//  they map to) are stored.
//
class XMLPARSER_EXPORT ElemStack : public XMemory
{
public :
    // -----------------------------------------------------------------------
    //  Class specific data types
    //
    //  These really should be private, but some of the compilers we have to
    //  support are too dumb to deal with that.
    //
    //  PrefMapElem
    //      fURIId is the id of the URI from the validator's URI map. The
    //      fPrefId is the id of the prefix from our own prefix pool. The
    //      namespace stack consists of these elements.
    //
    //  StackElem
    //      fThisElement is the basic element decl for the current element.
    //      The fRowCapacity is how large fChildIds has grown so far.
    //      fChildCount is how many of them are valid right now.
    //
    //      The fMapCapacity is how large fMap has grown so far. fMapCount
    //      is how many of them are valid right now.
    //
    //      Note that we store the reader number we were in when we found the
    //      start tag. We'll use this at the end tag to test for unbalanced
    //      markup in entities.
    //
    //  MapModes
    //      When a prefix is mapped to a namespace id, it matters whether the
    //      QName being mapped is an attribute or name. Attributes are not
    //      affected by an sibling xmlns attributes, whereas elements are
    //      affected by its own xmlns attributes.
    // -----------------------------------------------------------------------
    struct StackElem : public XMemory
    {
        XMLElementDecl*     fThisElement;
        unsigned int        fReaderNum;

        unsigned int        fChildCapacity;
        unsigned int        fChildCount;
        QName**             fChildren;

        PrefMapElem*        fMap;
        unsigned int        fMapCapacity;
        unsigned int        fMapCount;

        bool                fValidationFlag;
        bool                fCommentOrPISeen;
        bool                fReferenceEscaped;
        int                 fCurrentScope;
        Grammar*            fCurrentGrammar;
        unsigned int        fCurrentURI;
        XMLCh *             fSchemaElemName;
        unsigned int        fSchemaElemNameMaxLen;
        
        int                 fPrefixColonPos;
    };

    enum MapModes
    {
        Mode_Attribute
        , Mode_Element
    };


    // -----------------------------------------------------------------------
    //  Constructors and Destructor
    // -----------------------------------------------------------------------
    ElemStack(MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager);
    ~ElemStack();


    // -----------------------------------------------------------------------
    //  Stack access
    // -----------------------------------------------------------------------
    unsigned int addLevel();
    unsigned int addLevel(XMLElementDecl* const toSet, const unsigned int readerNum);
    const StackElem* popTop();


    // -----------------------------------------------------------------------
    //  Stack top access
    // -----------------------------------------------------------------------
    unsigned int addChild(QName* const child, const bool toParent);
    const StackElem* topElement() const;
    void setElement(XMLElementDecl* const toSet, const unsigned int readerNum);

    void setValidationFlag(bool validationFlag);
    bool getValidationFlag();

    inline void setCommentOrPISeen();
    inline bool getCommentOrPISeen() const;

    inline void setReferenceEscaped();
    inline bool getReferenceEscaped() const;

    void setCurrentScope(int currentScope);
    int getCurrentScope();

    void setCurrentGrammar(Grammar* currentGrammar);
    Grammar* getCurrentGrammar();

    void setCurrentURI(unsigned int uri);
    unsigned int getCurrentURI();

    inline void setCurrentSchemaElemName(const XMLCh * const schemaElemName);
    inline XMLCh *getCurrentSchemaElemName();

    void setPrefixColonPos(int colonPos);
    int getPrefixColonPos() const;

    // -----------------------------------------------------------------------
    //  Prefix map methods
    // -----------------------------------------------------------------------
    void addPrefix
    (
        const   XMLCh* const    prefixToAdd
        , const unsigned int    uriId
    );
    unsigned int mapPrefixToURI
    (
        const   XMLCh* const    prefixToMap
        , const MapModes        mode
        ,       bool&           unknown
    )   const;
    ValueVectorOf<PrefMapElem*>* getNamespaceMap() const;
    unsigned int getPrefixId(const XMLCh* const prefix) const;
    const XMLCh* getPrefixForId(unsigned int prefId) const;

    // -----------------------------------------------------------------------
    //  Miscellaneous methods
    // -----------------------------------------------------------------------
    bool isEmpty() const;
    void reset
    (
        const   unsigned int    emptyId
        , const unsigned int    unknownId
        , const unsigned int    xmlId
        , const unsigned int    xmlNSId
    );


private :
    // -----------------------------------------------------------------------
    //  Unimplemented constructors and operators
    // -----------------------------------------------------------------------
    ElemStack(const ElemStack&);
    ElemStack& operator=(const ElemStack&);


    // -----------------------------------------------------------------------
    //  Private helper methods
    // -----------------------------------------------------------------------
    void expandMap(StackElem* const toExpand);
    void expandStack();


    // -----------------------------------------------------------------------
    //  Data members
    //
    //  fEmptyNamespaceId
    //      This is the special URI id for the "" namespace, which is magic
    //      because of the xmlns="" operation.
    //
    //  fGlobalPoolId
    //      This is a special URI id that is returned when the namespace
    //      prefix is "" and no one has explicitly mapped that prefix to an
    //      explicit URI (or when they explicitly clear any such mapping,
    //      which they can also do.) And also its prefix pool id, which is
    //      stored here for fast access.
    //
    //  fPrefixPool
    //      This is the prefix pool where prefixes are hashed and given unique
    //      ids. These ids are used to track prefixes in the element stack.
    //
    //  fStack
    //  fStackCapacity
    //  fStackTop
    //      This the stack array. Its an array of pointers to StackElem
    //      structures. The capacity is the current high water mark of the
    //      stack. The top is the current top of stack (i.e. the part of it
    //      being used.)
    //
    //  fUnknownNamespaceId
    //      This is the URI id for the special URI that is assigned to any
    //      prefix which has not been mapped. This lets us keep going after
    //      issuing the error.
    //
    //  fXMLNamespaceId
    //  fXMLPoolId
    //  fXMLNSNamespaceId
    //  fXMLNSPoolId
    //      These are the URI ids for the special URIs that are assigned to
    //      the 'xml' and 'xmlns' namespaces. And also its prefix pool id,
    //      which is stored here for fast access.
    // -----------------------------------------------------------------------
    unsigned int                 fEmptyNamespaceId;
    unsigned int                 fGlobalPoolId;
    XMLStringPool                fPrefixPool;
    StackElem**                  fStack;
    unsigned int                 fStackCapacity;
    unsigned int                 fStackTop;
    unsigned int                 fUnknownNamespaceId;
    unsigned int                 fXMLNamespaceId;
    unsigned int                 fXMLPoolId;
    unsigned int                 fXMLNSNamespaceId;
    unsigned int                 fXMLNSPoolId;
    ValueVectorOf<PrefMapElem*>* fNamespaceMap;
    MemoryManager*               fMemoryManager;
};


class XMLPARSER_EXPORT WFElemStack : public XMemory
{
public :
    // -----------------------------------------------------------------------
    //  Class specific data types
    //
    //  These really should be private, but some of the compilers we have to
    //  support are too dumb to deal with that.
    //
    //  PrefMapElem
    //      fURIId is the id of the URI from the validator's URI map. The
    //      fPrefId is the id of the prefix from our own prefix pool. The
    //      namespace stack consists of these elements.
    //
    //  StackElem
    //      fThisElement is the basic element decl for the current element.
    //      The fRowCapacity is how large fChildIds has grown so far.
    //      fChildCount is how many of them are valid right now.
    //
    //      The fMapCapacity is how large fMap has grown so far. fMapCount
    //      is how many of them are valid right now.
    //
    //      Note that we store the reader number we were in when we found the
    //      start tag. We'll use this at the end tag to test for unbalanced
    //      markup in entities.
    //
    //  MapModes
    //      When a prefix is mapped to a namespace id, it matters whether the
    //      QName being mapped is an attribute or name. Attributes are not
    //      affected by an sibling xmlns attributes, whereas elements are
    //      affected by its own xmlns attributes.
    // -----------------------------------------------------------------------
    struct StackElem : public XMemory
    {
        int                 fTopPrefix;        
        unsigned int        fCurrentURI;
        unsigned int        fReaderNum;
        unsigned int        fElemMaxLength;
        XMLCh*              fThisElement;
    };

    enum MapModes
    {
        Mode_Attribute
        , Mode_Element
    };


    // -----------------------------------------------------------------------
    //  Constructors and Destructor
    // -----------------------------------------------------------------------
    WFElemStack(MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager);
    ~WFElemStack();


    // -----------------------------------------------------------------------
    //  Stack access
    // -----------------------------------------------------------------------
    unsigned int addLevel();
    unsigned int addLevel(const XMLCh* const toSet, const unsigned int toSetLen,
                          const unsigned int readerNum);
    const StackElem* popTop();


    // -----------------------------------------------------------------------
    //  Stack top access
    // -----------------------------------------------------------------------
    const StackElem* topElement() const;
    void setElement(const XMLCh* const toSet, const unsigned int toSetLen,
                    const unsigned int readerNum);

    void setCurrentURI(unsigned int uri);
    unsigned int getCurrentURI();

    // -----------------------------------------------------------------------
    //  Prefix map methods
    // -----------------------------------------------------------------------
    void addPrefix
    (
        const   XMLCh* const    prefixToAdd
        , const unsigned int    uriId
    );
    unsigned int mapPrefixToURI
    (
        const   XMLCh* const    prefixToMap
        , const MapModes        mode
        ,       bool&           unknown
    )   const;


    // -----------------------------------------------------------------------
    //  Miscellaneous methods
    // -----------------------------------------------------------------------
    bool isEmpty() const;
    void reset
    (
        const   unsigned int    emptyId
        , const unsigned int    unknownId
        , const unsigned int    xmlId
        , const unsigned int    xmlNSId
    );


private :
    // -----------------------------------------------------------------------
    //  Unimplemented constructors and operators
    // -----------------------------------------------------------------------
    WFElemStack(const WFElemStack&);
    WFElemStack& operator=(const WFElemStack&);


    // -----------------------------------------------------------------------
    //  Private helper methods
    // -----------------------------------------------------------------------
    void expandMap();
    void expandStack();


    // -----------------------------------------------------------------------
    //  Data members
    //
    //  fEmptyNamespaceId
    //      This is the special URI id for the "" namespace, which is magic
    //      because of the xmlns="" operation.
    //
    //  fGlobalPoolId
    //      This is a special URI id that is returned when the namespace
    //      prefix is "" and no one has explicitly mapped that prefix to an
    //      explicit URI (or when they explicitly clear any such mapping,
    //      which they can also do.) And also its prefix pool id, which is
    //      stored here for fast access.
    //
    //  fPrefixPool
    //      This is the prefix pool where prefixes are hashed and given unique
    //      ids. These ids are used to track prefixes in the element stack.
    //
    //  fStack
    //  fStackCapacity
    //  fStackTop
    //      This the stack array. Its an array of pointers to StackElem
    //      structures. The capacity is the current high water mark of the
    //      stack. The top is the current top of stack (i.e. the part of it
    //      being used.)
    //
    //  fUnknownNamespaceId
    //      This is the URI id for the special URI that is assigned to any
    //      prefix which has not been mapped. This lets us keep going after
    //      issuing the error.
    //
    //  fXMLNamespaceId
    //  fXMLPoolId
    //  fXMLNSNamespaceId
    //  fXMLNSPoolId
    //      These are the URI ids for the special URIs that are assigned to
    //      the 'xml' and 'xmlns' namespaces. And also its prefix pool id,
    //      which is stored here for fast access.
    // -----------------------------------------------------------------------
    unsigned int    fEmptyNamespaceId;
    unsigned int    fGlobalPoolId;
    unsigned int    fStackCapacity;
    unsigned int    fStackTop;
    unsigned int    fUnknownNamespaceId;
    unsigned int    fXMLNamespaceId;
    unsigned int    fXMLPoolId;
    unsigned int    fXMLNSNamespaceId;
    unsigned int    fXMLNSPoolId;
    unsigned int    fMapCapacity;
    PrefMapElem*    fMap;
    StackElem**     fStack;
    XMLStringPool   fPrefixPool;
    MemoryManager*  fMemoryManager;
};


// ---------------------------------------------------------------------------
//  ElemStack: Miscellaneous methods
// ---------------------------------------------------------------------------
inline bool ElemStack::isEmpty() const
{
    return (fStackTop == 0);
}

inline bool ElemStack::getValidationFlag()
{
    return fStack[fStackTop-1]->fValidationFlag;
}

inline void ElemStack::setValidationFlag(bool validationFlag)
{
    fStack[fStackTop-1]->fValidationFlag = validationFlag;
    return;
}

inline bool ElemStack::getCommentOrPISeen() const
{
    return fStack[fStackTop-1]->fCommentOrPISeen;
}

inline void ElemStack::setCommentOrPISeen()
{
    fStack[fStackTop-1]->fCommentOrPISeen = true;
    return;
}

inline bool ElemStack::getReferenceEscaped() const
{
    return fStack[fStackTop-1]->fReferenceEscaped;
}

inline void ElemStack::setReferenceEscaped()
{
    fStack[fStackTop-1]->fReferenceEscaped = true;
    return;
}

inline void ElemStack::setCurrentSchemaElemName(const XMLCh * const schemaElemName)
{
    unsigned int schemaElemNameLen = XMLString::stringLen(schemaElemName);
    unsigned int stackPos = fStackTop-1;
    
    if(fStack[stackPos]->fSchemaElemNameMaxLen <= schemaElemNameLen)
    {
        XMLCh *tempStr = fStack[stackPos]->fSchemaElemName;
        fStack[stackPos]->fSchemaElemNameMaxLen = schemaElemNameLen << 1;
        fStack[stackPos]->fSchemaElemName = (XMLCh *)fMemoryManager->allocate((fStack[stackPos]->fSchemaElemNameMaxLen)*sizeof(XMLCh));
        fMemoryManager->deallocate(tempStr);
    }
    XMLString::copyString(fStack[stackPos]->fSchemaElemName, schemaElemName);
}

inline XMLCh *ElemStack::getCurrentSchemaElemName()
{
    return fStack[fStackTop-1]->fSchemaElemName;
}

inline int ElemStack::getCurrentScope()
{
    return fStack[fStackTop-1]->fCurrentScope;
}

inline void ElemStack::setCurrentScope(int currentScope)
{
    fStack[fStackTop-1]->fCurrentScope = currentScope;
    return;
}

inline Grammar* ElemStack::getCurrentGrammar()
{
    return fStack[fStackTop-1]->fCurrentGrammar;
}

inline void ElemStack::setCurrentGrammar(Grammar* currentGrammar)
{
    fStack[fStackTop-1]->fCurrentGrammar = currentGrammar;
    return;
}

inline unsigned int ElemStack::getCurrentURI()
{
    return fStack[fStackTop-1]->fCurrentURI;
}

inline void ElemStack::setCurrentURI(unsigned int uri)
{
    fStack[fStackTop-1]->fCurrentURI = uri;
    return;
}

inline unsigned int ElemStack::getPrefixId(const XMLCh* const prefix) const
{
    return fPrefixPool.getId(prefix);
}

inline const XMLCh* ElemStack::getPrefixForId(unsigned int prefId) const
{
    return fPrefixPool.getValueForId(prefId);
}

inline void ElemStack::setPrefixColonPos(int colonPos)
{
    fStack[fStackTop-1]->fPrefixColonPos = colonPos;
}
 
inline int ElemStack::getPrefixColonPos() const {
    return fStack[fStackTop-1]->fPrefixColonPos;
}

// ---------------------------------------------------------------------------
//  WFElemStack: Miscellaneous methods
// ---------------------------------------------------------------------------
inline bool WFElemStack::isEmpty() const
{
    return (fStackTop == 0);
}

inline unsigned int WFElemStack::getCurrentURI()
{
    return fStack[fStackTop-1]->fCurrentURI;
}

inline void WFElemStack::setCurrentURI(unsigned int uri)
{
    fStack[fStackTop-1]->fCurrentURI = uri;
    return;
}


XERCES_CPP_NAMESPACE_END

#endif
