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

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

#include "GuaraNative.h"

#define checkNullOp(op) do { \
  if (!(op)) \
    SignalError(0, "java/lang/NullPointerException", "null operation"); \
} while (0)

#define checkRetType(op, type) do { \
  Hjava_lang_Class *cls = BR_unicamp_Guarana_Operation_getType((op)); \
  checkNullOp((op)); \
  if (!CLASS_IS_PRIMITIVE(cls) || CLASS_PRIM_SIG(cls) != (type)) \
    SignalError(0, "java/lang/IllegalArgument", "incorrect return type"); \
} while (0)

#define checkRet(res) do { \
  if (((res)->kind & res_returned) == 0) \
    SignalError(0, "java/lang/IllegalArgument", "not a return valud"); \
} while (0)

struct HBR_unicamp_Guarana_Result* BR_unicamp_Guarana_Result_operation(struct HBR_unicamp_Guarana_Operation *op, jint mode) {
  enum result_type nmode;
  union wrapValue wrap;
  switch (mode & res_reqMask) {
  case res_noResult:
    nmode = res_noResult;
    break;
  case res_inspect:
    nmode = res_inspect;
    break;
  case res_modify:
  default:
    nmode = res_modify;
    break;
  }
  return guarana_new_result_object(nmode, op, wrap);
}

struct HBR_unicamp_Guarana_Result* BR_unicamp_Guarana_Result_returnObject(struct Hjava_lang_Object *obj, struct HBR_unicamp_Guarana_Operation *op) {
  union wrapValue wrap;
  checkNullOp(op);
  guarana_unwrap(BR_unicamp_Guarana_Operation_getType(op), &wrap, obj);
  return guarana_new_result_object(res_returned, op, wrap);
}

struct HBR_unicamp_Guarana_Result* BR_unicamp_Guarana_Result_returnBoolean(jbool res, struct HBR_unicamp_Guarana_Operation *op) {
  union wrapValue wrap;
  checkRetType(op, 'Z');
  wrap.boolean_value = res;
  return guarana_new_result_object(res_returned, op, wrap);
}

struct HBR_unicamp_Guarana_Result* BR_unicamp_Guarana_Result_returnByte(jbyte res, struct HBR_unicamp_Guarana_Operation *op) {
  union wrapValue wrap;
  checkRetType(op, 'B');
  wrap.byte_value = res;
  return guarana_new_result_object(res_returned, op, wrap);
}

struct HBR_unicamp_Guarana_Result* BR_unicamp_Guarana_Result_returnShort(jshort res, struct HBR_unicamp_Guarana_Operation *op) {
  union wrapValue wrap;
  checkRetType(op, 'S');
  wrap.short_value = res;
  return guarana_new_result_object(res_returned, op, wrap);
}

struct HBR_unicamp_Guarana_Result* BR_unicamp_Guarana_Result_returnInt(jint res, struct HBR_unicamp_Guarana_Operation *op) {
  union wrapValue wrap;
  checkRetType(op, 'I');
  wrap.int_value = res;
  return guarana_new_result_object(res_returned, op, wrap);
}

struct HBR_unicamp_Guarana_Result* BR_unicamp_Guarana_Result_returnLong(jlong res, struct HBR_unicamp_Guarana_Operation *op) {
  union wrapValue wrap;
  checkRetType(op, 'J');
  wrap.long_value = res;
  return guarana_new_result_object(res_returned, op, wrap);
}

struct HBR_unicamp_Guarana_Result* BR_unicamp_Guarana_Result_returnFloat(jfloat res, struct HBR_unicamp_Guarana_Operation *op) {
  union wrapValue wrap;
  checkRetType(op, 'F');
  wrap.float_value = res;
  return guarana_new_result_object(res_returned, op, wrap);
}

struct HBR_unicamp_Guarana_Result* BR_unicamp_Guarana_Result_returnDouble(jdouble res, struct HBR_unicamp_Guarana_Operation *op) {
  union wrapValue wrap;
  checkRetType(op, 'D');
  wrap.double_value = res;
  return guarana_new_result_object(res_returned, op, wrap);
}

struct HBR_unicamp_Guarana_Result* BR_unicamp_Guarana_Result_returnChar(jchar res, struct HBR_unicamp_Guarana_Operation *op) {
  union wrapValue wrap;
  checkRetType(op, 'C');
  wrap.char_value = res;
  return guarana_new_result_object(res_returned, op, wrap);
}

struct HBR_unicamp_Guarana_Result* BR_unicamp_Guarana_Result_returnVoid(struct HBR_unicamp_Guarana_Operation *op) {
  union wrapValue wrap;
  checkRetType(op, 'V');
  return guarana_new_result_object(res_returned, op, wrap);
}

struct HBR_unicamp_Guarana_Result* BR_unicamp_Guarana_Result_throwObject(struct Hjava_lang_Throwable *obj, struct HBR_unicamp_Guarana_Operation *op) {
  union wrapValue wrap;
  checkNullOp(op);
  wrap.object_value = obj;
  return guarana_new_result_object(res_thrown, op, wrap);
}

jint BR_unicamp_Guarana_Result_getMode(struct HBR_unicamp_Guarana_Result *this) {
  return ((NativeResult*)this)->kind;
}

struct HBR_unicamp_Guarana_Operation* BR_unicamp_Guarana_Result_getOperation(struct HBR_unicamp_Guarana_Result *this) {
  return ((NativeResult*)this)->op;
}

jbool BR_unicamp_Guarana_Result_isException(struct HBR_unicamp_Guarana_Result *this) {
  return (((NativeResult*)this)->kind & res_thrown) != 0;
}

struct Hjava_lang_Object* BR_unicamp_Guarana_Result_getObjectValue(struct HBR_unicamp_Guarana_Result *this_) {
  NativeResult *this = (NativeResult*)this_;

  if (this->kind & res_thrown)
    return this->res.object_value;
  else if (this->kind & res_returned)
    return guarana_wrap(BR_unicamp_Guarana_Operation_getType(this->op), this->res);
  else
    return 0;
}

jbool BR_unicamp_Guarana_Result_getBooleanValue(struct HBR_unicamp_Guarana_Result *this_) {
  NativeResult *this = (NativeResult*)this_;

  checkRet(this);
  checkRetType(this->op, 'Z');
  return this->res.boolean_value;
}

jbyte BR_unicamp_Guarana_Result_getByteValue(struct HBR_unicamp_Guarana_Result *this_) {
  NativeResult *this = (NativeResult*)this_;

  checkRet(this);
  checkRetType(this->op, 'B');
  return this->res.byte_value;
}

jshort BR_unicamp_Guarana_Result_getShortValue(struct HBR_unicamp_Guarana_Result *this_) {
  NativeResult *this = (NativeResult*)this_;

  checkRet(this);
  checkRetType(this->op, 'S');
  return this->res.short_value;
}

jint BR_unicamp_Guarana_Result_getIntValue(struct HBR_unicamp_Guarana_Result *this_) {
  NativeResult *this = (NativeResult*)this_;

  checkRet(this);
  checkRetType(this->op, 'I');
  return this->res.int_value;
}

jlong BR_unicamp_Guarana_Result_getLongValue(struct HBR_unicamp_Guarana_Result *this_) {
  NativeResult *this = (NativeResult*)this_;

  checkRet(this);
  checkRetType(this->op, 'J');
  return this->res.long_value;
}

jchar BR_unicamp_Guarana_Result_getCharValue(struct HBR_unicamp_Guarana_Result *this_) {
  NativeResult *this = (NativeResult*)this_;

  checkRet(this);
  checkRetType(this->op, 'C');
  return this->res.char_value;
}

jfloat BR_unicamp_Guarana_Result_getFloatValue(struct HBR_unicamp_Guarana_Result *this_) {
  NativeResult *this = (NativeResult*)this_;

  checkRet(this);
  checkRetType(this->op, 'F');
  return this->res.float_value;
}

jdouble BR_unicamp_Guarana_Result_getDoubleValue(struct HBR_unicamp_Guarana_Result *this_) {
  NativeResult *this = (NativeResult*)this_;

  checkRet(this);
  checkRetType(this->op, 'D');
  return this->res.double_value;
}
