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

/**
 * FileDialog定数値
 */
#define FileDialog_LOAD	0
#define FileDialog_SAVE	1

/**
 * 「ファイルを開く」ダイアログを表示する
 */
static BOOL get_open_file_name(OPENFILENAME* ofn);

/**
 * 「ファイルを保存」ダイアログを表示する
 */
static BOOL get_save_file_name(OPENFILENAME* ofn);


/*
 * Class:     gnu_java_awt_peer_wce_WCEFileDialogPeer
 * Method:    createNative
 * Signature: (IIIII)I
 */
JNIEXPORT jint JNICALL Java_gnu_java_awt_peer_wce_WCEFileDialogPeer_createNative(JNIEnv *env, jobject peer_obj, jint parentWindowHandle, jint x, jint y, jint width, jint height) {
	peer_obj = (*env)->NewGlobalRef(env, peer_obj);
	if (! peer_obj) {
		throw_AWTError(env, "NewGlobalRef() failed.");
		return 0;
	}
	return (jint) create_native_file_dialog(peer_obj, (HWND) parentWindowHandle, x, y, width, height);
}

/*
 * Class:     gnu_java_awt_peer_wce_WCEFileDialogPeer
 * Method:    nativeGetFileName
 * Signature: (IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
 */
JNIEXPORT jstring JNICALL Java_gnu_java_awt_peer_wce_WCEFileDialogPeer_nativeGetFileName(JNIEnv *env,
																						 jobject peer_obj,
																						 jint ownerWindowHandle,
																						 int mode,
																						 jstring title,
																						 jstring directory,
																						 jstring file) {
	BOOL selected = FALSE;
	jstring selectedfile = NULL;
	_TCHAR* t = NULL;
	_TCHAR* d = NULL;
	_TCHAR* f = NULL;
	_TCHAR result[MAX_PATH + 1] = {0};
	OPENFILENAME of = {0};
	
	if (title) {
		t = get_string_chars(env, title);
	}
	if (directory) {
		d = get_string_chars(env, directory);
	}
	if (file) {
		// ファイル名が指定されている場合は、OPENFILENAME.lpstrFile にその値を設定する
		f = get_string_chars(env, file);
		_tcsncpy(result, f, sizeof(result) / sizeof(*result) - 1);
		result[sizeof(result) - 1] = _T('\0');
	}

	of.lStructSize = sizeof(OPENFILENAME);
	of.lpstrFilter = _T("All files\0*.*\0");
	of.hwndOwner = (HWND) ownerWindowHandle;
	of.lpstrFile = result;
	of.nMaxFile = MAX_PATH;
	of.lpstrInitialDir = d;
	of.lpstrTitle = t;
	

	switch (mode) {
	case FileDialog_LOAD:
		of.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
		selected = get_open_file_name(&of);
		break;

	case FileDialog_SAVE:
		of.Flags = OFN_OVERWRITEPROMPT;
		selected = get_save_file_name(&of);
		break;

	default:
		// ここには来ないはず
		assert(FALSE);
		throw_AWTError(env, "Illegal mode");
	}

	if (selected) {
		selectedfile = (*env)->NewString(env,
										 result,
										 _tcslen(result));
	}

	// 割り当てたメモリを開放する
	free(t);
	free(directory);
	free(f);

	return selectedfile;
}

static BOOL get_open_file_name(OPENFILENAME* ofn) {
	// gsgetfile.dll が存在する場合は、そちらを使用する
	HMODULE hModule = LoadLibrary(_T("gsgetfile.dll"));
	if (hModule) {
		typedef BOOL (*GSGETOPENFILENAME)(OPENFILENAME* pofn);
		GSGETOPENFILENAME gsGetOpenFileName
			= (GSGETOPENFILENAME) GetProcAddress(hModule, _T("gsGetOpenFileName"));
		if (gsGetOpenFileName) {
			return gsGetOpenFileName(ofn);
		}
	}

	// 標準のダイアログを表示する
	return GetOpenFileName(ofn);
}

static BOOL get_save_file_name(OPENFILENAME* ofn) {
	// gsgetfile.dll が存在する場合は、そちらを使用する
	HMODULE hModule = LoadLibrary(_T("gsgetfile.dll"));
	if (hModule) {
		typedef BOOL (*GSGETSAVEFILENAME)(OPENFILENAME* pofn);
		GSGETSAVEFILENAME gsGetSaveFileName
			= (GSGETSAVEFILENAME) GetProcAddress(hModule, _T("gsGetSaveFileName"));
		if (gsGetSaveFileName) {
			return gsGetSaveFileName(ofn);
		}
	}

	// 標準のダイアログを表示する
	return GetSaveFileName(ofn);
}
