#ifdef JS_THREADSAFE
class JSBlocker
{public:
 JSContext * c;
 JSBlocker(JSContext* cx) {JS_BeginRequest(cx);c=cx;}
 ~JSBlocker() {JS_EndRequest(c);}
};
class JSWaiter
{public:
 jsrefcount saveDepth;
 JSContext * c;
 JSWaiter(JSContext* cx) {saveDepth = JS_SuspendRequest(cx);c=cx;}
 ~JSWaiter() {JS_ResumeRequest(c,saveDepth);}
};
#endif

class JSRoot
{public:
 void* o;
 JSContext* c;
 JSRoot(JSContext* cx,void* obj): c(cx), o(obj)
  {o = JS_AddRoot(cx,&o) ? obj : NULL;}
 ~JSRoot()
  {o = o ? JS_RemoveRoot(c,&o),(void*)NULL: o;}
};

JSBool SuspendGC(JSContext*cx, JSGCStatus flags);

class JSBlockGC
{public:
 JSContext* c;
 JSGCCallback old;
 JSBlockGC(JSContext* cx): c(cx)
  {old = JS_SetGCCallback(cx,SuspendGC);}
 ~JSBlockGC()
  {JS_SetGCCallback(c,old);}
};

#ifdef JS_THREADSAFE
#define ENTERNATIVE(cx) JSBlockGC __BlockGC(cx); JSBlocker __Blocker(cx); TList<JSRoot> __Roots
#else
#define ENTERNATIVE(cx) JSBlockGC __BlockGC(cx); TList<JSRoot> __Roots
#endif

#define ROOT(x) (__Roots.Add(new JSRoot(cx,x)),x)

#define ISDBL(x) JSVAL_IS_DOUBLE(argv[x])
#define ISINT(x) JSVAL_IS_INT(argv[x])
#define ISSTR(x) JSVAL_IS_STRING(argv[x])
#define ISBOOL(x) JSVAL_IS_BOOLEAN(argv[x])

#define ISOBJ(x) JSVAL_IS_OBJECT(argv[x])

#define TOBOOL(x,y) JS_ValueToBoolean(cx,argv[x],&y)
#define TOINT(x,y) JS_ValueToInt32(cx,argv[x],&y)
#define TODBL(x,y) JS_ValueToNumber(cx,argv[x],&y)

#define GETPRIVATE(x,obj) (((JSPointer<x>*)JS_GetPrivate(cx,obj))->P)
#define GETPOINTER (((JSPointerBase*)JS_GetPrivate(cx,obj)))

#define SETPRIVATE(obj,x,t,ad,parent) \
 JS_SetPrivate(cx,obj,new JSPointer<x>(parent,t,ad))

#define DELPRIVATE(x) \
JSPointer<x> * t = \
   (JSPointer<x>*)JS_GetPrivate(cx,obj);\
 if (t) delete t; t=0; JS_SetPrivate(cx,obj,NULL)

#define CLOSEPRIVATE(x) \
JSPointer<x> * t = \
   (JSPointer<x>*)JS_GetPrivate(cx,obj);\
 if (t) t->Close()

#ifdef JS_THREADSAFE
#define MAKENEW(name) \
obj = ROOT(JS_NewObject(cx, JS_GetClass(cx,Env->o##name),Env->o##name, NULL));\
JS_DefineFunctions(cx,obj,name ## _functions);\
JS_DefineProperties(cx,obj,name ## _properties)
#else
#define MAKENEW(name) \
obj = JS_NewObject(cx, JS_GetClass(Env->o##name),Env->o##name, NULL);\
JS_DefineFunctions(cx,obj,name ## _functions);\
JS_DefineProperties(cx,obj,name ## _properties)
#endif
#define INITCLASS(name) \
 Env->o##name = JS_InitClass(cx, obj, NULL, name ## _Class(),\
 name ## _ ## name, 0,\
 name ## _properties, name ## _functions,NULL,name ## _fnstatic);

#define GETREC(x,y)  \
{JSObject* jx = x < argc && JSVAL_IS_OBJECT(argv[x])? JSVAL_TO_OBJECT(argv[x]) : NULL; \
 if (jx) {if (JS_InstanceOf(cx,jx,Record_Class(),0)) \
  y = GETPRIVATE(TParameterList,jx);} \
 else y = NULL;\
}
               
#define GETFORM(x,y)  \
{JSObject* jx = x < argc && JSVAL_IS_OBJECT(argv[x])? JSVAL_TO_OBJECT(argv[x]) : NULL; \
 if (jx) {if (JS_InstanceOf(cx,jx,Form_Class(),0)) \
  y = GETPRIVATE(EZFForm,jx);} \
 else y = NULL;\
}

#define GETTABLE(x,y)  \
{JSObject* jx = x < argc && JSVAL_IS_OBJECT(argv[x])? JSVAL_TO_OBJECT(argv[x]) : NULL; \
 if (jx) {if (JS_InstanceOf(cx,jx,Table_Class(),0)) \
  y = GETPRIVATE(DataTable,jx);} \
 else y = NULL;\
}

#define GETFILE(x,y)  \
{JSObject* jx = x < argc&& JSVAL_IS_OBJECT(argv[x]) ? JSVAL_TO_OBJECT(argv[x]) : NULL; \
 if (jx && JS_InstanceOf(cx,jx,Stream_Class(),0)) \
  y = GETPRIVATE(Stream,jx); \
 else y = NULL;\
}

#define GETSTRING(x) \
 {j ## x = argc > x ? JS_ValueToString(cx,argv[x]) : 0; \
  s ## x = (j ## x) ? JS_GetStringBytes(j ## x) : 0;}

#define GETUTF8(x) \
 JSString* j ## x = argc > x ? JS_ValueToString(cx,argv[x]) : 0; \
  TStr s ## x( (j ## x) ? JS_GetStringChars(j ## x) : (jschar*)0, \
   (j ## x) ? JS_GetStringLength(j ## x) : 0)

#define GETUCS2(x) \
 JSString* j ## x = argc > x ? JS_ValueToString(cx,argv[x]) : 0; \
  uint16* s ## x = (j ## x) ? (uint16*)JS_GetStringChars(j ## x) : (uint16*)0

// JSString* j ## x = argc > x ? JS_ValueToString(cx,argv[x]) : 0; 
//  TStr s ## x( (j ## x) ? JS_GetStringBytes(j ## x) : (char*)0)

#define INT(x) JSVAL_TO_INT(argv[x])
#define STR(x) JS_GetStringBytes(JSVAL_TO_STRING(argv[x]))
#define WSTR(x) JS_GetStringChars(JSVAL_TO_STRING(argv[x]))
#define UTF8STR(x) TStr(JS_GetStringChars(JSVAL_TO_STRING(argv[x])))
//#define DBL(x) JSVAL_TO_DOUBLE(argv[x])
//#define TF(x) JSVAL_TO_BOOLEAN(argv[x])

#define RETSTRW(x) \
{JSString*str = JS_NewUCStringCopyZ(cx,x); \
 if (!str) return JS_FALSE; \
 *rval = STRING_TO_JSVAL(str); \
 return JS_TRUE; }
                      
#define RETSTRWN(x,n) \
{JSString*str = JS_NewUCStringCopyN(cx,x,n); \
 if (!str) return JS_FALSE; \
 *rval = STRING_TO_JSVAL(str); \
 return JS_TRUE; }

#define RETSTR(x) \
{JSString*str = JS_NewStringCopyZ(cx,x); \
 if (!str) return JS_FALSE; \
 *rval = STRING_TO_JSVAL(str); \
 return JS_TRUE; }

#define RETSTRN(x,n) \
{JSString*str = JS_NewStringCopyN(cx,x,n); \
 if (!str) return JS_FALSE; \
 *rval = STRING_TO_JSVAL(str); \
 return JS_TRUE; }

#define RETBOOL(x) {*rval = BOOLEAN_TO_JSVAL(x); return JS_TRUE ;}

#define RETOBJ(x) {*rval = OBJECT_TO_JSVAL(x); return JS_TRUE;}

#define RETINT(x) {*rval = INT_TO_JSVAL(x); return JS_TRUE;}

#define GETOBJ(type,name) type * name = NULL;\
 JSPointer<type> *ptr_ ## name = (JSPointer<type>*)JS_GetPrivate(cx,obj); \
 if (ptr_ ## name) name = *ptr_ ## name;\
 if (!name) return JS_FALSE

#define MAYBEGC \
 if (++Env->GCTimer > (2<<10)) {Env->GCTimer=0;JS_MaybeGC(cx);}

#define GETENV \
 JSDBEnvironment* Env = (JSDBEnvironment*)JS_GetContextPrivate(cx);\
 MAYBEGC

#define WRITELN(x) {if (Env->out) Env->out->writestr(x,"\n");}

#define ERR_COUNT(class,name) \
 {JS_ReportError(cx,"Wrong number of parameters in call to %s.%s",#class,#name); \
 return JS_FALSE; }

#define ERR_TYPE(class,name,index,type) \
 {JS_ReportError(cx,"Expected a %s in parameter %d for %s.%s",#type,index,#class,#name); \
 return JS_FALSE; }

#define ERR_MSG(class,name,msg) \
 { JS_SetPendingException(cx,STRING_TO_JSVAL(JS_NewStringCopyZ(cx,TStr(#class ":" #name " (", msg, ")"))));\
  *rval = OBJECT_TO_JSVAL(NULL); return JS_FALSE; }
/*JS_ReportError(cx,"%s.%s: %s",#class,#name,msg); */

/*#define WARN_MSG(class,name,msg) \
 {JS_ReportError(cx,"%s.%s: %s",#class,#name,msg); \
 return JS_TRUE; } */

#define WRAP(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \

#define CALL(class,name) \
class ## _ ## name(cx, obj, argc, argv, rval) 

#define I_WRAP_S(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc != 1) ERR_COUNT(class,name); \
 if (!ISSTR(0)) ERR_TYPE(class,name,1,string); \
 GETOBJ(class,t); \
 RETINT(t->name(STR(0))); \
}

#define B_WRAP_S(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc != 1) ERR_COUNT(class,name); \
 if (!ISSTR(0)) ERR_TYPE(class,name,1,string); \
 GETOBJ(class,t); \
 RETBOOL(t->name(TStr(WSTR(0)))); \
}

#define B_WRAP_SET_R(class,list,name) \
static JSBool class ## _set ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc != 2) ERR_COUNT(class,name); \
 int32 index; TParameterList * r1; \
 if (!TOINT(0,index)) ERR_TYPE(class,name,1,integer); \
 GETREC(1,r1); if (!r1) ERR_TYPE(class,name,2,record); \
 GETOBJ(class,t);\
 if (t->list[index] == NULL) RETBOOL(false);\
 if (&t->list[index]->name == r1) RETBOOL(true);\
 t->list[index]->name.Clear();\
 t->list[index]->name = *r1;\
 RETBOOL(true);\
}

#define R_WRAP_GET(class,list,name) \
static JSBool class ## _get ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc != 1) ERR_COUNT(class,name); \
 int32 index; TParameterList * r1; \
 if (!TOINT(0,index)) ERR_TYPE(class,name,1,integer); \
 if (argc == 2)\
 {GETREC(1,r1); if (!r1) ERR_TYPE(class,name,2,record); }\
 GETOBJ(class,t);\
 if (t->list[index] == NULL) RETOBJ(NULL); \
 if (r1) \
  {*r1 = t->list[index]->Responses; RETOBJ(NULL); }\
 else \
  {RETOBJ(Record_Object(cx,&t->list[index]->name,false,ptr_t));}\
}

#define B_WRAP_SET_S(class,list,name) \
static JSBool class ## _set ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{int32 index; \
 if (argc != 2) ERR_COUNT(class,name); \
 if (!TOINT(0,index)) ERR_TYPE(class,name,1,string); \
 if (!ISSTR(1)) ERR_TYPE(class,name,1,string); \
 GETOBJ(class,t); \
 if (t->list[index] == NULL) RETBOOL(false);\
 t->list[index]->name= TStr(WSTR(1));\
 RETBOOL(true);\
}

#define S_WRAP_GET(class,list,name) \
static JSBool class ## _get ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{int32 index; \
 if (argc != 1) ERR_COUNT(class,name); \
 if (!TOINT(0,index)) ERR_TYPE(class,name,1,string); \
 GETOBJ(class,t); \
 if (t->list[index] == NULL) RETSTR("");\
 RETSTRW(WStr(t->list[index]->name));\
}

#define B_WRAP_SET_I(class,list,name) \
static JSBool class ## _set ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{int32 index; \
 if (argc != 2) ERR_COUNT(class,name); \
 if (!TOINT(0,index)) ERR_TYPE(class,name,1,string); \
 if (!ISINT(1)) ERR_TYPE(class,name,1,integer); \
 GETOBJ(class,t); \
 if (t->list[index] == NULL) RETBOOL(false);\
 t->list[index]->name = INT(1);\
 RETBOOL(true);\
}

#define I_WRAP_GET(class,list,name) \
static JSBool class ## _get ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{int32 index; \
 if (argc != 1) ERR_COUNT(class,name); \
 if (!TOINT(0,index)) ERR_TYPE(class,name,1,string); \
 GETOBJ(class,t); \
 if (t->list[index] == NULL) RETBOOL(false);\
 RETINT(t-> list [index]-> name);\
}

#define B_WRAP_S_F(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc == 0 || argc > 2) ERR_COUNT(class,name); \
 if (!ISSTR(0)) ERR_TYPE(class,name,1,string); \
 Stream* out = 0; \
 if (argc == 2) GETFILE(1,out); \
 GETOBJ(class,t); \
 RETBOOL(t->name(STR(0),out)); \
}

#define B_WRAP_IR(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc != 2) ERR_COUNT(class,name); \
 int32 v0; TParameterList * r1; \
 if (!TOINT(0,v0)) ERR_TYPE(class,name,1,integer); \
 GETREC(1,r1); if (!r1) ERR_TYPE(class,name,2,record); \
 GETOBJ(class,t);\
 RETBOOL(t->name(v0,*r1)); \
}

#define C_WRAP_S(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc != 1) ERR_COUNT(class,name); \
 if (!ISSTR(0)) ERR_TYPE(class,name,1,string);\
 char s[2]; s[1]=0; \
 GETOBJ(class,t);\
 s[0] = t->name(STR(0)); \
 RETSTR(s); \
}

#define C_WRAP_V(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc != 0) ERR_COUNT(class,name); \
 char s[2]; s[1]=0; \
 GETOBJ(class,t);\
 s[0] = t->name(); \
 RETSTR(s); \
}

#define V_WRAP_C(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc != 1) ERR_COUNT(class,name); \
 GETOBJ(class,t);\
 if (!ISSTR(0)) ERR_TYPE(class,name,1,string); \
 t->name((STR(0))[0]); \
 RETBOOL(true);\
}

#define DECLARE_WRAP(class,name) \
JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval);

#define I_WRAP_R(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc != 1) ERR_COUNT(class,name); \
 TParameterList * r1; \
 GETREC(0,r1); if (!r1) ERR_TYPE(class,name,1,record); \
 GETOBJ(class,t);\
 RETINT(t->name(*r1)); \
}

#define I_WRAP_F(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc != 1) ERR_COUNT(class,name); \
 Stream * r1; \
 GETFILE(0,r1); \
 if (!r1) ERR_TYPE(class,name,1,stream); \
 GETOBJ(class,t);\
 RETINT(t->name(*r1)); \
}

#define B_WRAP_IS(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc != 2) ERR_COUNT(class,name); \
 int32 v0;\
 if (!TOINT(0,v0)) ERR_TYPE(class,name,1,integer); \
 if (!ISSTR(1)) ERR_TYPE(class,name,2,string); \
 GETOBJ(class,t); \
 RETBOOL(t->name(v0,STR(1))); \
}

#define I_WRAP_SS(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc != 2) ERR_COUNT(class,name); \
 int32 v1;\
 if (!ISSTR(0)) ERR_TYPE(class,name,1,string); \
 if (!ISSTR(1)) ERR_TYPE(class,name,2,string); \
 GETOBJ(class,t); \
 RETINT(t->name(STR(0),STR(1))); \
}

#define V_WRAP_SS(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc != 2) ERR_COUNT(class,name); \
 int32 v1;\
 if (!ISSTR(0)) ERR_TYPE(class,name,1,string); \
 if (!ISSTR(1)) ERR_TYPE(class,name,2,string); \
 GETOBJ(class,t); \
 t->name(STR(0),STR(1)); \
 RETBOOL(true); \
}

#define V_WRAP_II(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc != 2) ERR_COUNT(class,name); \
 int32 v1;\
 if (!ISINT(0)) ERR_TYPE(class,name,1,integer); \
 if (!ISINT(1)) ERR_TYPE(class,name,2,integer); \
 GETOBJ(class,t); \
 t->name(INT(0),INT(1)); \
 RETBOOL(true); \
}

#define V_WRAP_I(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc != 1) ERR_COUNT(class,name); \
 int32 v1;\
 if (!ISINT(0)) ERR_TYPE(class,name,1,integer); \
 GETOBJ(class,t); \
 t->name(INT(0)); \
 RETBOOL(true); \
}

#define V_WRAP_S(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc != 1) ERR_COUNT(class,name); \
 int32 v1;\
 if (!ISSTR(0)) ERR_TYPE(class,name,1,string); \
 GETOBJ(class,t); \
 t->name(STR(0)); \
 RETBOOL(true); \
}

#define B_WRAP_I(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc == 0) ERR_COUNT(class,name); \
 int32 v1;\
 if (!TOINT(0,v1)) ERR_TYPE(class,name,1,integer); \
 GETOBJ(class,t); \
 RETBOOL(t->name(v1)); \
}

#define S_WRAP_I(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc == 0)  ERR_COUNT(class,name); \
 int32 v1; if (!TOINT(0,v1)) ERR_TYPE(class,name,1,integer); \
 GETOBJ(class,t); \
 RETSTR(t->name(v1)); \
}


#define S_WRAP_II(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc == 0)  ERR_COUNT(class,name); \
 int32 v1; if (!TOINT(0,v1)) ERR_TYPE(class,name,1,integer); \
 int32 v2; if (!TOINT(0,v2)) ERR_TYPE(class,name,2,integer); \
 GETOBJ(class,t); \
 RETSTR(t->name(v1,v2)); \
}


#define S_WRAP_II(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc == 0)  ERR_COUNT(class,name); \
 int32 v1; if (!TOINT(0,v1)) ERR_TYPE(class,name,1,integer); \
 int32 v2; if (!TOINT(0,v2)) ERR_TYPE(class,name,2,integer); \
 GETOBJ(class,t); \
 RETSTR(t->name(v1,v2)); \
}



#define I_WRAP_I(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc == 0) ERR_COUNT(class,name); \
 int32 v1; if (!TOINT(0,v1)) ERR_TYPE(class,name,1,integer); \
 GETOBJ(class,t); \
 RETINT(t->name(v1)); \
}


#define I_WRAP_V(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 if (argc != 0) ERR_COUNT(class,name); \
 GETOBJ(class,t); \
 RETINT(t->name()); \
}

#define S_WRAP_V(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 GETOBJ(class,t); \
 RETSTR(t->name()); \
}

#define B_WRAP_V(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 GETOBJ(class,t); \
 RETBOOL(t->name()); \
}

#define V_WRAP_V(class,name) \
static JSBool class ## _ ## name(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ \
 GETOBJ(class,t); \
 t->name(); \
 RETBOOL(true); \
}

#define WRAP_HELP(class,text) \
static JSBool class ## _HELP(JSContext *cx, \
 JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
{ RETSTR(text); }

