/*
 * The contents of this file are subject to the Netscape Public
 * License Version 1.1 (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.mozilla.org/NPL/

 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.

 * The Original Code is Rhino code, released
 * May 6, 1999.

 * The Initial Developer of the Original Code is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1997-1999 Netscape Communications Corporation. All
 * Rights Reserved.

 * Contributor(s): 

 * Alternatively, the contents of this file may be used under the
 * terms of the GNU Public License (the "GPL"), in which case the
 * provisions of the GPL are applicable instead of those above.
 * If you wish to allow use of your version of this file only
 * under the terms of the GPL and not to allow others to use your
 * version of this file under the NPL, indicate your decision by
 * deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL.  If you do not delete
 * the provisions above, a recipient may use your version of this
 * file under either the NPL or the GPL.
 */

#ifndef _JS_NODE_H_
#define _JS_NODE_H_

#include <lstLib.h>
#include <assert.h>
#include "js-zonenew.h"
#include "js-context.h"
#include "js-instanceof.h"
#include "js-vector.h"
#include "js-preordernodeiterator.h"
#include "js-shallownodeiterator.h"

/* Classes */
class JSNode: public JSZoneNew, public NODE, public JSInstanceOf {
    friend class JSPreorderNodeIterator;
    friend class JSShallowNodeIterator;
    public:
        class   Datum;
        class   Props;

    public:
        typedef JSVector<JSNode *, JSContext::ZoneAllocator> _Vector;
        class Vector: public JSZoneNew, public _Vector {
            public:
                Vector(JSContext *cx, int initialCapacity = 20)
                        : _Vector(&cx->allocator, initialCapacity) {
                }
                virtual ~Vector() {
                }

                void    destroy(JSContext *cx) {
                    this->~Vector();
                    JSZoneNew::destroy(cx);
                }
                void  operator delete(void *ptr) {
                        assert(0);
                }
        } ;
        /*
        void  operator delete(void *ptr) {
                assert(0);
        }
        */
    public:
        static const jsString_t className;

        static const int        TARGET_PROP             =  1,
                                BREAK_PROP              =  2,
                                CONTINUE_PROP           =  3,
                                ENUM_PROP               =  4,
                                FUNCTION_PROP           =  5,
                                TEMP_PROP               =  6,
                                LOCAL_PROP              =  7,
                                CODEOFFSET_PROP         =  8,
                                FIXUPS_PROP             =  9,
                                VARS_PROP               = 10,
                                USES_PROP               = 11,
                                REGEXP_PROP             = 12,
                                CASES_PROP              = 13,
                                DEFAULT_PROP            = 14,
                                CASEARRAY_PROP          = 15,
                                SOURCENAME_PROP         = 16,
                                SOURCE_PROP             = 17,
                                TYPE_PROP               = 18,
                                SPECIAL_PROP_PROP       = 19,
                                LABEL_PROP              = 20,
                                FINALLY_PROP            = 21,
                                LOCALCOUNT_PROP         = 22,
                                TARGETBLOCK_PROP        = 23,
                                VARIABLE_PROP           = 24,
                                LASTUSE_PROP            = 25,
                                ISNUMBER_PROP           = 26,
                                DIRECTCALL_PROP         = 27,

                                BASE_LINENO_PROP        = 28,
                                END_LINENO_PROP         = 29,
                                SPECIALCALL_PROP        = 30,

                                /* value is vector */
                                FUNCTION_LIST_PROP
                                                        = 31;
        /*
         * this value of the ISNUMBER_PROP specifies
         * which of the children are Number types
         */
        static const int        BOTH    = 0,
                                LEFT    = 1,
                                RIGHT   = 2;

    protected:
        int             type;   // type of the node; TokenStream.NAME
                                // for example
        LIST            children;
        Props           *props;
        Datum           *datum; // encapsulated data; depends on type

        int             refCount;

    protected:
        static  jsString_t      propToString(int propType);

        jsString_t
                toStringTreeHelper(JSContext *cx, int level);
        void    initialize(int nodeType);

    public:
        JSNode(int nodeType);
        JSNode(int nodeType, JSNode *child);
        JSNode(int nodeType, JSNode *left, JSNode *right);
        JSNode(int nodeType, JSNode *left, JSNode *mid, JSNode *right);
        JSNode(JSContext *cx, int nodeType, int datum);
        JSNode(JSContext *cx, int nodeType, double datum);
        JSNode(JSContext *cx, int nodeType, jsString_t datum);
        JSNode(JSContext *cx, int nodeType, JSNode *child, int datum);
        JSNode(JSContext *cx, int nodeType, JSNode *child, double datum);
        JSNode(JSContext *cx, int nodeType, JSNode *child, jsString_t datum);
        JSNode(JSContext *cx, int nodeType, JSNode *child, Datum *datum);
        JSNode(JSContext *cx, int nodeType, JSNode *left, JSNode *right,
                int dataum);
        JSNode(JSContext *cx, int nodeType, JSNode *left, JSNode *right,
                double datum);
        JSNode(JSContext *cx, int nodeType, JSNode *left, JSNode *right,
                jsString_t datum);

        void    destroy(JSContext *cx);
        void    addRef();
        void    release(JSContext *cx);

        int     getType();
        void    setType(int type);
        jsBool_t
                hasChildren();
        JSNode  *getFirstChild();
        JSNode  *getLastChild();
        JSNode  *getNextSibling();
        JSNode  *getChildBefore(JSNode *child);
        JSNode  *getLastSibling();
        JSShallowNodeIterator
                getChildIterator();
        JSPreorderNodeIterator
                getPreorderIterator(JSContext *cx);
        void    addChildToFront(JSNode *child);
        void    addChildToBack(JSNode *child);
        void    addChildrenToFront(JSNode *children);
        void    addChildrenToBack(JSNode *children);
        void    addChildBefore(JSNode *newChild, JSNode *node);
        void    addChildAfter(JSNode *newChild, JSNode *node);
        void    removeChild(JSNode *child);
        void    replaceChild(JSNode *child, JSNode *newChild);
        void    removeChildren();
        jsBool_t
                getProp(int propType, int *prop);
        jsBool_t
                getProp(int propType, double *prop);
        jsBool_t
                getProp(int propType, jsString_t *prop);
        jsBool_t
                getProp(int propType, JSNode **prop);
        jsBool_t
                getProp(int propType, Vector **prop);
        jsBool_t
                getProp(int propType, JSVariableTable **prop);
        jsBool_t
                getProp(int propType, jsString_t *prop, int *propLength);
        Datum   *getProp(int propType);
        void    putProp(JSContext *cx, int propType, int prop);
        void    putProp(JSContext *cx, int propType, jsString_t prop);
        void    putProp(JSContext *cx, int propType, JSNode *prop);
        void    putProp(JSContext *cx, int propType, Vector *prop);
        void    putProp(JSContext *cx, int propType, JSVariableTable *prop);
        void    putProp(JSContext *cx, int propType, jsString_t prop,
                        int propLength);
        void    putProp(JSContext *cx, int propType, Datum *prop);
        void    delProp(int propType);

        jsBool_t
                getDatum(int *datum);
        jsBool_t
                getDatum(double *datum);
        jsBool_t
                getDatum(jsString_t *datum);
        Datum   *getDatum();
        void    setDatum(JSContext *cx, int datum);
        int     getInt();
        double  getDouble();
        int64_t getLong();
        jsString_t
                 getString();
        JSNode  *cloneNode(JSContext *cx);
        jsString_t
                toString(JSContext *cx);
        jsString_t
                toStringTree(JSContext *cx);
        JSNode  *getFirst();
        JSNode  *getNext();

        /* instanceof methods */
        jsBool_t
                isInstanceOf(const jsString_t className);
} ;

/* Inlines */
#ifdef FASTER
inline int
JSNode::getType()
{
    return type;
}
inline void
JSNode::setType(int type)
{
    this->type = type;
}
#endif /* FASTER */

#endif /* _JS_NODE_H_ */

