/*
 * 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_CONTEXT_H_
#define _JS_CONTEXT_H_

#include <stdarg.h>
#include <lstLib.h>
#include <assert.h>
#include <pthread.h>
#include "js-types.h"
#include "js-runtimenew.h"
#include "js-zone.h"
#ifdef PERSIST
# include "js-randomwriter.h"
# include "js-randomreader.h"
#endif

/* Classes */
class JSRuntime;
class JSErrorReporter;
class JSRegExpProxy;
class JSNativeCall;
class JSIterating;
class JSScriptable;
class JSScriptableObject;
class JSExceptionHandler;
class JSRuntimeException;
class JSNativeFunction;
class JSTokenStream;
class JSEvaluatorException;
class JSScript;
class JSFunction;
class JSInterpreter;
class JSInterpreterData;
class JSVariableTable;
class JSFrame;
class JSReader;
class JSValStack;

class JSContext: public JSRuntimeNew, public NODE {
  friend class JSNativeDebug;
    public:
	class ZoneAllocator {
	    public:
		JSContext   *cx;

	    public:
		ZoneAllocator(JSContext *cx) {
		    this->cx = cx;
		}

		void    *allocate(size_t size) {
		    return JS_NewZoneObj(cx, size);
		}
		void    deallocate(void *obj) {
		    JS_DeleteZoneObj(cx, obj);
	 	}

	} ;
       	void  operator delete(void *ptr) {
       		assert(0);
       	}

    protected:
	static	pthread_key_t	key;
	static	int		debugLevel;

	JSErrorReporter	*errorReporter;
	pthread_t	currentThread;
	JSRegExpProxy	*regExpProxy;
	jsBool_t	compileFunctionsWithDynamicScopeFlag;
	int		optimizationLevel;
	int		enterCount;

	LIST		frames;
	LIST		interpreters;
	LIST		variableTables;

	JSValStack	*localVals;
	int		newBornsIndex;
	void		*newBorns[32];	// increased at using gc string as hash
					// value in js-scriptable object.
	void		*closure;
	
    public:
	static	const int	VERSION_UNKNOWN = -1;
	static	const int	VERSION_DEFAULT = 0;
	static	const int	VERSION_1_0 = 100;
	static	const int	VERSION_1_1 = 110;
	static	const int	VERSION_1_2 = 120;
	static	const int	VERSION_1_3 = 130;
	static	const int	VERSION_1_4 = 140;
	static	const int	VERSION_1_5 = 150;
	static	const jsBool_t	printTrees = FALSE;

	JSNativeCall	*currentActivation;
	JSIterating	*iterating;
	JSScriptable	*ctorScope;
	int		version;
	int		errorCount;
	int		interpreterLine;
	jsString_t	interpreterSourceFile;
	jsString_t	source;
	jsString_t	sourceName;
	int		lineno;
	JSRuntime	*runtime;
	JSExceptionHandler
			*exceptionHandler;
	JSZone		*zone;
	ZoneAllocator	allocator;

	JSRuntimeException	*outOfMemory;
#ifdef BRANCH
	jsBranchProc_t	branch;
	JSScript 	*currentScript;
#endif

    protected:
	JSNativeFunction *
		compile(JSScriptable *scope, JSTokenStream *ts,
			jsBool_t returnFunction);
	JSNativeFunction *
		compile(JSScriptable *scope, JSReader *in,
			jsString_t sourceName, int lineno, 
			jsBool_t returnFunction);
	void	newArrayHelper(JSScriptable *scope, JSScriptable *array);
	void	startEnter();
	void	finishExit();

    public:
	static	void	classInitialize();

	static	JSContext *
			enter(JSContext *cx);
	static	void	exit();
	static	JSContext *
			getCurrentContext();
	static	void	reportWarning(JSContext *cx, jsString_t message,
				jsString_t sourceName, int lineno,
				jsString_t lineSource, int lineOffset);
	static	void	reportWarning(JSContext *cx, jsString_t message);
	static	void	reportError(JSContext *cx, jsString_t message,
				jsString_t sourceName, int lineno,
				jsString_t lineSource, int lineOffset);
	static	void	reportError(JSContext *cx, jsString_t message);
	static	JSEvaluatorException *
			reportRuntimeError(JSContext *cx, jsString_t message,
				jsString_t sourceName, int lineno,
				jsString_t lineSource, int lineOffset);
	static	JSEvaluatorException *
			reportRuntimeError(JSContext *cx, jsString_t message);
	static	jsVal_t	getUndefinedValue();
	static	jsString_t
			getMessage(JSContext *cx, jsString_t messageId, ...);
	static	jsString_t
			getMessageV(JSContext *cx, jsString_t messageId,
				va_list ap);
	static	jsString_t
			getSourcePosition(JSContext *cx, int *linep, jsString_t *buf);
	static	jsString_t
			getSourcePosition(JSContext *cx, int *linep);

	JSContext(JSRuntime *runtime);
	virtual ~JSContext() {
	}
	
	void	cleanup();
	void	destroy(JSRuntime *runtime);

	int	getLanguageVersion();
	void	setLanguageVersion(int version) ;
	JSErrorReporter *
		getErrorReporter();
	JSErrorReporter *
		setErrorReporter(JSErrorReporter *reporter);
	JSScriptable *
		initStandardObjects(JSScriptableObject *scope);
	jsVal_t	evaluateString(JSScriptable *scope, jsString_t source,
			jsString_t sourceName, int lineno);
	jsVal_t	evaluateReader(JSScriptable *scope, JSReader *in,
			jsString_t sourceName, int lineno);
	jsBool_t
		stringIsCompilableUnit(jsString_t source);
	JSScript *
		compileReader(JSScriptable *scope, JSReader *in,
			jsString_t sourceName, int lineno);
	JSFunction *
		compileFunction(JSScriptable *scope, jsString_t source,
			jsString_t sourceName, int lineno);
	jsString_t
		decompileScript(JSScript *script, JSScriptable *scope,
			int indent);
	jsString_t
		decompileFunction(JSFunction *fun, int indent);
	jsString_t
		decompileFunctionBody(JSFunction *fun, int indent);
	JSScriptable *
		newObject(JSScriptable *scope);
	JSScriptable *
		newObject(JSScriptable *scope, jsString_t constructorName);
	JSScriptable *
		newObject(JSScriptable *scope, jsString_t constructorName,
			int numArgs, jsVal_t *args);
	JSScriptable *
		newArray(JSScriptable *scope, int length);
	JSScriptable *
		newArray(JSScriptable *scope, jsVal_t *elements,
			int elementsLength);
	jsVal_t *
		getElements(JSScriptable *object, int *elementsLength);
	jsBool_t
		toBoolean(jsVal_t value);
	double	toNumber(jsVal_t value);
	jsString_t
		toString(jsVal_t value);
	JSScriptable *
		toObject(jsVal_t value, JSScriptable *scope);
	jsVal_t	toValue(jsBool_t b);
	jsVal_t	toValue(int i);
	jsVal_t	toValue(double d);
	jsVal_t	toValue(jsString_t d);
	
	int	getOptimizationLevel();
	void	setOptimizationLevel(int optimizationLevel);
	jsBool_t
		hasCompileFunctionsWithDynamicScope();
	void	setCompileFunctionsWithDynamicScope(jsBool_t flag);
	int	getDebugLevel();
	int	setDebugLevel(int debugLevel);
	JSRegExpProxy *
		getRegExpProxy();
	jsBool_t
		isVersionECMA1();

#ifdef BRANCH
	void	setBranchCallback(jsBranchProc_t branch);
#endif
	void	setClosure(void *closure);
	void	*getClosure();
	JSFrame *
		pushFrame(JSScriptable *scope, JSScriptable *thisObj,
			int numArgs, jsVal_t *args,
			JSInterpreterData *theData);
	void	popFrame();

	void	pushLocalVals(int n);
	void	pushLocalVal(jsVal_t val);
	jsVal_t	*getLocalVals(int n);
	void	popLocalVals(int n);

	void	addInterpreter(JSInterpreter *interpreter);
	void	delInterpreter(JSInterpreter *interpreter);
	void	showIcodeSize();
	void	addVariableTable(JSVariableTable *variableTable);
	void	delVariableTable(JSVariableTable *variableTable);

	void	addNewBorn(void *newBorn);

        void    setSourceInfo(jsString_t source, jsString_t sourceName,
                        int lineno);
        void    clearSourceInfo();

	/* gc methods */
	void	mark();

#ifdef PERSIST
        /* persist methods */
        int     saveWriter( JSScriptable *scope, JSScript* script,
                        JSRandomWriter* out );
        JSScript*
                loadReader( JSScriptable *scope, JSRandomReader* in );
        jsVal_t evaluateBinary( JSScriptable *scope, void* data,
                        size_t size );
#endif
	#define ISNOT_ALPHA(a) \
                ((0x81 <= (unsigned char)(a) && (unsigned char)(a) <= 0x9F) || \
                 (0x0E <= (unsigned char)(a) && (unsigned char)(a) <= 0xFC)) ? 1 : 0)
} ;

#endif /* _JS_CONTEXT_H_ */

