/*  -
   Copyright (C) 2006 Weongyo Jeong (weongyo@gmail.com)

This file is part of ROVM.

ROVM is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.

ROVM is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING.  If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.  */

#include <stdio.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 "log.h"
#include "utils.h"
#include "ticket.h"

/**
   TKTREE 에서 하나의 node key 를 제거할 때 호출되는 callback 함수.

   @param k	삭제할 node key
 */
void
rovm_tktree_delete_key (k)
     tktree_key k;
{
  char *tid = (char *) k;

  if (tid)
    rc_free (tid);
}

/**
   TKTREE 에서 하나의 node value 를 제거할 때 호출되는 callback 함수.

   @param v	삭제할 node value
 */
void
rovm_tktree_delete_value (v)
     tktree_value v;
{
  struct ticket *tk = (struct ticket *) v;

  destroy_ticket (tk);
}

/* 이 파일은 ticket 을 위한 tree function 들의 wrapper 로 구성되어 있습니다.  
   이렇게 하는 이유는 아직 개발이 테스트 단계이며, 안정적이며 최고의 tree 를 
   아직 선정하지 못하였기 때문입니다.  */

/**
   tktree SP 에 key 값과 value 값을 등록한다.

   @note	Wrapper Function 입니다.

   @param sp	생성된 ticket tree
   @param key	등록할 key 값
   @param value 등록한 value 값
   @return	만약 성공적으로 등록이 되었다면 0 을, 그렇지 않다면 -1 을 반환한다.
 */
int
tktree_insert (sp, key, value)
     tktree_t *sp;
     char *key;
     void *value;
{
  splay_tree_node_t n;

  if (!sp || !key)
    return -1;

  n = splay_tree_insert (sp, (splay_tree_key) key, (splay_tree_value) value);
  if (!n)
    return -1;

  return 0;
}

/**
   tktree SP 에서 KEY 값을 가지는 key 와 value 쌍을 *모두* 제거한다.

   @param sp    Ticket Tree 포인터
   @param key   제거할 Ticket ID
 */
void
tktree_remove (sp, key)
     tktree_t *sp;
     char *key;
{
  splay_tree_key backup;
  splay_tree_node_t n = splay_tree_lookup (sp, (tktree_key) key);

  if (!n)
    return;

  backup = n->key;
  /* !참조! splay_tree_remove () 함수에서는 Node 의 Value 값만 제거하지 key 값은
     제거하지 않기 때문에, 이를 아래에서 key 값까지 제거해준다.  */
  splay_tree_remove (sp, (splay_tree_key) n->key);
  rovm_tktree_delete_key (backup);
}

/**
   tktree SP 에서 key 값이 KEY 인 node 를 찾는다.  만약 존재하지 않을 경우,
   NULL 을 반환하며, 발견하였을 경우, 해당 value 값을 반환한다.

   @note	Wrapper Function 입니다.

   @param sp	생성된 ticket tree
   @param key	검색 할 key 값
   @return	발견한 key 값의 value 값을 반환한다.  존재하지 않는 다면, NULL 을
                반환한다.
 */
void *
tktree_lookup (sp, key)
     tktree_t *sp;
     char *key;
{
  splay_tree_node_t n = splay_tree_lookup (sp, (tktree_key) key);

  if (!n)
    return NULL;

  return (void *) n->value;
}

/**
   Ticket Tree 의 각각의 node 을 walking 할 때 사용합니다.

   @param sp    Ticket Tree 포인터
   @param fn    각각의 node 만났을 때 호출되는 function.
   @param data  인자 fn 에 넘길 data
   @return      만약 인자 fn 이 실행된 후 반환되는 값이 0 이 아닐 경우,
                walking 을 멈추고 바로 해당 값을 반환하게 됩니다.
 */
int
tktree_walking (sp, fn, data)
     tktree_t *sp;
     tktree_foreach_fn fn;
     void *data;
{
  return splay_tree_foreach (sp, fn, data);
}

/**
   새로운 ticket tree 를 생성한다.

   @note	Wrapper Function 입니다.

   @param compare_fn		Tree 의 compare function
   @param delete_key_fn		Tree 의 key 를 삭제할 때 사용할 함수.
   @param delete_value_fn	Tree 의 value 를 삭제할 때 사용할 함수.
   @return 새로 생성된 ticket tree 반환한다.
 */
tktree_t *
init_tktree (compare_fn, delete_key_fn, delete_value_fn)
     tktree_compare_fn compare_fn;
     tktree_delete_key_fn delete_key_fn;
     tktree_delete_value_fn delete_value_fn;
{
  return (tktree_t *) splay_tree_new (compare_fn, delete_key_fn, delete_value_fn);
}


/**
   더 이상 ticket tree 가 필요없을 때, 해당 사항들을 모두 제거할 때 사용한다.

   @note	Wrapper Function 입니다.

   @param tk	제거할 tktree_t 구조체.
 */
void
finish_tktree (tk)
     tktree_t *tk;
{
  splay_tree_delete (tk);
}

/**
   Ticket Key 를 서로 비교하여 서로 같을 경우, 0 을 반환하고 그렇지 않을 경우
   1 혹은 -1 을 반환한다.

   @param k1	Key 1 번
   @param k2	Key 2 번
*/
static inline int
compare_ticketvalue (t1, t2)
     char *t1, *t2;
{
  int __tmpi;

  for (__tmpi=0; __tmpi<TICKETID_SIZE; __tmpi++)
    {
      if ((int) t1[__tmpi] < (int) t2[__tmpi])
        return -1;
      else if ((int) t1[__tmpi] > (int) t2[__tmpi])
        return 1;
    }

  return 0;
}

/**
   Splay Tree 비교 루틴.  K1 과 K2 가 같을 경우, 0 을 반환한다.  그렇지 않을 경우,
   -1 혹은 1 이 반환된다.

   @param k1 Key 1 번
   @param k2 Key 2 번
   @return 만약 K1 과 K2 가 같을 경우 0 을 반환한다.
*/
int
rovm_tktree_compare (k1, k2)
     tktree_key k1;
     tktree_key k2;
{
  return compare_ticketvalue ((char *) k1, (char *) k2);
}

/**
   ROVM 구조체의 tktree 을 초기화합니다.

   @param r	ROVM 구조체 포인터
   @return	성공적으로 수행되었을 경우 0 을, 그렇지 않다면 -1 을 반환한다.
 */
int
init_rovm_tktree (r)
     struct rovm *r;
{
  rc_status_t rv;

  ROVM_TKTREE (r) = init_tktree ((tktree_compare_fn) rovm_tktree_compare,
				 (tktree_delete_key_fn) rovm_tktree_delete_key,
				 (tktree_delete_value_fn) rovm_tktree_delete_value);
  if (!ROVM_TKTREE (r))
    return -1;

  rv = rc_thread_mutex_create (&ROVM_TKMUTEX (r), RC_THREAD_MUTEX_DEFAULT, ROVM_POOL (r));
  if (rv != RC_SUCCESS)
    return -1;

  return 0;
}

