#include <bfc/std.h>

// not perfect but it should work
int WCSICMP(const wchar_t *str1, const wchar_t *str2)
{
	while (*str1 && *str2) 
	{
		if (towlower(*str1) < towlower(*str2))
			return -1;
		if (towlower(*str2) < towlower(*str1)) 
			return 1;
		str1++;
		str2++;
	}
	
	if (!*str1 && !*str2) return 0;
	if (*str1) return 1;
	if (*str2) return -1;

	return -1; // shouldn't get here but we'll make the compiler shut up
}

int WCSNICMP(const wchar_t *str1, const wchar_t *str2, size_t len)
{
	while (*str1 && *str2 && len) 
	{
		if (towlower(*str1) < towlower(*str2)) 
			return -1;
		if (towlower(*str2) < towlower(*str1)) 
			return 1;
		str1++;
		str2++;
		len--;
	}

	if (!len) return 0;
	if (!*str1 && !*str2) return 0;
	if (*str1) return 1;
	if (*str2) return -1;

	return -1; // shouldn't get here but we'll make the compiler shut up
}


/* these are super slow because of memory allocation, but will tide us over until apple adds wcscasecmp and family to their BSD API */

#if 0 // remember this if we ever decide to use -fshort-wchar
int WCSICMP(const wchar_t *str1, const wchar_t *str2)
{
	CFStringRef cfstr1 =  CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)str1, wcslen(str1)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
	CFStringRef cfstr2 =  CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)str2, wcslen(str2)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
	int result = CFStringCompare(cfstr1, cfstr2, kCFCompareCaseInsensitive);
	CFRelease(cfstr1);
	CFRelease(cfstr2);
	return result;
}

int WCSNICMP(const wchar_t *str1, const wchar_t *str2, size_t len)
{
	CFStringRef cfstr1 =  CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)str1, wcslen(str1)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
	CFStringRef cfstr2 =  CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)str2, wcslen(str2)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
	int result =   CFStringCompareWithOptions(cfstr1, cfstr2, CFRangeMake(0, len), kCFCompareCaseInsensitive);
	CFRelease(cfstr1);
	CFRelease(cfstr2);
	return result;
}
#endif

int WCSICOLL(const wchar_t *str1, const wchar_t *str2)
{
	CFStringRef cfstr1 =  CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)str1, wcslen(str1)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
	CFStringRef cfstr2 =  CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)str2, wcslen(str2)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
	int result = CFStringCompare(cfstr1, cfstr2, kCFCompareCaseInsensitive|kCFCompareNonliteral);
	CFRelease(cfstr1);
	CFRelease(cfstr2);
	return result;
}

bool WCSIPREFIX(const wchar_t *str1, const wchar_t *prefix)
{
	CFStringRef cfstr1 =  CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)str1, wcslen(str1)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
	CFStringRef cfstr2 =  CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)prefix, wcslen(prefix)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
	bool result = CFStringHasPrefix(cfstr1, cfstr2);
	CFRelease(cfstr1);
	CFRelease(cfstr2);
	return result;
}

wchar_t *DO_WCSDUP(const wchar_t *ptr EXTRA_INFO) 
{
	if (ptr == NULL) return NULL;
	int size = wcslen(ptr);
	wchar_t *ret = (wchar_t *)MALLOC((size + 1) * sizeof(wchar_t));
	if (ret != NULL) 
	{
		WCSCPYN(ret, ptr, size+1);
	}
	return ret;
}

void WCSCPYN(wchar_t *dest, const wchar_t *src, int maxchar)
{
	ASSERT(dest != NULL);
	ASSERT(src != NULL);
	wcsncpy(dest, src, maxchar-1); // TODO: switch to a less brain dead function
  dest[maxchar-1]=0;
}

void STRTOUPPER(char *str) 
{
if (str)
{
  while (*str)
  {
    *str = toupper(*str);
  }
}
}
void STRTOLOWER(char *str) 
{
  if (str)
  {
    while (*str)
    {
      *str = towlower(*str);
    }
  }
}

COMEXP void WCSTOUPPER(wchar_t *str)
{
  if (str)
  {
    while (*str)
    {
      *str = towupper(*str);
    }
  }
}

COMEXP void WCSTOLOWER(wchar_t *str)
{
  if (str)
  {
    while (*str)
    {
      *str = towlower(*str);
    }
  }
}

int WCSICMPSAFE(const wchar_t *str1, const wchar_t *str2, const wchar_t *defval1, const wchar_t *defval2) 
{
  if (str1 == NULL) str1 = defval1;
  if (str2 == NULL) str2 = defval2;
  return WCSICMP(str1, str2);
}

wchar_t *WCSTOK(wchar_t *str, const wchar_t *sep, wchar_t **last)
{
	return wcstok(str, sep, last);
}

int WCSCASEEQLSAFE(const wchar_t *str1, const wchar_t *str2, const wchar_t *defval1, const wchar_t *defval2) 
{
  return !WCSICMPSAFE(str1, str2, defval1, defval2);
}

int STRLEN(const char *str) 
{
  ASSERT(str != NULL);
  return strlen(str);
}

bool ISALPHA(wchar_t alpha) 
{
	return iswalpha(alpha); 
}

bool ISDIGIT(wchar_t digit)
{
  return iswdigit(digit);
}

bool ISSPACE(wchar_t space)
{
  return iswspace(space);
}

bool ISPUNCT(wchar_t punct)
{
  return iswpunct(punct);
}

int STRCMP(const char *str1, const char *str2) 
{
  ASSERT(str1!=NULL);
  ASSERT(str2!=NULL);
  return strcmp(str1, str2);
}

int STRCMPSAFE(const char *str1, const char *str2, const char *defval1, const char *defval2) 
{
  if (str1 == NULL) str1 = defval1;
  if (str2 == NULL) str2 = defval2;
  return STRCMP(str1, str2);
}

void STRNCPY(char *dest, const char *src, int maxchar) 
{
  ASSERT(dest != NULL);
  ASSERT(src != NULL);
  strncpy(dest, src, maxchar);
  //INLINE
}

int STRICMPSAFE(const char *str1, const char *str2, const char *defval1, const char *defval2) 
{
  if (str1 == NULL) str1 = defval1;
  if (str2 == NULL) str2 = defval2;
  return STRICMP(str1, str2);
}

int STRICMP(const char *str1, const char *str2) 
{
  ASSERT(str1!=NULL);
  ASSERT(str2!=NULL);
  return strcasecmp(str1, str2);
}

void STRCPY(char *dest, const char *src) 
{
  ASSERT(dest != NULL);
  ASSERT(src != NULL);
  ASSERT(dest != src);
  strcpy(dest, src);
  //INLINE
}

char *STRSTR(const char *str1, const char *str2) 
{
  ASSERT(str1!=NULL);
  ASSERT(str2!=NULL);
  ASSERT(str1 != str2);
  return strstr(str1, str2);
}