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

/* 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;
		int             scriptBaseLineno;
		jsString_t      interpreterSourceFile;
		jsString_t      source;
		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:
		void    setSourceInfo(jsString_t sourceStr, jsString_t sourceName, int lineno);
		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);

		/* gc methods */
		void    mark();

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

