#include "qjs_js.h"
#include "jsffi.h"

JSC_CCALL(os_gc, JS_RunGC(JS_GetRuntime(js)) )
JSC_CCALL(os_mem_limit, JS_SetMemoryLimit(JS_GetRuntime(js), js2number(js,argv[0])))
JSC_CCALL(os_gc_threshold, JS_SetGCThreshold(JS_GetRuntime(js), js2number(js,argv[0])))
JSC_CCALL(os_max_stacksize, JS_SetMaxStackSize(JS_GetRuntime(js), js2number(js,argv[0])))

JSC_CCALL(os_calc_mem,
  JSMemoryUsage mu;
  JS_ComputeMemoryUsage(JS_GetRuntime(js),&mu);
  ret = JS_NewObject(js);
  JS_SetPropertyStr(js,ret,"malloc_size",number2js(js,mu.malloc_size));
  JS_SetPropertyStr(js,ret,"malloc_limit",number2js(js,mu.malloc_limit));
  JS_SetPropertyStr(js,ret,"memory_used_size",number2js(js,mu.memory_used_size));
  JS_SetPropertyStr(js,ret,"malloc_count",number2js(js,mu.malloc_count));
  JS_SetPropertyStr(js,ret,"memory_used_count",number2js(js,mu.memory_used_count));
  JS_SetPropertyStr(js,ret,"atom_count",number2js(js,mu.atom_count));
  JS_SetPropertyStr(js,ret,"atom_size",number2js(js,mu.atom_size));
  JS_SetPropertyStr(js,ret,"str_count",number2js(js,mu.str_count));
  JS_SetPropertyStr(js,ret,"str_size",number2js(js,mu.str_size));
  JS_SetPropertyStr(js,ret,"obj_count",number2js(js,mu.obj_count));
  JS_SetPropertyStr(js,ret,"obj_size",number2js(js,mu.obj_size));
  JS_SetPropertyStr(js,ret,"prop_count",number2js(js,mu.prop_count));
  JS_SetPropertyStr(js,ret,"prop_size",number2js(js,mu.prop_size));
  JS_SetPropertyStr(js,ret,"shape_count",number2js(js,mu.shape_count));
  JS_SetPropertyStr(js,ret,"shape_size",number2js(js,mu.shape_size));
  JS_SetPropertyStr(js,ret,"js_func_count",number2js(js,mu.js_func_count));
  JS_SetPropertyStr(js,ret,"js_func_size",number2js(js,mu.js_func_size));
  JS_SetPropertyStr(js,ret,"js_func_code_size",number2js(js,mu.js_func_code_size));
  JS_SetPropertyStr(js,ret,"js_func_pc2line_count",number2js(js,mu.js_func_pc2line_count));
  JS_SetPropertyStr(js,ret,"js_func_pc2line_size",number2js(js,mu.js_func_pc2line_size));
  JS_SetPropertyStr(js,ret,"c_func_count",number2js(js,mu.c_func_count));
  JS_SetPropertyStr(js,ret,"array_count",number2js(js,mu.array_count));
  JS_SetPropertyStr(js,ret,"fast_array_count",number2js(js,mu.fast_array_count));
  JS_SetPropertyStr(js,ret,"fast_array_elements",number2js(js,mu.fast_array_elements));
  JS_SetPropertyStr(js,ret,"binary_object_count",number2js(js,mu.binary_object_count));
  JS_SetPropertyStr(js,ret,"binary_object_size",number2js(js,mu.binary_object_size));
)

JSC_SSCALL(os_eval,
  ret = JS_Eval(js,str2,strlen(str2),str, 0);
)

JSC_SSCALL(js_compile,
  ret = JS_Eval(js, str2, strlen(str2), str, JS_EVAL_FLAG_COMPILE_ONLY);
)

JSC_CCALL(js_eval_compile,
  JS_DupValue(js,argv[0]);
  ret = JS_EvalFunction(js, argv[0]);
)

#include "qjs_blob.h"

JSC_CCALL(js_compile_blob,
  JSRuntime *rt = JS_GetRuntime(js);
//  JS_SetStripInfo(rt, JS_STRIP_SOURCE);
//  JS_SetStripInfo(rt, JS_STRIP_DEBUG);
  size_t size;
  uint8_t *data = JS_WriteObject(js, &size, argv[0], JS_WRITE_OBJ_BYTECODE);
  if (!data) {
    return JS_ThrowInternalError(js, "Failed to serialize bytecode");
  }
  ret = js_new_blob_stoned_copy(js, data, size);
  js_free(js, data);
)

JSC_CCALL(js_compile_unblob,
  size_t size;
  void *data = js_get_blob_data(js, &size, argv[0]);
  if (!data) return JS_ThrowReferenceError(js, "Must be a stoned blob.");
  
  return JS_ReadObject(js, data, size, JS_READ_OBJ_BYTECODE);
)

JSC_CCALL(js_disassemble,
  return js_debugger_fn_bytecode(js, argv[0]);
)

JSC_CCALL(js_fn_info,
  return js_debugger_fn_info(js, argv[0]);
)

static const JSCFunctionListEntry js_js_funcs[] = {
  MIST_FUNC_DEF(os, calc_mem, 0),
  MIST_FUNC_DEF(os, mem_limit, 1),
  MIST_FUNC_DEF(os, gc_threshold, 1),
  MIST_FUNC_DEF(os, max_stacksize, 1),
  MIST_FUNC_DEF(os, gc, 0),
  MIST_FUNC_DEF(os, eval, 2),
  MIST_FUNC_DEF(js, compile, 2),
  MIST_FUNC_DEF(js, eval_compile, 1),
  MIST_FUNC_DEF(js, compile_blob, 1),
  MIST_FUNC_DEF(js, compile_unblob, 1),
  MIST_FUNC_DEF(js, disassemble, 1),
  MIST_FUNC_DEF(js, fn_info, 1),
};

JSValue js_js_use(JSContext *js) {
  JSValue mod = JS_NewObject(js);
  JS_SetPropertyFunctionList(js,mod,js_js_funcs,countof(js_js_funcs));
  return mod;
}