/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



#define UNICODE
#ifdef _MSC_VER
#pragma warning(push,1) /* disable warnings within system headers */
#endif
#include <windows.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include <wchar.h>

#include <osl/mutex.h>
#include <osl/nlsupport.h>
#include <osl/diagnose.h>
#include <osl/process.h>
#include <rtl/tencinfo.h>

struct EnumLocalesParams
{
	WCHAR Language[3];
	WCHAR Country[3];
	LCID  Locale;
};

static DWORD g_dwTLSLocaleEncId = (DWORD) -1;

/*****************************************************************************/
/* callback function test
/* 
/* osl_getTextEncodingFromLocale calls EnumSystemLocalesA, so that we don't
/* need to provide a unicode wrapper for this function under Win9x
/* that means the callback function has an ansi prototype and receives
/* the locale strings as ansi strings
/*****************************************************************************/

BOOL CALLBACK EnumLocalesProcA( LPSTR lpLocaleStringA )
{
	struct EnumLocalesParams * params;

	LCID  localeId;	
	LPSTR pszEndA;

	WCHAR langCode[4];
   
	/* convert hex-string to LCID */	
    localeId = strtol( lpLocaleStringA, &pszEndA, 16 );

	/* check params received via TLS */
	params = (struct EnumLocalesParams *) TlsGetValue( g_dwTLSLocaleEncId );
	if( NULL == params || '\0' == params->Language[0] )
		return FALSE;

	/* 
        get the ISO language code for this locale 
    
        remeber: we call the GetLocaleInfoW function
        because the ansi version of this function returns
        an error under WinNT/2000 when called with an 
        unicode only lcid 
    */
	if( GetLocaleInfo( localeId, LOCALE_SISO639LANGNAME , langCode, 4 ) )
	{
		WCHAR ctryCode[4];

		/* continue if language code does not match */
		if( 0 != wcscmp( langCode, params->Language ) )
			return TRUE;

		/* check if country code is set and equals the current locale */
		if( '\0' != params->Country[0] && GetLocaleInfo( localeId, LOCALE_SISO3166CTRYNAME , ctryCode, 4 ) )
		{
			/* save return value in TLS and break if  found desired locale */
			if( 0 == wcscmp( ctryCode, params->Country ) )
			{
				params->Locale = localeId;
				return FALSE;
			}
		}
		else
		{
			/* fill with default values for that language */
			LANGID langId = LANGIDFROMLCID( localeId );

			/* exchange sublanguage with SUBLANG_NEUTRAL */
			langId = MAKELANGID( PRIMARYLANGID( langId ), SUBLANG_NEUTRAL );

			/* and use default sorting order */
			params->Locale = MAKELCID( langId, SORT_DEFAULT );

			return FALSE;
		}
	}

	/* retry by going on */
	return TRUE;
}


/*****************************************************************************/
/* GetTextEncodingFromLCID
/*****************************************************************************/

rtl_TextEncoding GetTextEncodingFromLCID( LCID localeId )
{
	rtl_TextEncoding Encoding = RTL_TEXTENCODING_DONTKNOW;
	WCHAR ansiCP[6];

	/* query ansi codepage for given locale */
	if( localeId && GetLocaleInfo( localeId, LOCALE_IDEFAULTANSICODEPAGE, ansiCP, 6 ) )
	{
		/* if GetLocaleInfo returns "0", it is a UNICODE only locale */
		if( 0 != wcscmp( ansiCP, L"0" ) )
		{
			WCHAR *pwcEnd;
			UINT  codepage;

			/* values returned from GetLocaleInfo are dezimal based */
			codepage = wcstol( ansiCP, &pwcEnd, 10 );

			/* find matching rtl encoding */
			Encoding = rtl_getTextEncodingFromWindowsCodePage( codepage );
		}
		else
			Encoding = RTL_TEXTENCODING_UNICODE;
	}

	return Encoding;
}


/*****************************************************************************/
/* osl_getTextEncodingFromLocale
/*****************************************************************************/

rtl_TextEncoding SAL_CALL osl_getTextEncodingFromLocale( rtl_Locale * pLocale )
{
	struct EnumLocalesParams params = { L"", L"", 0 };

	/* initialise global TLS id */
	if( (DWORD) -1 == g_dwTLSLocaleEncId )
	{
		oslMutex globalMutex = * osl_getGlobalMutex();

		/* initializing must be thread save */
		osl_acquireMutex( globalMutex );

		if( (DWORD) -1 == g_dwTLSLocaleEncId )
			g_dwTLSLocaleEncId = TlsAlloc();

		osl_releaseMutex( globalMutex );
	}

    /* if pLocale is NULL, use process locale as default */
    if( NULL == pLocale )
        osl_getProcessLocale( &pLocale );

	/* copy in parameters to structure */
	if( pLocale && pLocale->Language )
	{
		wcscpy( params.Language, pLocale->Language->buffer );

		if( pLocale->Country )
			wcscpy( params.Country, pLocale->Country->buffer );

		/* save pointer to local structure in TLS */
		TlsSetValue( g_dwTLSLocaleEncId, &params );

		/* enum all locales known to Windows */
		EnumSystemLocalesA( EnumLocalesProcA, LCID_SUPPORTED );

		/* use the LCID found in iteration */
		return GetTextEncodingFromLCID( params.Locale );
	}

	return RTL_TEXTENCODING_DONTKNOW;
}

/*****************************************************************************/
/* imp_getProcessLocale
/*****************************************************************************/

void _imp_getProcessLocale( rtl_Locale ** ppLocale )
{
	WCHAR langCode[4];
	WCHAR ctryCode[4];
    LCID  localeId;

    OSL_ASSERT( ppLocale );

    /* get the LCID to retrieve information from */
    localeId = GetUserDefaultLCID();

    /* call GetLocaleInfo to retrieve the iso codes */
	if( GetLocaleInfo( localeId, LOCALE_SISO639LANGNAME , langCode, 4 )  &&
        GetLocaleInfo( localeId, LOCALE_SISO3166CTRYNAME , ctryCode, 4 ) )
	{
        *ppLocale = rtl_locale_register( langCode, ctryCode, L"" );
    }
    else
	{
        *ppLocale = rtl_locale_register( L"C", L"", L"" );
    }
}


