#include <stdarg.h>

#include "types.h"
#include "mpool.h"
#include "tktree.h"
#include "clstree.h"
#include "sha1.h"
#include "listen.h"
#include "rovm.h"

#include "thread.h"
#include "thread_mutex.h"
#include "thread_cond.h"

#include "mpm_worker_fdqueue.h"
#include "mpm_worker_pod.h"
#include "mpm_worker.h"

#include "connection.h"
#include "request.h"
#include "proc_rc.h"

#include "ticket.h"
#include "file.h"

#include "el.h"

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

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

  while (fd->name)
    {
      RvField *f;

      if (rc_find_efield (cls, (u1 *) fd->name, (u1 *) fd->type))
        return 0;

      f = init_efield (cls, (u1 *) fd->name, (u1 *) fd->type);
      if (!f)
        return -1;

      FIELD_NEXT (f) = CLASS_FIELD (cls);
      CLASS_FIELD (cls) = f;

      fd++;
    }

  return 0;
}

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

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

  while (md->name)
    {
      RvMethod * m;

      if (rc_find_emethod (cls, (u1 *) md->name, (u1 *) md->type))
        return 0;

      /* Native Function 을 호출할 수 있도록 method 값들을 설정합니다.  */
      m = init_emethod ((u1 *) md->name, (u1 *) md->type);
      if (!m)
        return -1;

      METHOD_FLAG (m) |= ACCESS_NATIVE;
      METHOD_NATIVE (m) = md->func;
      METHOD_NEXT (m) = CLASS_METHOD (cls);
      
      CLASS_METHOD (cls) = m;

      md++;
    }

  return 0;
}

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

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

  OBJECT_USERDATA_IDX (self, idx) = (unsigned long) value;

  return 0;
}

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

   (외부 공개 함수)

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

  return (void *) OBJECT_USERDATA_IDX (self, idx);
}

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

   (외부 공개 함수)

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

  va_start (ap, fmt);

  idx = 0;
  while (*p)
    {
      switch (*p)
        {
        case 's':
          {
            char **s = va_arg (ap, char **);

            *s = "Under Construction";
            break;
          }
        case 'i':
          {
            int *i = va_arg (ap, int *);
            
            *i = STACK_V_INT (args + idx);
            break;
          }
        default:
          goto error;
          break;
        }

      idx++;
      p++;
    }

  va_end (ap);

  return 0;

 error:
  va_end (ap);

  return -1;
}
