// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
*
*   Copyright (C) 1997-2013, International Business Machines
*   Corporation and others.  All Rights Reserved.
*
*******************************************************************************
*   file name:  locavailable.cpp
*   encoding:   UTF-8
*   tab size:   8 (not used)
*   indentation:4
*
*   created on: 2010feb25
*   created by: Markus W. Scherer
*
*   Code for available locales, separated out from other .cpp files
*   that then do not depend on resource bundle code and res_index bundles.
*/

#include "unicode/utypes.h"
#include "unicode/locid.h"
#include "unicode/uloc.h"
#include "unicode/ures.h"
#include "cmemory.h"
#include "ucln_cmn.h"
#include "uassert.h"
#include "umutex.h"
#include "uresimp.h"

// C++ API ----------------------------------------------------------------- ***

U_NAMESPACE_BEGIN

static icu::Locale*  availableLocaleList = NULL;
static int32_t  availableLocaleListCount;
static icu::UInitOnce gInitOnceLocale = U_INITONCE_INITIALIZER;

U_NAMESPACE_END

U_CDECL_BEGIN

static UBool U_CALLCONV locale_available_cleanup(void)
{
    U_NAMESPACE_USE

    if (availableLocaleList) {
        delete []availableLocaleList;
        availableLocaleList = NULL;
    }
    availableLocaleListCount = 0;
    gInitOnceLocale.reset();

    return TRUE;
}

U_CDECL_END

U_NAMESPACE_BEGIN

void U_CALLCONV locale_available_init() {
    // This function is a friend of class Locale.
    // This function is only invoked via umtx_initOnce().

    // for now, there is a hardcoded list, so just walk through that list and set it up.
    //  Note: this function is a friend of class Locale.
    availableLocaleListCount = uloc_countAvailable();
    if(availableLocaleListCount) {
       availableLocaleList = new Locale[availableLocaleListCount];
    }
    if (availableLocaleList == NULL) {
        availableLocaleListCount= 0;
    }
    for (int32_t locCount=availableLocaleListCount-1; locCount>=0; --locCount) {
        availableLocaleList[locCount].setFromPOSIXID(uloc_getAvailable(locCount));
    }
    ucln_common_registerCleanup(UCLN_COMMON_LOCALE_AVAILABLE, locale_available_cleanup);
}

const Locale* U_EXPORT2
Locale::getAvailableLocales(int32_t& count)
{
    umtx_initOnce(gInitOnceLocale, &locale_available_init);
    count = availableLocaleListCount;
    return availableLocaleList;
}


U_NAMESPACE_END

// C API ------------------------------------------------------------------- ***

U_NAMESPACE_USE

/* ### Constants **************************************************/

/* These strings describe the resources we attempt to load from
 the locale ResourceBundle data file.*/
static const char _kIndexLocaleName[] = "res_index";
static const char _kIndexTag[]        = "InstalledLocales";

static char** _installedLocales = NULL;
static int32_t _installedLocalesCount = 0;
static icu::UInitOnce _installedLocalesInitOnce;

/* ### Get available **************************************************/

static UBool U_CALLCONV uloc_cleanup(void) {
    char ** temp;

    if (_installedLocales) {
        temp = _installedLocales;
        _installedLocales = NULL;

        _installedLocalesCount = 0;
        _installedLocalesInitOnce.reset();

        uprv_free(temp);
    }
    return TRUE;
}

// Load Installed Locales. This function will be called exactly once
//   via the initOnce mechanism.

static void U_CALLCONV loadInstalledLocales() {
    UResourceBundle *indexLocale = NULL;
    UResourceBundle installed;
    UErrorCode status = U_ZERO_ERROR;
    int32_t i = 0;
    int32_t localeCount;

    U_ASSERT(_installedLocales == NULL);
    U_ASSERT(_installedLocalesCount == 0);

    _installedLocalesCount = 0;
    ures_initStackObject(&installed);
    indexLocale = ures_openDirect(NULL, _kIndexLocaleName, &status);
    ures_getByKey(indexLocale, _kIndexTag, &installed, &status);

    if(U_SUCCESS(status)) {
        localeCount = ures_getSize(&installed);
        _installedLocales = (char **) uprv_malloc(sizeof(char*) * (localeCount+1));
        if (_installedLocales != NULL) {
            ures_resetIterator(&installed);
            while(ures_hasNext(&installed)) {
                ures_getNextString(&installed, NULL, (const char **)&_installedLocales[i++], &status);
            }
            _installedLocales[i] = NULL;
            _installedLocalesCount = localeCount;
            ucln_common_registerCleanup(UCLN_COMMON_ULOC, uloc_cleanup);
        }
    }
    ures_close(&installed);
    ures_close(indexLocale);
}

static void _load_installedLocales()
{
    umtx_initOnce(_installedLocalesInitOnce, &loadInstalledLocales);
}

U_CAPI const char* U_EXPORT2
uloc_getAvailable(int32_t offset)
{

    _load_installedLocales();

    if (offset > _installedLocalesCount)
        return NULL;
    return _installedLocales[offset];
}

U_CAPI int32_t  U_EXPORT2
uloc_countAvailable()
{
    _load_installedLocales();
    return _installedLocalesCount;
}

