/*
 * Copyright (C) 2008 Search Solution Corporation. All rights reserved by Search Solution.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * - Neither the name of the <ORGANIZATION> nor the names of its contributors
 *   may be used to endorse or promote products derived from this software without
 *   specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 *
 */


/*
 * cci_t_set.c -
 */

#ident "$Id$"

/************************************************************************
 * IMPORTED SYSTEM HEADER FILES						*
 ************************************************************************/
#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if defined(WINDOWS)
#include <winsock.h>
#else
#include <arpa/inet.h>
#endif

/************************************************************************
 * OTHER IMPORTED HEADER FILES						*
 ************************************************************************/

#include "cci_common.h"
#include "cas_cci.h"
#include "cci_t_set.h"
#include "cci_query_execute.h"
#include "cci_net_buf.h"
#include "cci_util.h"

/************************************************************************
 * PRIVATE DEFINITIONS							*
 ************************************************************************/

/************************************************************************
 * PRIVATE TYPE DEFINITIONS						*
 ************************************************************************/

/************************************************************************
 * PRIVATE FUNCTION PROTOTYPES						*
 ************************************************************************/

/************************************************************************
 * INTERFACE VARIABLES							*
 ************************************************************************/

/************************************************************************
 * PUBLIC VARIABLES							*
 ************************************************************************/

/************************************************************************
 * PRIVATE VARIABLES							*
 ************************************************************************/

/************************************************************************
 * IMPLEMENTATION OF INTERFACE FUNCTIONS 				*
 ************************************************************************/

/************************************************************************
 * IMPLEMENTATION OF PUBLIC FUNCTIONS	 				*
 ************************************************************************/

void
t_set_free (T_SET * set)
{
  if (set == NULL)
    return;

  FREE_MEM (set->element);
  FREE_MEM (set->data_buf);
  hm_conv_value_buf_clear (&(set->conv_value_buffer));
  FREE_MEM (set);
}

int
t_set_size (T_SET * set)
{
  return (set->num_element);
}

int
t_set_element_type (T_SET * set)
{
  return set->type;
}

int
t_set_get (T_SET * set, int index, T_CCI_A_TYPE a_type, void *value, int *indicator)
{
  char *ele_value_p;
  char u_type;
  int data_size;
  int err_code;

  if (index <= 0 || index > set->num_element)
    return CCI_ER_SET_INDEX;

  ele_value_p = (char *) set->element[index - 1];
  u_type = t_set_element_type (set);

  NET_STR_TO_INT (data_size, ele_value_p);
  if (data_size <= 0)
    {
      *indicator = -1;
      if (a_type == CCI_A_TYPE_STR)
	{
	  *((void **) value) = NULL;
	}
      return 0;
    }

  ele_value_p += 4;
  *indicator = 0;

  switch (a_type)
    {
    case CCI_A_TYPE_STR:
      err_code =
	qe_get_data_str (&(set->conv_value_buffer), (T_CCI_U_TYPE) u_type, ele_value_p, data_size, value, indicator);
      break;
    case CCI_A_TYPE_INT:
      err_code = qe_get_data_int ((T_CCI_U_TYPE) u_type, ele_value_p, value);
      break;
    case CCI_A_TYPE_BIGINT:
      err_code = qe_get_data_bigint ((T_CCI_U_TYPE) u_type, ele_value_p, value);
      break;
    case CCI_A_TYPE_FLOAT:
      err_code = qe_get_data_float ((T_CCI_U_TYPE) u_type, ele_value_p, value);
      break;
    case CCI_A_TYPE_DOUBLE:
      err_code = qe_get_data_double ((T_CCI_U_TYPE) u_type, ele_value_p, value);
      break;
    case CCI_A_TYPE_BIT:
      err_code = qe_get_data_bit ((T_CCI_U_TYPE) u_type, ele_value_p, data_size, value);
      break;
    case CCI_A_TYPE_DATE:
      err_code = qe_get_data_date ((T_CCI_U_TYPE) u_type, ele_value_p, value);
      break;
    case CCI_A_TYPE_UINT:
    case CCI_A_TYPE_UBIGINT:
    default:
      return CCI_ER_TYPE_CONVERSION;
    }

  return err_code;
}

int
t_set_alloc (T_SET ** out_set)
{
  T_SET *set;

  *out_set = NULL;
  set = (T_SET *) MALLOC (sizeof (T_SET));
  if (set == NULL)
    return CCI_ER_NO_MORE_MEMORY;

  memset (set, 0, sizeof (T_SET));
  *out_set = set;
  return 0;
}

int
t_set_make (T_SET * set, char ele_type, int size, void *value, int *indicator)
{
  int i;
  T_NET_BUF net_buf;
  char u_type;
  int err_code;
  int *ele_index = NULL;

  net_buf_init (&net_buf);

  ele_index = (int *) MALLOC (sizeof (int) * size);
  if (ele_index == NULL)
    {
      return CCI_ER_NO_MORE_MEMORY;
    }

  if (ele_type == CCI_U_TYPE_SHORT)
    {
      ele_type = CCI_U_TYPE_INT;
    }

  for (i = 0; i < size; i++)
    {
      ele_index[i] = net_buf.data_size;

      u_type = ele_type;
      if (indicator[i])
	{
	  u_type = CCI_U_TYPE_NULL;
	}

      switch (u_type)
	{
	case CCI_U_TYPE_NULL:
	  {
	    ADD_ARG_BYTES (&net_buf, NULL, 0);
	  }
	  break;
	case CCI_U_TYPE_CHAR:
	case CCI_U_TYPE_STRING:
	case CCI_U_TYPE_NCHAR:
	case CCI_U_TYPE_VARNCHAR:
	case CCI_U_TYPE_NUMERIC:
	case CCI_U_TYPE_ENUM:
	  {
	    char *ele_value;
	    ele_value = ((char **) value)[i];
	    ADD_ARG_STR (&net_buf, ele_value, strlen (ele_value) + 1, NULL);
	  }
	  break;
	case CCI_U_TYPE_BIT:
	case CCI_U_TYPE_VARBIT:
	  {
	    T_CCI_BIT ele_value;
	    ele_value = ((T_CCI_BIT *) value)[i];
	    ADD_ARG_BYTES (&net_buf, ele_value.buf, ele_value.size);
	  }
	  break;
	case CCI_U_TYPE_BIGINT:
	  {
	    INT64 ele_value;
	    ele_value = ((INT64 *) value)[i];
	    ADD_ARG_BIGINT (&net_buf, ele_value);
	  }
	  break;
	case CCI_U_TYPE_INT:
	case CCI_U_TYPE_SHORT:
	  {
	    int ele_value;
	    ele_value = ((int *) value)[i];
	    ADD_ARG_INT (&net_buf, ele_value);
	  }
	  break;
	case CCI_U_TYPE_FLOAT:
	  {
	    float ele_value;
	    ele_value = ((float *) value)[i];
	    ADD_ARG_FLOAT (&net_buf, ele_value);
	  }
	  break;
	case CCI_U_TYPE_MONETARY:
	case CCI_U_TYPE_DOUBLE:
	  {
	    double ele_value;
	    ele_value = ((double *) value)[i];
	    ADD_ARG_DOUBLE (&net_buf, ele_value);
	  }
	  break;
	case CCI_U_TYPE_DATE:
	case CCI_U_TYPE_TIME:
	case CCI_U_TYPE_TIMESTAMP:
	case CCI_U_TYPE_DATETIME:
	  {
	    T_CCI_DATE ele_value;
	    ele_value = ((T_CCI_DATE *) value)[i];
	    ADD_ARG_DATETIME (&net_buf, &ele_value);
	  }
	  break;
	case CCI_U_TYPE_TIMETZ:
	case CCI_U_TYPE_TIMESTAMPTZ:
	case CCI_U_TYPE_TIMESTAMPLTZ:
	case CCI_U_TYPE_DATETIMETZ:
	case CCI_U_TYPE_DATETIMELTZ:
	  {
	    T_CCI_DATE_TZ ele_value;
	    ele_value = ((T_CCI_DATE_TZ *) value)[i];
	    ADD_ARG_DATETIMETZ (&net_buf, &ele_value);
	  }
	  break;
	case CCI_U_TYPE_OBJECT:
	  {
	    char *tmp_str;
	    T_OBJECT ele_value;

	    tmp_str = ((char **) value)[i];
	    err_code = ut_str_to_oid (tmp_str, &ele_value);
	    if (err_code < 0)
	      {
		goto set_make_error;
	      }
	    ADD_ARG_OBJECT (&net_buf, &ele_value);
	  }
	  break;
	case CCI_U_TYPE_USHORT:
	case CCI_U_TYPE_UINT:
	case CCI_U_TYPE_UBIGINT:
	case CCI_U_TYPE_BLOB:
	case CCI_U_TYPE_CLOB:
	default:
	  err_code = CCI_ER_TYPE_CONVERSION;
	  goto set_make_error;
	}
    }

  if (net_buf.err_code < 0)
    {
      err_code = net_buf.err_code;
      goto set_make_error;
    }

  set->element = (void **) MALLOC (sizeof (void *) * size);
  if (set->element == NULL)
    {
      err_code = CCI_ER_NO_MORE_MEMORY;
      goto set_make_error;
    }

  set->data_buf = net_buf.data;
  set->data_size = net_buf.data_size;
  for (i = 0; i < size; i++)
    {
      set->element[i] = (char *) (set->data_buf) + ele_index[i];
    }
  set->num_element = size;
  set->type = ele_type;

  FREE_MEM (ele_index);
  return 0;

set_make_error:
  net_buf_clear (&net_buf);
  FREE_MEM (ele_index);
  return err_code;
}

int
t_set_decode (T_SET * set)
{
  void **element;
  char *cur_p;
  int i;
  int remain_size;
  int ele_size;

  if (set->num_element < 0 || set->data_size < 0)
    return CCI_ER_COMMUNICATION;

  if (set->num_element == 0 || set->data_size == 0)
    return 0;

  element = (void **) MALLOC (sizeof (void *) * set->num_element);
  if (element == NULL)
    return CCI_ER_NO_MORE_MEMORY;
  memset (element, 0, sizeof (void *) * set->num_element);

  remain_size = set->data_size;
  cur_p = (char *) set->data_buf;

  for (i = 0; i < set->num_element; i++)
    {
      element[i] = cur_p;
      if (remain_size < 4)
	{
	  FREE_MEM (element);
	  return CCI_ER_COMMUNICATION;
	}
      NET_STR_TO_INT (ele_size, cur_p);
      cur_p += 4;
      remain_size -= 4;

      if (ele_size <= 0)
	continue;

      if (remain_size < ele_size)
	{
	  FREE_MEM (element);
	  return CCI_ER_COMMUNICATION;
	}
      cur_p += ele_size;
      remain_size -= ele_size;
    }

  set->element = element;
  return 0;
}

int
t_set_to_str (T_SET * set, T_VALUE_BUF * conv_val)
{
  T_NET_BUF net_buf;
  char *buf;
  int indicator;
  int err_code;
  int i;

  net_buf_init (&net_buf);

  net_buf_cp_str (&net_buf, "{", 1);

  for (i = 1; i <= set->num_element; i++)
    {
      if (i != 1)
	{
	  net_buf_cp_str (&net_buf, ", ", 2);
	}

      buf = NULL;
      err_code = t_set_get (set, i, CCI_A_TYPE_STR, (void *) &buf, &indicator);
      if (err_code < 0)
	{
	  net_buf_clear (&net_buf);
	  return err_code;
	}

      if (indicator < 0 || buf == NULL)
	{
	  buf = (char *) "NULL";
	}

      net_buf_cp_str (&net_buf, buf, strlen (buf));
    }

  net_buf_cp_str (&net_buf, "}", 2);

  hm_conv_value_buf_alloc (conv_val, net_buf.data_size);
  strcpy ((char *) conv_val->data, net_buf.data);

  net_buf_clear (&net_buf);

  return 0;
}

/************************************************************************
 * IMPLEMENTATION OF PRIVATE FUNCTIONS	 				*
 ************************************************************************/
