/*
  이 파일은 ROVM 의 확장 모듈을 작성할 수 있도록 도와주는 헤더 
  파일입니다.
 */

#ifndef _ROVM_ENVLANG_H
#define _ROVM_ENVLANG_H

#ifndef ERRLOG_EMERG
#define	ERRLOG_EMERG		0	/* system is unusable */
#define	ERRLOG_ALERT		1	/* action must be taken immediately */
#define	ERRLOG_CRIT		2	/* critical conditions */
#define	ERRLOG_ERR		3	/* error conditions */
#define	ERRLOG_WARNING		4	/* warning conditions */
#define	ERRLOG_NOTICE		5	/* normal but significant condition */
#define	ERRLOG_INFO		6	/* informational */
#define	ERRLOG_DEBUG		7	/* debug-level messages */

#define	ERRLOG_LEVELMASK	7	/* mask off the level value */

#define ERRLOG_WITHERRNO	(ERRLOG_LEVELMASK + 1)
#define ERRLOG_MARK		__FILE__,__LINE__
#endif

/*
  다른 헤더에서 정의한 typedef 들과의 충돌을 방지하기 위해서 아래와 같이
  #ifndef 를 사용하게 되었습니다.
*/
#ifndef ROVM_ECLASS_TYPEDEF
typedef struct eclass RvClass;
#endif
#ifndef ROVM_EOBJECT_TYPEDEF
typedef struct eobject RvObject;
#endif
#ifndef ROVM_EVALUE_TYPEDEF
typedef struct rovm_stack RvValue;
#endif

#ifndef NULL_OBJECT
#define NULL_OBJECT             (RvObject *) 0
#endif
#ifndef NULL_VALUE
#define NULL_VALUE              (RvValue *) 0
#endif

typedef struct emethoddef RvMethodDef;
typedef struct efielddef RvFieldDef;

/**
   Field 모형을 정의한 구조체입니다.
 */
struct efielddef
{
  const char *name;
  const char *type;
};

/**
   Method 의 모형을 정의한 구조체입니다.
 */
struct emethoddef
{
  const char *name;
  const char *type;

  int (*func) (RvObject *cls, RvValue *arg, RvValue *ret);
};

/**
   ObjectRef 에 사용자가 데이타를 설정할 때 사용됩니다.

   @param self  현재 ObjectRef
   @param idx   설정할 사용자 index 번호 (반드시 OBJECT_MAX_USERDATA 보가
                값이 작아야 합니다.
   @param value 설정할 값.
*/
extern int RvSetUserData (RvObject *, int, void *);

/**
   ObjectRef 에 사용자가 설정한 데이타를 얻어올 때, 사용한다.

   (외부 공개 함수)

   @param self  현재 ObjectRef
   @param idx   사용자 데이타의 index 번호
   @return      사용자가 설정한 값을 반환합니다.
*/
extern void *RvGetUserData (RvObject *, int);

/**
   FDS 에 정의되어 있는 field 들을 클래스 CLS 의 하위 field 로 정의한다.

   @param cls   현재 Class 를 정의할 클래스 변수 포인터
   @param fds   Field 가 선언되어 있는 구조체 포인터.
   @return      실행 중 오류가 발생할 경우, -1 을, 그렇지 않을 경우 0 을 반환하게
                된다.
*/
extern int RvDefineFields (RvClass *cls, RvFieldDef *fds);

/**
   CLS 에 MD 를 읽어서 해당 Method 를 정의들을 CLS 내부에 정의한다.

   @param cls   현재 Class 를 정의할 클래스 변수 포인터
   @param md    Method 가 선언되어 있는 변수.
   @return      실행 중 오류가 발생할 경우, -1 을, 그렇지 않을 경우 0 을 반환하게
                된다.
*/
extern int RvDefineMethods (RvClass *, RvMethodDef *);

/**
   ARGS 를 FMT 과 비교하여 해당 변수에 올바른 값을 설정해 주는 역활을 하는
   함수입니다.

   @param args  RvValue 구조체입니다.  이것은 Stack Slot 에 대한 포인터를
                가지게 됩니다.
   @param fmt   해석할 구문입니다.
   @return      성공일 경우 0 을, 그렇지 않을 경우 -1 을 반환한다.
*/
extern int RvParseArg (RvObject *, RvValue *, const char *, ...);

/**
   문자열을 ArrayRef 로 변환하여 반환합니다.  (NewRvArray 에서 할당된
   GC 메모리는 자동으로 delayed slot 에 등록되어 있습니다.)

   @param self  SELF ObjectRef
   @param str   문자열 포인터 ('\0' 로 끝나지 않을 수 있습니다.)
   @param len   문자열 길이
   @return      새롭게 생성된 ArrayRef 포인터
*/
extern RvValue *RvStr2ArrayRef (RvObject *, char *, int);

/**
   Field 값을 설정하는 함수입니다.

   @param self  SELF ObjectRef
   @param name  Field 이름
   @param type  Field 타입
*/
extern int RvSetField (RvObject *self, const char *name, const char *type, ...);

/**
   Field 값을 얻어오는 함수입니다.  Type 에 따라서 ... 가 적용되는 것이
   특징입니다.

   @param self  SELF ObjectRef
   @param name  Field 이름
   @param type  Field 타입
 */
extern int RvGetField (RvObject *self, const char *name, const char *type, ...);

/**
   RvGetField () 함수와 비슷한 함수입니다만, 값을 저장하는 공간인 RvValue 
   구조체를 반환하는 것이 특징입니다.

   @param self  SELF ObjectRef
   @param name  Field 이름
   @param type  Field 타입
 */
extern RvValue *RvGetFieldValue (RvObject *self, const char *name, const char *type);

/**
   새로운 배열 (ArrayRef) 를 생성합니다.

   @param self  SELF ObjectRef
   @param len   생성되는 배열의 기본 길이
   @return      생성된 ArrayRef 포인터를 반환합니다.  만약 생성과정에서 
                오류가 발생하였을 경우 NULL_OBJECT 를 반환하게 됩니다.
 */
extern RvObject *RvArrayNew (RvObject *self, int len);

/**
   배열 ARRAY 에 타입이 TYPE 인 항목을 새롭게 추가할 때 사용됩니다.

   @param array ArraryRef 포인터
   @param type  새롭게 추가되는 항목의 타입 문자열
   @return      성공시 0, 실패시 -1 을 반환합니다.
 */
extern int RvArrayPush (RvObject *array, const char *type, ...);

/**
   배열 ARRAY 에서 가장 위에 있는 entry 를 제거합니다.

   @param array         ArrayRef 포인터
   @param poped_value   이 함수 실행으로 poped 되는 RvValue 구조체에 대한 정보를
                        기록해 줍니다.
   @return      성공시 0, 실패시 -1 을 반환합니다.
 */
extern int RvArrayPop (RvObject *array, RvValue **poped_value);

extern char * RvArray2Str (RvObject *self, RvObject *array);

/**
   배열 ARRAY 의 현재 길이를 계산하여 반환합니다.

   @param array ArrayRef 포인터
   @return      현재 배열의 크기
 */
extern int RvArrayLength (RvObject *array);

/**
   배열 ARRAY 에서 가장 위(뒤) 에 있는 값을 계산하여 그에 대한 RvValue 구조체를
   반환합니다.

   @param array ArrayRef 포인터
   @return      값을 담는 구조체인 RvValue 구조체
 */
extern RvValue *RvArrayLastValue (RvObject *array);

/**
   문자열이 STR 이고 길이가 LEN 인 StringRef 를 반환한다.
 */
extern RvObject *RvStrNew (RvObject *self, char *str, size_t len);

/**
   문자열 STR 에서 시작점을 OFFSET 으로 하고 길이 LEN 만큼 잘라 그것을
   StringRef 로 변환하여 반환합니다.

   @param self   SELF ObjectRef
   @param str    대상이 되는 문자열
   @param offset 문자열의 시작점
   @param len    자를 길이
   @return       새롭게 생성된 StringRef, 실패시 NULL_OBJECT
 */
extern RvObject *RvStrSubstr (RvObject *self, char *str, int offset, size_t len);

/**
   StringRef 에서 문자열과 길이를 각각 PTR 과 LEN 에 담아 반환합니다.

   @param str   StringRef 포인터
   @param ptr   문자열을 저장할 문자열 포인터
   @param len   문자열의 길이를 저장할 int 포인터
   @return      성공시 0, 실패시 -1 을 반환합니다.
 */
extern int RvStrGetInfo (RvObject *str, char **ptr, int *len);

/**
   문자열 객체 STR 에서 실제 값이 저장되어 있는 공간인 value 의 실제 포인터
   값을 반환합니다.

   @param str   문자열 객체
   @return      실제 char * 포인터.
 */
extern char *RvStrGetPointer (RvObject *str);

/**
   문자열 객체 STR 의 길이를 계산하여 반환합니다.

   @param str   문자열 객체
   @return      문자열의 길이
 */
extern int RvStrSize (RvObject *str);

/**
   메쏘드의 반환값을 설정할 때 사용되는 함수입니다.  TYPE 에 따라 ... 에 알맞은
   type 이 와야 합니다.

   @param self  SELF ObjectRef
   @param ret   메쏘드의 세번째 인자인 ret 의 포인터값입니다.
   @param type  반환값의 타입
   @return      성공시 0, 실패시 -1 을 반환합니다.
*/
extern int RvSetReturn (RvObject *self, RvValue *ret, const char *type, ...);

/**
   값을 담는 공간인 RET 에 값 VALUE 를 복사하는데 사용되는 함수로써 반환값을
   RvValue 그대로 복사하고 싶을 때 사용됩니다.

   @param ret   확장 모듈 메쏘드 호출시 3 번째 인자가 되는 값입니다.
   @param value 설정할 값
   @return      오류 발생시 -1, 그렇지 않을 경우 0 을 반환
 */
extern int RvSetReturnValue (RvValue *ret, RvValue *value);

/**
   값 VALUE 가 StringRef 인지를 반환합니다.

   @param value 값을 담는 구조체
   @return      만약 true 일 경우 1 을, 그렇지 않다면 0 을 반환합니다.
 */
extern int RvValueIsStringRef (RvValue *value);

/**
   값 VALUE 에서 StringRef 를 추출하여 반환합니다.

   @return      만약 VALUE 가 StringRef 일 경우, 그에 해당하는 포인터를 반환하고
                그렇지 않다면 NULL_OBJECT 를 반환합니다.
 */
extern RvObject *RvValueStringRef (RvValue *value);

/**
   RvValue 구조체에 들어있는 값을 문자열로 변환하여 반환합니다.

   @param self  SELF ObjectRef
   @param val   문자열로 변환할 val
 */
extern char *RvValue2Str (RvObject *self, RvValue *val);
//extern int RvValue2Int (RvObject *self, RvValue *val);

/**
   값 VALUE 가 ArrayRef 일 경우, 값에 저장되어 있는 ArrayRef 포인터를 
   반환합니다.

   @param value 값을 담는 공간인 RvValue 구조체
   @return      만약 ArrayRef 일 경우, 해당 ArrayRef 포인터를, 그렇지
                않을 경우 NULL_OBJECT 가 반환됩니다.
 */
extern RvObject *RvValueArrayRef (RvValue *value);

/**
   값을 담는 공간인 O1 과 O2 를 비교하여 만약 같다면 1 을 반환하고 그렇지
   않다면 0 을 반환합니다.  만약 중간에 오류가 발생하였다면 -1 을 반환하게
   됩니다.  만약 배열 비교일 경우, 내부 항목들을 재귀 호출로써 비교를 하게
   되며, 문자열 객체일 경우, 문자열의 길이 및 내용을 비교하게 됩니다. 
   만약 ObjectRef 일 경우는 주소값을 기준으로 비교를 하게 됩니다.  그 외의
   값은 실제 해당 값을 비교함으로써 이루어지게 됩니다.

   @param o1    비교할 대상값 1 번
   @param o2    비교할 대상값 2 번
   @return      만약 같다면 1 을 반환하고 그렇지 않다면 0 을 반환합니다.
                만약 중간에 오류가 발생하였다면 -1 을 반환
 */
extern int RvValueRichCompare (RvValue *o1, RvValue *o2);

/**
   값 VALUE 의 복사본을 만들어 그 값을 반환하게 됩니다.  이 함수가 존재하는 이유는
   확장 모듈 작성시 GC 메모리 포인터를 스택상에 보관하고 있을 그 순간에 GC 가 
   실행될 경우, 해당 객체가 증발해 버리는 사고를 방지하기 위해서 존재합니다.

   아래의 RvMemMalloc () 에서 할당되는 메모리는 Delayed Stack Slot 에 자동으로
   등록되게 됩니다.

   @param self  메모리 참조를 위해 사용되는 Object 객체
   @param value 복사할 값
   @return      복사된 값
 */
extern RvValue *RvValueCopy (RvObject *self, RvValue *value);

/**
   GC 메모리 공간을 할당할 때 사용되는 함수입니다.  아래에서 할당되는 메모리는
   자동으로 Delayed Stack Slot 에 등록되게 됩니다.

   @param self  ROVM 구조체와 TICKET 구조체의 포인터를 얻기 위해 사용되는
                객체
   @param size  할당할 메모리 크기
   @return      할당된 메모리 포인터
 */
extern void *RvMemMalloc (RvObject *self, size_t size);

/**
   VAL 의 타입 이름을 반환합니다.

   @param val   알고자 하는 값
   @return      해당 타입의 이름
 */
extern const char *RvGetTypeName (RvValue *val);

/**
   ROVM Request 에서 발생하는 모든 메세지를 기록하기 위해서 사용하는 logger 함수.

   @param self	SELF 객체
   @param level 현재 로그의 위험도 등급
   @param file	메세지가 발생한 파일 이름
   @param line	메세지가 발생한 파일의 라인 번호
   @param fmt	vprintf 관련 포맷
 */
extern int RvLogError (RvObject *, int, const char *, int, const char *, ...);

/**
   배열 객체 ARRAY 의 index IDX 에 존재하는 값 구조체를 반환합니다.

   @param array 배열 객체
   @param idx   찾을 index 번호
   @return      찾은 값 구조체를 반환
 */
extern RvValue *RvArrayGetItem (RvObject *array, size_t idx);

/**
   배열 객체 ARRAY 의 index IDX 에 값 VAL 를 설정하는 함수입니다.

   @param array 배열 객체
   @param idx   값을 갱신할 index 번호
   @param val   설정할 값
   @return      오류 발생시 -1, 정상시 0
 */
extern int RvArraySetItem (RvObject *array, size_t idx, RvValue *val);

/**
   배열 객체 ARRAY 를 길이 TOTAL 로 크기를 재조정합니다.  이에 대한 결과값으로
   배열 객체의 필드 LEN 값이 변경되게 됩니다.

   @param array 배열 객체
   @param total 배열의 총 길이
   @return      오류 발생시 -1, 정상시 0 을 반환합니다.
 */
extern int RvArrayResize (RvObject *array, int total);

/**
   배열 객체 ARRAY 의 index WHERE 에 값 FMT 을 넣게 됩니다.  FMT 을 바로
   넣는 것이 아니라 ... 에 맞게 해석한 뒤 알맞게 들어가게 됩니다.

   @param array 배열 객체
   @param where 어디에 넣을 것인가를 결정하는 index 번호
   @param fmt   문자열 포맷
   @return      만약 중간에 오류가 발견되었을 경우 -1, 그렇지 않을 경우
                0 을 반환하게 됩니다.
 */
extern int RvArrayInsert (RvObject *array, int where, const char *fmt, ...);

/**
   배열 객체 ARRAY 에서 LO 와 HI 값을 처리할 때 사용됩니다.  만약 V 가 NULL
   일 경우는 del ARRAY[LO:HI] 와 같은 의미가 되며, 그렇지 않을 경우 
   ARRAY[LO:HI] = v 의 의미가 됩니다.

   파이썬의 코드가 매우 많이 참조되었습니다. ^^ 같은 기능을 다시 머리로 생각해서
   만드는 것을 세상에서 가장 싫어합니다.

   @param array 배열 객체
   @param lo    배열에서의 lowest index
   @param hi    배열에서의 highest index
   @param v     삽입할 경우, 그에 해당하는 값
   @return      만약 실행 중 오류가 발생했었다면 -1 을 그렇지 않다면 0 을 
                반환합니다.
 */
extern int RvArraySliceAdvanced (RvObject *array, int lo, int hi, RvObject *v);

/**
   Array 관련 함수로써 SELF 와 B 는 모두 ArrayRef 객체입니다.  이 함수는
   B 에 들어 있는 항목들을 모두 SELF 에 추가하는 일을 합니다.

   @param self  배열 객체 1 번
   @param b     배열 객체 2 번
   @return      배열 객체 2 번이 배열 객체 1 번에 모두 삽입된 결과값을
                만드는데, 과정에서 오류가 발생하였을 경우 -1 을 그렇지
                않을 경우 0 을 반환합니다.
 */
extern int RvArrayExtend (RvObject *self, RvObject *b);

/**
   배열 객체 ARRAY 의 순서를 반대로 만듭니다.

   @param array 배열 객체
   @return      오류 발생시 -1, 정상시 0 을 반환
 */
extern int RvArrayReverse (RvObject *array);

/**
   배열 객체 ARRAY 에서 인덱스 I 의 값을 POP 하고 그 POP 된 값을 POPED_VALUE
   에 설정하게 됩니다.  만약 배열의 중간 부분이 POP 될 경우, 자동으로 그 공간이
   줄어들게 됩니다.

   @param array 배열 객체
   @param i     POP 할 항목의 인덱스
   @param poped_value POP 된 항목에 들어있던 값
   @return      오류 발생시 -1, 정상시 0 값을 반환합니다.
 */
extern int RvArrayPopWithIndex (RvObject *array, int i, RvValue **poped_value);

/**
   배열 객체 ARRAY 에서 실제 값이 저장되는 공간인 필드 VALUE 의 주소 포인터를
   반환하게 됩니다.

   배열 객체와 문자열 객체의 필드 VALUE 는 둘다 모두 특별하게 취급해줘야하는
   부분이 존재합니다.

   @param array 배열 객체
   @return      필드 VALUE 의 주소 포인터
 */
extern RvValue *RvArrayGetEntry (RvObject *array);

/**
   값 ENTRY 가 RvValue 구조체로 이루어진 배열이라고 가정을 하고, 해당 IDX 에
   맞는 포인터값을 반환하게 됩니다.

   @param entry RvValue 구조체 포인터
   @param idx   배열의 index 번호
   @return      해당 값 포인터
 */
extern RvValue *RvValueEntryItem (RvValue *entry, int idx);

extern RvObject *RvObjectNew (RvObject *self, int iptype, char *hostname, unsigned short port, char *path);

#endif
