package local;

public class LocalString {

    private String locale;	// locale used by this object

    /** Return an ordering string for str */
    public native String xfrm(String str);

    /** Sort the array in this locale */
    public native String[] sort(String[] input);

    public LocalString() throws InvalidLocaleException {
	this("");		// default to current locale
    }

    public LocalString(String locale) throws InvalidLocaleException {
	if (locale == null)
	    throw new NullPointerException("null locale");
	this.locale = locale;
	testLocale();		// verify locale at construction time
    }

    // private method to test if locale is legal
    private native void testLocale() throws InvalidLocaleException;

    static {
	System.loadLibrary("LocalString");
    }
}



#include "local_LocalString.h"
#include <stdlib.h>
#include <javaString.h>
#include <locale.h>

HArrayOfObject *
alloc_class_array(
    char *type,
    int cnt)
{
    HArrayOfObject *retval;

    retval = (HArrayOfObject *)ArrayAlloc(T_CLASS, cnt);
    if (retval == NULL) {
	SignalError(EE(),
	    "java/lang/OutOfMemoryError", NULL);
	return NULL;
    }
    unhand(retval)->body[cnt] =
	(HObject *)FindClass(EE(), type, TRUE);
    return retval;
}

void
local_LocalString_testLocale(
    struct Hlocal_LocalString *this_h)
{
    char *new_locale, *old_locale;

    new_locale = makeCString(unhand(this_h)->locale);
    old_locale = setlocale(LC_COLLATE, new_locale);
    if (old_locale == NULL) {
	SignalError(EE(),
	    "local/InvalidLocaleException",
	    new_locale);
	return;
    }
    setlocale(LC_COLLATE, old_locale);
}

HString *
local_LocalString_xfrm(
    struct Hlocal_LocalString *this_h,
    Hjava_lang_String *str_h)
{
    Hjava_lang_String *retval = NULL;
    char *str, *xfrm, *new_locale, *old_locale;
    size_t xfrm_len;

    str = allocCString(str_h);
    if (str == NULL)
        return NULL; /* allocCString() used SignalError() */
    xfrm_len = strxfrm(NULL, str, 0);
    if ((xfrm = (char *)malloc(xfrm_len + 1)) == NULL) {
        SignalError(EE(),
	    "java/lang/OutOfMemoryError", NULL);
        return NULL;
    }

    new_locale = makeCString(unhand(this_h)->locale);
    old_locale = setlocale(LC_COLLATE, new_locale);
    if (old_locale == NULL) {
	SignalError(EE(),
	    "java/lang/InternalError",
	    new_locale);
	goto cleanup;
    }
    strxfrm(xfrm, str, xfrm_len);
    setlocale(LC_COLLATE, old_locale);

    retval = makeJavaString(xfrm, xfrm_len);

cleanup:
    free(xfrm);
    free(str);
    return retval;
}

static int
cmp(const void *str1, const void *str2)
{
    return strcoll(*(char **)str1, *(char **)str2);
}

HArrayOfString *
local_LocalString_sort(
    struct Hlocal_LocalString *this_h,
    HArrayOfString *strings_h)
{
    ClassArrayOfString *in_strings;
    HArrayOfString *retval = NULL;
    ClassArrayOfString *retstrs;
    char **strings = NULL, *new_locale, *old_locale;
    int i, str_cnt;

    if (strings_h == NULL) { /* check for null reference */
	SignalError(EE(),
	    "java/lang/NullPointerException", "null array");
	return NULL;
    }

    in_strings = unhand(strings_h);
    str_cnt = obj_length(strings_h);
    strings = (char **)malloc(str_cnt * sizeof *strings);
    if (strings == NULL) {
	SignalError(EE(),
	    "java/lang/OutOfMemoryError", NULL);
	return NULL;
    }
    for (i = 0; i < str_cnt; i++) {
	if (in_strings->body[i] == NULL) {
	    SignalError(EE(),
		"java/lang/NullPointerException",
		"Null string in array");
	    goto cleanup;
	}
	strings[i] = makeCString(in_strings->body[i]);
	if (strings[i] == NULL)
	    goto cleanup; /* SignalError() already done */
    }

    new_locale = makeCString(unhand(this_h)->locale);
    old_locale = setlocale(LC_COLLATE, new_locale);
    if (old_locale == NULL) {
	SignalError(EE(),
	    "java/lang/InternalError",
	    new_locale);
	goto cleanup;
    }
    qsort(strings, str_cnt, sizeof *strings, cmp);
    setlocale(LC_COLLATE, old_locale);

    retval = (HArrayOfString *)
	alloc_class_array("java/lang/String", str_cnt);
    retstrs = unhand(retval);
    for (i = 0; i < str_cnt; i++) {
	retstrs->body[i] =
	    makeJavaString(strings[i], strlen(strings[i]));
    }

cleanup:
    free(strings);
    return retval;
}
