/*
 *	The entry point of IMM32.DLL.
 *
 *	Copyright 2000 Hidenori Takeshima
 */

#include "config.h"

#include "winbase.h"
#include "windef.h"
#include "wingdi.h"
#include "winuser.h"
#include "winerror.h"
#include "immddk.h"

#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(imm);

#include "imm_private.h"

static HANDLE			IMM32_hHeap;
static DWORD			IMM32_dwTLSIndex;
static CRITICAL_SECTION		IMM32_csIMM;

static BOOL IMM32_InitProcessMem( void );
static void IMM32_CleanupProcessMem( void );
static void IMM32_InitThreadData( void );
static void IMM32_CleanupThreadData( void );


/***********************************************************************
 *		IMM32_DllMain
 */
BOOL WINAPI IMM32_DllMain(
	HINSTANCE hInstDLL,
	DWORD fdwReason,
	LPVOID lpvReserved )
{
	switch ( fdwReason )
	{
	case DLL_PROCESS_ATTACH:
		IMM32_InitProcessMem();
		IMM32_RegisterIMEWndClass( hInstDLL );
		break;
	case DLL_PROCESS_DETACH:
		IMM32_UnloadAllIMEs();
		IMM32_UnregisterIMEWndClass( hInstDLL );
		IMM32_CleanupProcessMem();
		break;
	case DLL_THREAD_ATTACH:
		IMM32_InitThreadData();
		break;
	case DLL_THREAD_DETACH:
		IMM32_CleanupThreadData();
		break;
	}

	return TRUE;
}

static BOOL IMM32_InitProcessMem( void )
{
	IMM32_hHeap = (HANDLE)NULL;
	IMM32_dwTLSIndex = (DWORD)0xffffffff;

	IMM32_hHeap = HeapCreate( 0, 0x10000, 0 );
	if ( IMM32_hHeap == (HANDLE)NULL )
	{
		ERR( "cannot allocate heap for IMM32.\n" );
		return FALSE;
	}

	IMM32_dwTLSIndex = TlsAlloc();
	if ( IMM32_dwTLSIndex == (DWORD)0xffffffff )
	{
		ERR( "cannot allocate a TLS for IMM.\n" );
		return FALSE;
	}

	InitializeCriticalSection( &IMM32_csIMM );

	return TRUE;
}

static void IMM32_CleanupProcessMem( void )
{
	DeleteCriticalSection( &IMM32_csIMM );

	if ( IMM32_dwTLSIndex != (DWORD)0xffffffff )
	{
		TlsFree( IMM32_dwTLSIndex );
		IMM32_dwTLSIndex = (DWORD)0xffffffff;
	}

	if ( IMM32_hHeap != (HANDLE)NULL )
	{
		(void)HeapDestroy( IMM32_hHeap );
		IMM32_hHeap = (HANDLE)NULL;
	}
}

LPVOID IMM32_HeapAlloc( DWORD dwFlags, DWORD dwSize )
{
	return HeapAlloc( IMM32_hHeap, dwFlags, dwSize );
}

LPVOID IMM32_HeapReAlloc( DWORD dwFlags, LPVOID lpv, DWORD dwSize )
{
	return HeapReAlloc( IMM32_hHeap, dwFlags, lpv, dwSize );
}

void IMM32_HeapFree( LPVOID lpv )
{
	if ( lpv != NULL )
		HeapFree( IMM32_hHeap, 0, lpv );
}


static void IMM32_InitThreadData( void )
{
	TlsSetValue( IMM32_dwTLSIndex, NULL );
}

static void IMM32_CleanupThreadData( void )
{
	IMM32_THREADDATA*	pData;

	pData = (IMM32_THREADDATA*)TlsGetValue( IMM32_dwTLSIndex );
	if ( pData != NULL )
	{
		/* Destroy Thread-local Data. */
		if ( pData->hwndIME != (HWND)NULL )
			DestroyWindow( pData->hwndIME );
		if ( pData->hIMC != NULLIMC )
			ImmDestroyContext( pData->hIMC );

		IMM32_HeapFree( pData );
		TlsSetValue( IMM32_dwTLSIndex, NULL );
	}
}

IMM32_THREADDATA* IMM32_GetThreadData( void )
{
	IMM32_THREADDATA*	pData;

	pData = (IMM32_THREADDATA*)TlsGetValue( IMM32_dwTLSIndex );
	if ( pData != NULL )
		return pData;

	pData = (IMM32_THREADDATA*)
			IMM32_HeapAlloc( 0, sizeof(IMM32_THREADDATA) );
	if ( pData == NULL )
		return NULL;

	/* Initialize Thread-local Data. */
	pData->hwndIME = (HWND)NULL;
	pData->hIMC = NULLIMC;

	TlsSetValue( IMM32_dwTLSIndex, pData );

	return pData;
}

HIMC IMM32_GetDefaultContext( void )
{
	IMM32_THREADDATA*	pData;

	pData = IMM32_GetThreadData();
	if ( pData == NULL )
		return NULLIMC;
	if ( pData->hIMC == NULLIMC )
		pData->hIMC = ImmCreateContext();

	return pData->hIMC;
}

HWND IMM32_GetDefaultIMEWnd( void )
{
	IMM32_THREADDATA*	pData;

	pData = IMM32_GetThreadData();
	if ( pData == NULL )
		return NULLIMC;
	if ( pData->hwndIME == (HWND)NULL )
		pData->hwndIME = IMM32_CreateDefaultIMEWnd();

	return pData->hwndIME;
}


void IMM32_Lock( void )
{
	EnterCriticalSection( &IMM32_csIMM );
}

void IMM32_Unlock( void )
{
	LeaveCriticalSection( &IMM32_csIMM );
}
