/*
 * OperationFactoryInternal.c
 * Implementation of native methods in class
 * BR.unicamp.Guarana.OperationFactoryInternal
 *
 * Copyright 1997,1998 Alexandre Oliva <oliva@dcc.unicamp.br>
 */

/* guarana.unicamp.br/APIguarana/lib */

#include "GuaraNative.h"

#define checkTarget(obj, replaced) do { \
  if ((replaced) && (obj) != ((NativeOperation*)(replaced))->object) \
    SignalError(0, "java/lang/IllegalAccessException", \
		"target Object changed"); \
} while (0)

#define checkCompat(clazz, op) do { \
  if (op && ((NativeOperation *)op)->kind != op_nop) { \
    Hjava_lang_Class *orig = BR_unicamp_Guarana_Operation_getType(op); \
    if (!jboolean_do_execute_java_method(0, (jobject)orig, "isAssignableFrom", "(Ljava/lang/Class;)Z", 0, 0, clazz)) \
      SignalError(0, "java/lang/IllegalArgumentException", "incompatible result types"); \
  } \
} while (0)

#define checkMobj(this) do { \
  if (this->obj->meta_object != this->mobj) \
    SignalError(0, "java/lang/IllegalAccessException", "MetaObject changed"); \
} while (0)

struct Hjava_lang_Object* BR_unicamp_Guarana_OperationFactoryInternal_getObject(struct HBR_unicamp_Guarana_OperationFactoryInternal* this_) {
  OperationFactory *this = (OperationFactory*)this_;
  return this->obj;
}

struct HBR_unicamp_Guarana_Operation* BR_unicamp_Guarana_OperationFactoryInternal_nop(struct HBR_unicamp_Guarana_OperationFactoryInternal* this_) {
  OperationFactory *this = (OperationFactory*)this_;
  NativeOperation *op;
  op = guarana_new_native_operation(this->obj, CURRENTTHREAD(), 0);
  op->kind = op_nop;

  return (struct HBR_unicamp_Guarana_Operation*)op;
}

struct HBR_unicamp_Guarana_Operation* BR_unicamp_Guarana_OperationFactoryInternal_invoke(struct HBR_unicamp_Guarana_OperationFactoryInternal *this_, struct Hjava_lang_reflect_Method *meth, HArrayOfObject *arguments, struct HBR_unicamp_Guarana_Operation *repl) {
  OperationFactory *this = (OperationFactory*)this_;
  NativeOperation *op;
  jint i, len;
  struct wrapArgVec *argvec;
  
  checkMobj(this);
  checkCompat(unhand(meth)->returnType, repl);
  checkTarget(this->obj, repl);
  op = guarana_new_native_operation(this->obj, CURRENTTHREAD(), repl);
  op->kind = op_method_invocation | op_wrapped;
  op->op_id.method = CLASS_METHODS(unhand(meth)->clazz) + unhand(meth)->slot;

  /* FIXME: access array reflexively? */
  len = obj_length(arguments);
  argvec = gc_malloc(sizeof(*argvec) + (len-1)*sizeof(argvec->args), &gcNormal);
  argvec->len = len;

  for(i = 0; i < len; ++i)
    argvec->args[i] = arguments->data[i].body[0];
  
  SOFT_ADDREFERENCE(op, argvec);
  op->op_arg.argvec = argvec;

  return (struct HBR_unicamp_Guarana_Operation*)op;
}

struct HBR_unicamp_Guarana_Operation* BR_unicamp_Guarana_OperationFactoryInternal_construct(struct HBR_unicamp_Guarana_OperationFactoryInternal *this_, struct Hjava_lang_reflect_Constructor *constr, HArrayOfObject *arguments, struct HBR_unicamp_Guarana_Operation *repl) {
  OperationFactory *this = (OperationFactory*)this_;
  NativeOperation *op;
  int i, len;
  struct wrapArgVec *argvec;
  
  checkMobj(this);
  checkCompat(&voidClass, repl);
  checkTarget(this->obj, repl);
  op = guarana_new_native_operation(this->obj, CURRENTTHREAD(), repl);
  op->kind = op_constructor_invocation | op_wrapped;
  op->op_id.method = CLASS_METHODS(unhand(constr)->clazz) + unhand(constr)->slot;

  /* FIXME: access array reflexively? */
  len = obj_length(arguments);
  argvec = gc_malloc(sizeof(*argvec) + (len-1)*sizeof(argvec->args), &gcNormal);
  argvec->len = len;
  
  for(i = 0; i < len; ++i)
    argvec->args[i] = arguments->data[i].body[0];
  
  SOFT_ADDREFERENCE(op, argvec);
  op->op_arg.argvec = argvec;

  return (struct HBR_unicamp_Guarana_Operation*)op;
}

struct HBR_unicamp_Guarana_Operation* BR_unicamp_Guarana_OperationFactoryInternal_monitorEnter(struct HBR_unicamp_Guarana_OperationFactoryInternal *this_, struct HBR_unicamp_Guarana_Operation *repl) {
  OperationFactory *this = (OperationFactory*)this_;
  NativeOperation *op;
  
  checkMobj(this);
  checkCompat(&voidClass, repl);
  checkTarget(this->obj, repl);
  op = guarana_new_native_operation(this->obj, CURRENTTHREAD(), repl);
  op->kind = op_monitor_enter;

  return (struct HBR_unicamp_Guarana_Operation*)op;
}

struct HBR_unicamp_Guarana_Operation* BR_unicamp_Guarana_OperationFactoryInternal_monitorExit(struct HBR_unicamp_Guarana_OperationFactoryInternal *this_, struct HBR_unicamp_Guarana_Operation *repl) {
  OperationFactory *this = (OperationFactory*)this_;
  NativeOperation *op;
  
  checkMobj(this);
  checkCompat(&voidClass, repl);
  checkTarget(this->obj, repl);
  op = guarana_new_native_operation(this->obj, CURRENTTHREAD(), repl);
  op->kind = op_monitor_exit;

  return (struct HBR_unicamp_Guarana_Operation*)op;
}

struct HBR_unicamp_Guarana_Operation* BR_unicamp_Guarana_OperationFactoryInternal_read(struct HBR_unicamp_Guarana_OperationFactoryInternal *this_, struct Hjava_lang_reflect_Field *field, struct HBR_unicamp_Guarana_Operation *repl) {
  OperationFactory *this = (OperationFactory*)this_;
  NativeOperation *op;
  
  checkMobj(this);
  checkCompat(unhand(field)->type, repl);
  checkTarget(this->obj, repl);
  op = guarana_new_native_operation(this->obj, CURRENTTHREAD(), repl);
  op->kind = op_field_read;
  op->op_id.field_id.clazz = unhand(field)->clazz;
  op->op_id.field_id.field = unhand(field)->clazz->fields + unhand(field)->slot;

  return (struct HBR_unicamp_Guarana_Operation*)op;
}

struct HBR_unicamp_Guarana_Operation* BR_unicamp_Guarana_OperationFactoryInternal_write(struct HBR_unicamp_Guarana_OperationFactoryInternal *this_, struct Hjava_lang_reflect_Field *field, struct Hjava_lang_Object *value, struct HBR_unicamp_Guarana_Operation *repl) {
  OperationFactory *this = (OperationFactory*)this_;
  NativeOperation *op;
  
  checkMobj(this);
  checkCompat(&voidClass, repl);
  checkTarget(this->obj, repl);
  op = guarana_new_native_operation(this->obj, CURRENTTHREAD(), repl);
  op->kind = op_field_read | op_wrapped;
  op->op_id.field_id.clazz = unhand(field)->clazz;
  op->op_id.field_id.field = unhand(field)->clazz->fields + unhand(field)->slot;
  op->op_arg.object_value = value;
  return (struct HBR_unicamp_Guarana_Operation*)op;
}

struct HBR_unicamp_Guarana_Operation* BR_unicamp_Guarana_OperationFactoryInternal_length(struct HBR_unicamp_Guarana_OperationFactoryInternal *this_, struct HBR_unicamp_Guarana_Operation *repl) {
  OperationFactory *this = (OperationFactory*)this_;
  NativeOperation *op;
  
  checkMobj(this);
  checkCompat(&intClass, repl);
  checkTarget(this->obj, repl);
  op = guarana_new_native_operation(this->obj, CURRENTTHREAD(), repl);
  op->kind = op_array_length;

  return (struct HBR_unicamp_Guarana_Operation*)op;
}

struct HBR_unicamp_Guarana_Operation* BR_unicamp_Guarana_OperationFactoryInternal_readElement(struct HBR_unicamp_Guarana_OperationFactoryInternal *this_, jint elmt, struct HBR_unicamp_Guarana_Operation *repl) {
  OperationFactory *this = (OperationFactory*)this_;
  NativeOperation *op;
  
  checkMobj(this);
  checkCompat(CLASS_ELEMENT_TYPE(OBJECT_CLASS(this->obj)), repl);
  checkTarget(this->obj, repl);
  op = guarana_new_native_operation(this->obj, CURRENTTHREAD(), repl);
  op->kind = op_array_read;
  op->op_id.index = elmt;

  return (struct HBR_unicamp_Guarana_Operation*)op;
}

struct HBR_unicamp_Guarana_Operation* BR_unicamp_Guarana_OperationFactoryInternal_writeElement(struct HBR_unicamp_Guarana_OperationFactoryInternal *this_, jint elmt, struct Hjava_lang_Object *value, struct HBR_unicamp_Guarana_Operation *repl) {
  OperationFactory *this = (OperationFactory*)this_;
  NativeOperation *op;
  
  checkMobj(this);
  checkCompat(&voidClass, repl);
  checkTarget(this->obj, repl);
  op = guarana_new_native_operation(this->obj, CURRENTTHREAD(), repl);
  op->kind = op_array_write | op_wrapped;
  op->op_id.index = elmt;
  op->op_arg.object_value = value;

  return (struct HBR_unicamp_Guarana_Operation*)op;
}
