#include <windows.h>
#include <jni.h>
#include "wce-peer.h"
#include <gnu_java_awt_peer_wce_WCEToolkit.h>

/**
 * スレッド数。
 */
static LONG g_threads_count;

/**
 * GetSysColor()で使用するインデックス値と、SystemColorクラスインデックス値との
 * 対応表
 */
static int g_system_colors_index[] = {
	COLOR_DESKTOP,						// SystemColor.DESKTOP
	COLOR_ACTIVEBORDER,					// SystemColor.ACTIVE_CAPTION
	COLOR_CAPTIONTEXT,					// SystemColor.ACTIVE_CAPTION_TEXT
	COLOR_ACTIVEBORDER,					// SystemColor.ACTIVE_CAPTION_BORDER
	COLOR_INACTIVECAPTION,				// SystemColor.INACTIVE_CAPTION
	COLOR_INACTIVECAPTIONTEXT,			// SystemColor.INACTIVE_CAPTION_TEXT
	COLOR_INACTIVEBORDER,				// SystemColor.INACTIVE_CAPTION_BORDER
	COLOR_WINDOW,						// SystemColor.WINDOW
	COLOR_WINDOWFRAME,					// SystemColor.WINDOW_BORDER
	COLOR_WINDOWTEXT,					// SystemColor.WINDOW_TEXT
	COLOR_MENU,							// SystemColor.MENU
	COLOR_MENUTEXT,						// SystemColor.MENU_TEXT
	COLOR_STATIC,						// SystemColor.TEXT
	COLOR_STATICTEXT,					// SystemColor.TEXT_TEXT
	COLOR_HIGHLIGHT,					// SystemColor.TEXT_HIGHLIGHT
	COLOR_HIGHLIGHTTEXT,				// SystemColor.TEXT_HIGHLIGHT_TEXT
	COLOR_GRAYTEXT,						// SystemColor.TEXT_INACTIVE_TEXT
	COLOR_BTNFACE,						// SystemColor.CONTROL
	COLOR_BTNTEXT,						// SystemColor.CONTROL_TEXT
	COLOR_BTNHIGHLIGHT,					// SystemColor.CONTROL_HIGHLIGHT
	COLOR_3DLIGHT,						// SystemColor.CONTROL_LT_HIGHLIGHT
	COLOR_BTNSHADOW,					// SystemColor.CONTROL_SHADOW
	COLOR_3DDKSHADOW,					// SystemColor.CONTROL_DK_SHADOW
	COLOR_SCROLLBAR,					// SystemColor.SCROLLBAR
	COLOR_INFOBK,						// SystemColor.INFO
	COLOR_INFOTEXT,						// SystemColor.INFO_TEXT
};

/**
 * 基本的にシステムカラーは変化しないので、一度読み込んだ後は保持しておく
 */
static jint* g_system_colors;

/*
 * Class:     gnu_java_awt_peer_wce_WCEToolkit
 * Method:    init
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_wce_WCEToolkit_init(JNIEnv *env, jclass clazz) {
	init(env);
}

/*
 * Class:     gnu_java_awt_peer_wce_WCEToolkit
 * Method:    run
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_wce_WCEToolkit_run(JNIEnv *env, jobject toolkit) {
	MSG msg;
	jclass clazz;
	jmethodID notifyID;
	jfieldID initializedID;
	
	OutputDebugString(_T("Starting OS message loop thread.\n"));
	if (InterlockedIncrement(&g_threads_count) > 1) {
		// 2つ以上のスレッドを生成することはできない。
		OutputDebugString(_T("WARNING: OS message loop thread already exists.\n"));
		return;
	}

	initialize_system_window(env, toolkit);

	// 初期化完了を通知する
	clazz = (*env)->GetObjectClass(env, toolkit);
	initializedID = (*env)->GetStaticFieldID(env, clazz, "initialized", "Z");
	(*env)->SetStaticBooleanField(env, clazz, initializedID, JNI_TRUE);

	// クラスロックを取得して、notify()する
	(*env)->MonitorEnter(env, clazz);
	notifyID = (*env)->GetMethodID(env, clazz, "notify", "()V");
	(*env)->CallVoidMethod(env, clazz, notifyID);
	(*env)->MonitorExit(env, clazz);

	// 不要になったローカル参照を削除する
	(*env)->DeleteLocalRef(env, clazz);

	// メッセージループを開始する
	while (GetMessage(&msg, NULL, 0, 0) > 0) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	OutputDebugString(_T("OS Message loop thread end.\n"));
}

/*
 * Class:     gnu_java_awt_peer_wce_WCEToolkit
 * Method:    run
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_wce_WCEToolkit_handleNativeMessage(JNIEnv *env, jobject toolkit, int hWnd, int msg, int wp, int lp) {
	handle_native_message(env, (HWND) hWnd, (UINT) msg, (WPARAM) wp, (LPARAM) lp);
}

/*
 * Class:     gnu_java_awt_peer_wce_WCEToolkit
 * Method:    loadNativeSystemColors
 * Signature: ([I)V
 */
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_wce_WCEToolkit_loadNativeSystemColors(JNIEnv *env, jobject toolkit, jintArray systemColors) {
	int i, count;
	int arraylen = (*env)->GetArrayLength(env, systemColors);		
	int indexlen = sizeof(g_system_colors_index) / sizeof(g_system_colors_index[0]);
	if (g_system_colors == NULL) {
		g_system_colors = (jint*) malloc(sizeof(jint) * indexlen);
		for (i = 0; i < indexlen; ++i) {
			// COLORREFからColor.getRGB()が返す形式に変換する
			// COLORREF       = 00bbggrr
			// Color.getRGB() = 00rrggbb
			COLORREF colorref = (COLORREF) GetSysColor(g_system_colors_index[i]);
			g_system_colors[i] = ((colorref << 16) & 0xff0000) | (colorref & 0xff00) | ((colorref >> 16) & 0xff);
		}
	}
	count = indexlen > arraylen ? arraylen : indexlen;
	(*env)->SetIntArrayRegion(env, systemColors, 0, count, g_system_colors);
}

/*
 * Class:     gnu_java_awt_peer_wce_WCEToolkit
 * Method:    beep
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_wce_WCEToolkit_beep(JNIEnv *env, jobject toolkit) {
	// システムデフォルト
	MessageBeep(0xFFFFFFFF);
}

/*
 * Class:     gnu_java_awt_peer_wce_WCEToolkit
 * Method:    getScreenResolution
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_gnu_java_awt_peer_wce_WCEToolkit_getScreenResolution(JNIEnv *env, jobject toolkit) {
	return (jint) GetDeviceCaps(NULL, LOGPIXELSX);
}
