#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <iconv.h>
#include "utfchar.h"
  
int 
_utfchar_concat (UTFCHAR *dest, UTFCHAR *str1, UTFCHAR *str2)
{
      int i;
      for (i = 0; *str1; i++) {
         *dest++ = *str1++;
      }
      for (i = 0; *str2; i++) {
         *dest++ = *str2++;
      }
      *dest = 0;
      return i;
}

UTFCHAR *
_utfchar_dup (UTFCHAR *src)
{
  UTFCHAR *new_utfchar;
  int n_len;
  n_len = _utfchar_length (src);
  if (n_len == 0)
    return NULL;
  new_utfchar = (UTFCHAR *) calloc (n_len + 1, sizeof (UTFCHAR ));
  _utfchar_copy (new_utfchar, src);
  return new_utfchar;
}

int
_utfchar_copy (UTFCHAR * dest, UTFCHAR * original)
{
  int i;
  if (dest == NULL || original == NULL)
    return -1;
  for (i = 0; *original; i++) {
    *dest++ = *original++;
  }
  *dest = 0;
  return i;
}
                                                                                                  
int
_utfchar_length (UTFCHAR * p)
{
  int i;
  assert (p != NULL);
  if (p == NULL)
    return 0;
  for (i = 0; *p; i++)
    p++;
  return i;
}

int
_utfchar_comp (UTFCHAR *s1, UTFCHAR *s2)
{
  UTFCHAR *p1, *p2;
  
  p1 = s1, p2 = s2;
  
  while (*p1 && *p2){
    if (*p1 > *p2)
      return 1;
    else if (*p1 < *p2)
      return -1;
    p1++, p2++;
  }
  if (!*p1 && *p2)
    return -1;
  if (!*p2 && *p1)
    return 1;
  return 0;
}

void
_utfchar_print (UTFCHAR *utf_string)
{
  int len;
  char from_buffer[100], to_buffer[100];
  int  from_i = 0, to_i = 0;
  char *f_ptr, *t_ptr;
  iconv_t cd;
  size_t ret;

  len = _utfchar_length (utf_string);
  
  memset (from_buffer, 0, 100); memset (to_buffer, 0, 100);
  memcpy (from_buffer, utf_string, sizeof (UTFCHAR) * (len + 1));
  
  f_ptr = from_buffer, t_ptr = to_buffer;
  from_i = len * sizeof (UTFCHAR) , to_i = 100;
  
  cd = iconv_open ("EUC-KR", "UTF16");
  if (cd == (iconv_t) -1) {
    fprintf (stderr, "_utfchar_print error: iconv_open error,"
	     "returning..\n");
    return;
  }
  ret = iconv (cd, &f_ptr, &from_i, &t_ptr, &to_i);
  if (ret == (size_t) -1){
    fprintf (stderr, "_utfchar_print error: iconv error,"
	     "returning...\n");
    return;
  }
  fprintf (stdout, "%s", to_buffer);
  iconv_close (cd);
  return;
}

UTFCHAR *
_utfchar_convert_u8_to_u16 (unsigned char *u8str)
{
  char *inbuf, *outbuf;
  int inlen, outlen, outlen2;
  char *inptr, *outptr;
  UTFCHAR *p16char;
  iconv_t cd;
  size_t iconv_ret;

  assert (u8str != NULL);
  if (!u8str || strlen (u8str) == 0){
    fprintf (stdout, "_dictionary_convert_u8_to_u16 error: "
	     "u8str is null or zero length");
    return NULL;
  }
  inlen = strlen (u8str);
  inbuf = (unsigned char *) calloc (inlen + 1, sizeof (unsigned char));
  strcpy (inbuf, u8str);
  /* just to be safe enough to hold converted string */
  outbuf =
    (unsigned char *) calloc (2 * (inlen + 1), sizeof (unsigned char));
  inptr = inbuf;
  outptr = outbuf;
  inlen = strlen (u8str);
  outlen2 = outlen = inlen * 2;

  cd = iconv_open ("UTF-16", "UTF-8");
  if (cd == (iconv_t) -1){
    fprintf (stdout, "_utfchar_convert_u8_to_u16 error :"
	     "iconv_open failed\n");
    return NULL;
  }
  
  iconv_ret = iconv (cd, &inptr, &inlen, &outptr, &outlen);
  if (iconv_ret == (size_t) -1){
    fprintf (stdout, "_utfchar_convert_u8_to_u16 error :"
	     "iconv failed\n");
    iconv_close (cd);
    free (inbuf);
    free (outbuf);
    
    return NULL;
  }
  
  if ((outbuf[0] == (char) 0xff) &&
      (outbuf[1] == (char) 0xff || outbuf[1] == (char) 0xfe)) {
    p16char =
      (UTFCHAR *) calloc ((outlen2 - outlen - 1) / 2 +1, sizeof (UTFCHAR));
    if(!p16char){
      fprintf (stdout, "_dictionary_convert_u8_to_u16 error: "
	       "memory allocation error\n");
      iconv_close (cd);
      free (inbuf);
      free (outbuf);
    
      return NULL;
    }
    memcpy (p16char, outbuf + 2, outlen2 - outlen - 2);
    
  } else {
    
    p16char =
      (UTFCHAR *) calloc ((outlen2 - outlen)/2 + 1, sizeof (UTFCHAR));
    if(!p16char){
      fprintf (stdout, "_dictionary_convert_u8_to_u16 error: "
	       "memory allocation error\n");
      iconv_close (cd);
      free (inbuf);
      free (outbuf);
    
      return NULL;
    }

    memcpy (p16char, outbuf, outlen2 - outlen);
  }

  free (inbuf);
  free (outbuf);
  iconv_close (cd);
  
  return p16char;
}

unsigned char *
_utfchar_convert_u16_to_u8 (UTFCHAR *u16str)
{
  char inbuf[1024], outbuf[1024];
#if 0  
  char *inbuf, *outbuf;
#endif
  int inlen, outlen, outlen2;
  char *inptr, *outptr;
  unsigned char *p8char;
  iconv_t cd;
  size_t iconv_ret;

  assert (u16str != NULL);
  if (!u16str || _utfchar_length (u16str) == 0){
    fprintf (stdout, "_dictionary_convert_u16_to_u8 error: "
	     "u16str is null or zero length\n");
    return NULL;

  }
#if 0
  inlen = (_utfchar_length (u16str) + 1) * sizeof (UTFCHAR);
  inbuf =
    (char *) calloc (_utfchar_length (u16str) + 1, sizeof (UTFCHAR));
  memcpy (inbuf, u16str, sizeof (UTFCHAR) * inlen);
  inptr = inbuf;
#endif
  inlen = sizeof (inbuf);
  memset (inbuf, 0, inlen);
  memcpy (inbuf, u16str, _utfchar_length (u16str) * sizeof (UTFCHAR ));
  inptr = inbuf;
  
#if 0
  /* just to be safe enough to hold converted string */
  outbuf =
    (unsigned char *) calloc (2 * inlen, sizeof (unsigned char));
  outlen2 = outlen = inlen * 2;
  outptr = outbuf;
#endif
  
  outlen2 = outlen = sizeof (outbuf);
  memset (outbuf, 0, outlen);
  outptr = outbuf;

  cd = iconv_open ("UTF-8", "UTF-16");
  if (cd == (iconv_t) -1){
    fprintf (stdout, "_dictionary_convert_u16_to_u8 error: "
	     "iconv_open failed\n");
    return NULL;
  }
  
  iconv_ret = iconv (cd, &inptr, &inlen, &outptr, &outlen);
  
  if (iconv_ret == (size_t) -1){
    fprintf (stdout, "_dictionary_convert_u16_to_u8 error: "
	     "iconv failed\n");
    if (cd != (iconv_t) -1)
      iconv_close (cd);
    return NULL;
  }
  
  p8char =
    (unsigned char *)calloc (outlen2 - outlen + 1, sizeof (unsigned char));
  if(!p8char){
    fprintf (stdout, "_dictionary_convert_u16_to_u8 error: "
	     "memory allocation error\n");
    return NULL;
  }
  memcpy (p8char, outbuf, outlen2 - outlen);
#if 0
  free (inbuf);
  free (outbuf);
#endif
  iconv_close (cd);
  return p8char;

}
