#ifndef _ROVM_CLASS_H
#define _ROVM_CLASS_H

/** 만약 Class 를 찾을 수 없을 경우, 이 값을 반환하게 됩니다.  */
#define NULL_CLASS              (RvClass *) 0
/** 만약 찾고자 하는 Class 가 이 ROVM 서버가 아닌 원격에 있는 Class 일 경우,
    이 값을 반환하게 됩니다.  */
#define REMOTE_CLASS            (RvClass *) 1

#define NULL_FIELD              (RvField *) 0
#define NULL_METHOD             (RvMethod *) 0
#define NULL_OBJECT             (RvObject *) 0

typedef unsigned short u2;
typedef unsigned char u1;
typedef unsigned int u4;
typedef struct eclass RvClass;
#define ROVM_ECLASS_TYPEDEF     /**< el.h 와의 충돌 방지를 위해.  */
typedef struct eclass_field RvField;
typedef struct eclass_method RvMethod;
typedef struct eobject RvObject;
#define ROVM_EOBJECT_TYPEDEF    /**< el.h 와의 충돌 방지를 위해.  */

enum access_flag
  {
    ACCESS_NATIVE = 0x1
  };

#define FIELD_NAME(NODE)                ((NODE)->name)
#define FIELD_TYPE(NODE)                ((NODE)->type)
#define FIELD_INDEX(NODE)               ((NODE)->index)
#define FIELD_NEXT(NODE)                ((NODE)->next)

struct eclass_field
{
  /** Field 의 이름을 가지고 있는 문자열 포인터입니다.  */
  u1 *name;
  /** Field 의 타입을 가르키는 문자열 포인터입니다.  */
  u1 *type;

  /** Field 의 경우, ObjectRef 가 생성될 때 마다 각각의 field 를 위한
      공간이 필요한데, 해당 공간에서 이 field 가 존재하는 위치를 가르키는 
      index 번호입니다.  */
  u2 index;

  /** 다음 field 에 대한 포인터.  */
  struct eclass_field *next;
};

#define MTYPE_STR(NODE)                 ((NODE)->str)
#define MTYPE_ARGC(NODE)                ((NODE)->argc)
#define MTYPE_ARGV(NODE)                ((NODE)->argv)
#define MTYPE_RET(NODE)                 ((NODE)->ret)

/**
   Method 의 Type 을 분석하여 그에 대한 세부 정보를 가지고 있는 구조체입니다.
 */
struct eclass_method_type
{
  /** Method 의 Type 정보입니다.  */
  u1 *str;

  /** Type 에서 Argument 의 갯수를 가지고 있습니다.  */
  u2 argc;
  /** Type 에서 각각의 Argument 의 위치 관련 offset 정보를 가지고 있습니다.  */
  u2 *argv;
  /** Type 에서 Return 관련 정보의 위치 offset 정보를 가지고 있습니다.  */
  u2 ret;
};

#define METHOD_FLAG(NODE)               ((NODE)->flag)
#define METHOD_NAME(NODE)               ((NODE)->name)
#define METHOD_TYPE(NODE)               ((NODE)->type)
#define METHOD_MAX_LOCALS(NODE)         ((NODE)->max_locals)
#define METHOD_OPLEN(NODE)              ((NODE)->oplen)
#define METHOD_OP(NODE)                 ((NODE)->op)
#define METHOD_NATIVE(NODE)             ((NODE)->native)
#define METHOD_NEXT(NODE)               ((NODE)->next)

/**
   하나의 Method 를 나타내는 구조체입니다.
 */
struct eclass_method
{
  /** 현재 Method 의 다양한 옵션을 정의하기 위한 flag 변수.  */
  enum access_flag flag;

  /** Method 의 이름을 가지고 있는 문자열 포인터입니다.  */
  u1 *name;
  /** Method 의 타입을 해석된 형태로 가지고 있는 구조체.  */
  struct eclass_method_type *type;

  /** Method 내부에서 사용할 로컬 변수의 최대 크기.  */
  u2 max_locals;

  /** 현재 Method 가 ROVM opcode 들로 구성되어 있을 경우, 해당 opcode 에 대한
      전체 길이를 정의하는 변수.  */
  u4 oplen;
  /** 현재 Method 가 ROVM opcode 들로 구성되어 있을 경우, 해당 opcode 에 대한
      포이터.  */
  rc_opcode_t *op;

  /** 현재 Method 의 flag 중 ACCESS_NATIVE 가 설정되어 있을 경우, 이 함수
      포인터가 설정됩니다.  오직 아래 변수는 ACCESS_NATIVE 를 위한 변수입니다.  */
  int (*native) (RvObject *cls, RvValue *arg, RvValue *ret);

  /** 다음 method 에 대한 포인터.  */
  struct eclass_method *next;
};

#define CLASS_FLAG(NODE)                ((NODE)->flag)
#define CLASS_ROVM(NODE)                ((NODE)->r)
#define CLASS_NAME(NODE)                ((NODE)->name)
#define CLASS_FIELD(NODE)               ((NODE)->f)
#define CLASS_FIELD_COUNT(NODE)         ((NODE)->field_count)
#define CLASS_METHOD(NODE)              ((NODE)->m)
#define CLASS_NATIVE_HANDLE(NODE)       ((NODE)->native_handle)

/**
   ENVLANG File Format 에 정의되어 있는 클래스를 C 언어로 표현한 구조체
   입니다.

   (20050206) 현재 구조는 매우 간단하며, field, exception 은 지원도 하지 
              않습니다.
 */
struct eclass
{
  /** 현재 Class 의 다양한 옵션을 정의하기 위한 flag 변수.  */
  enum access_flag flag;
  /** ROVM 구조체에 대한 빠른 접근을 위해서, 이에 대한 포인터를 간직한다.  */
  struct rovm *r;
  /** 현재 RvClass 의 flag 중 ACCESS_NATIVE 가 설정되어 있을 경우, 이 변수가 사용된다.  */
  rc_dso_handle_t *native_handle;

  /** 현재 RvClass 의 이름을 가지고 있습니다.  여기 할당된 이름은 단순히 debug
      용으로 사용되며, 이 이름을 이용하여 class 를 찾는 과정 같은 것은 없다.  */
  u1 *name;

  /** 현재 RvClass 에 정의되어 있는 field 들에 대한 linked list 입니다.  */
  struct eclass_field *f;
  /** 현재 RvClass 에 정의되어 있는 field 들의 총 갯수를 가지고 있습니다.  */
  u2 field_count;

  /** 현재 RvClass 에 정의되어 있는 method 들에 대한 linked list 입니다.  */
  struct eclass_method *m;
};

#define OBJECT_REQUEST(NODE)            ((NODE)->r)
#define OBJECT_TICKET(NODE)             ((NODE)->tk)
#define OBJECT_TYPE(NODE)               ((NODE)->type)
/** 현재 ObjectRef 가 local 용임을 가르킵니다.  */
#define LOCAL_OBJECT                    0
/** 현재 ObjectRef 가 remote 용임을 가르킵니다.  */
#define REMOTE_OBJECT                   1
#define OBJECT_IS_STRING(NODE)          ((NODE)->is_string)
#define OBJECT_IS_ARRAY(NODE)           ((NODE)->is_array)
#define OBJECT_CTIME(NODE)              ((NODE)->ctime)
#define OBJECT_MAX_USERDATA             16
#define OBJECT_USERDATA(NODE)           ((NODE)->userdata)
#define OBJECT_USERDATA_IDX(NODE, IDX)  ((NODE)->userdata[(IDX)])
#define OBJECTL_CLASS(NODE)             ((NODE)->cls)
#define OBJECTL_ROVM(NODE)              CLASS_ROVM (OBJECTL_CLASS (NODE))
#define OBJECTL_FIELD(NODE)             ((NODE)->f)
#define OBJECTL_FIELD_IDX(NODE, IDX)    (&((NODE)->f[(IDX)]))

/**
   RvObject 구조체에 대해서 정의합니다.
 */
struct eobject
{
  /** request 에 대한 구조체로써 확장 모듈쪽에서 발생하는 오류 메세지들을
      사용자에게 건내질 수 있도록 하기 위해서 존재합니다.

      이 변수는 method 호출이 이루어지기전 직전에 현재 사용되는 request_rec
      구조체에 대한 정보가 설정되게 됩니다.  */
  request_rec *r;
  /** 현재 이 ObjectRef 가 소속되어 있는 Ticket 구조체를 가르킨다.  */
  struct ticket *tk;

  /** 현재 이 RvObject 가 local 클래스 참조를 위한 ObjectRef 인지 remote
      ObjectRef 를 위한 참조인지를 나타내는 변수입니다.  만약 값이 0 일 경우,
      local 을 의미하며, 1 일 경우 remote 를 의미합니다.
      (공통요소)  */
  unsigned type : 1;
  /** 값이 1 일 경우, 현재 이 ObjectRef 가 String 객체임을 의미합니다.  */
  unsigned is_string : 1;
  /** 값이 1 일 경우, 현재 이 ObjectRef 가 Array 객체임을 의미합니다.  */
  unsigned is_array : 1;
  unsigned unused : 29;

  /** 이 ObjectRef 가 *생성된 시각*에 대한 기록을 가지고 있습니다.  이 정보는
      Garbage Collector 가 유용하게 사용하기 위해서 존재합니다. 
      (공통요소)  */
  rc_time_t ctime;

  /** 사용자가 자신의 값을 임시적으로 기록할 수 있는 공간을 부여한다.  */
  unsigned long userdata[OBJECT_MAX_USERDATA];

  /** 아직 완벽한 eobject 구조체의 모습은 아니지만, 아래의 변수는 LOCAL_OBJECT 일
      경우 해당, 클래스가 설정되는 변수이다.  */
  RvClass *cls;

  /** LOCAL_OBJECT 일 경우, 해당 클래스의 필드값을 위한 공간이 할당된다.  */
  RvValue *f;
};

extern int rc_expandarray (RvObject *, int);
extern RvClass *rc_getclassbyhost (request_rec *, int, char *, unsigned short, char *);
extern RvObject *NewRemoteRvObject (request_rec *, int, char *, unsigned short, char *);
extern RvObject *NewRvObject (struct rovm *, struct ticket *, RvClass *);
extern RvObject *NewRvArray (struct rovm *, struct ticket *, int);
extern RvObject *NewRvStringObject (struct rovm *, struct ticket *, const char *, size_t);

extern int rc_callmethod (request_rec *, struct ticket *, char *, char *, u2, u2 *);

extern RvValue *rc_getfieldvalue (RvObject *self, const char *fname, const char *ftype);
extern int rc_getinfo_string (RvObject *obj, char **str, int *len);
extern int rc_getinfo_array (RvObject *obj, RvValue **entry, int *arrlen);

#endif

