/*
 * 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_ */

