/**

  Windows用 Tool



*/

#include  "WinTools.h"


//#include  "..\stdafx.h"
//#include  "..\resource.h"

//#include  "tools++.h"




using namespace jbxl;
using namespace jbxwl;







////////////////////////////////////////////////////////////////////////////////////////
// Uicode

//
// locale が正しくないと，日本語の変換は失敗する．setlocale( LC_CTYPE, "jpn" )
//

Buffer  jbxwl::tc2Buffer(TCHAR* tchar, int size)
{
	if (size<=0) size = LDATA;
	Buffer buf = make_Buffer(size);

#ifdef _UNICODE
	size_t len;
	int err = wcstombs_s(&len, (char*)buf.buf, buf.bufsz, tchar, _TRUNCATE);

	if (err!=0) clear_Buffer(&buf);
	else buf.vldsz = (int)Min(len-1, strlen((char*)buf.buf));
	buf.state = err;

#else
	copy_s2Buffer(tchar, &buf);

#endif

	return buf;
}



Buffer  jbxwl::ts2Buffer(LPCTSTR str, int size)
{
	if (size<=0) size = (int)tcslen(str);

#ifdef _UNICODE
	Buffer buf = make_Buffer((size+1)*4);
	size_t len;

	int err = wcstombs_s(&len, (char*)buf.buf, buf.bufsz, str, _TRUNCATE);
	if (err!=0) clear_Buffer(&buf);
	else buf.vldsz = (int)Min(len-1, strlen((char*)buf.buf));
	buf.state = err;

#else
	Buffer buf = make_Buffer(size);
	copy_b2Buffer((char*)str, &buf, size);

#endif

	return buf;
}



CString  jbxwl::mbs2ts(char* str)
{
	CString buf = _T("");
	if (str==NULL) return buf;

#ifdef _UNICODE
	TCHAR  tchar[LBUF];
	size_t len;
	int err = mbstowcs_s(&len, tchar, LDATA, str, strlen(str));
	if (err==0) buf = tchar;

#else
	buf = (LPTSTR)str;

#endif

	return buf;
}



//
// 要 free.  NULL は絶対に返ってこない
// 
/*
char*  jbxwl::ts2mbs(LPCTSTR str)
{
	Buffer buf = ts2Buffer(str);
	return (char*)buf.buf;
}
*/



//////////////////////////////////////////////////////////////////

//
//	戻り値： 0以上  dstのバッファにコピーされた文字数．
//				-1  srcまたは dstが NULL 
//				-2  メモリの確保に失敗した．何も実行されなかった．

int  jbxwl::copy_ts2Buffer(LPCTSTR str, Buffer* buf)
{
	if (buf==NULL) return -1;
	int cc = 0;

#ifdef _UNICODE
	char* mbstr = ts2mbs(str);
	copy_s2Buffer(mbstr, buf);
	::free(mbstr);
	cc = buf->vldsz;

#else
	cc = copy_s2Buffer((char*)str, buf);

#endif

	return cc;
}




//
//	戻り値： 0以上  dstのバッファにコピーされた文字数．
//				-1  srcまたは dstが NULL 
//				-2  メモリの確保に失敗した．何も実行されなかった．

int  jbxwl::cat_ts2Buffer(LPCTSTR str, Buffer* buf)
{
	if (buf==NULL) return -1;
	int cc = 0;

#ifdef _UNICODE
	char* mbstr = ts2mbs(str);
	cat_s2Buffer(mbstr, buf);
	::free(mbstr);
	cc = buf->vldsz;

#else
	cc = cat_s2Buffer((char*)str, buf);

#endif

	return cc;
}




unsigned long int  jbxwl::file_size_t(LPCTSTR fn)											  
{									  
	struct _stat stbuf;											   														   
	_tstat(fn, &stbuf);
	return stbuf.st_size;
}




BOOL  jbxwl::file_exist_t(LPCTSTR fn)
{
	BOOL ret = FALSE;
	if (fn==NULL) return FALSE;

#ifdef _UNICODE
	FILE* fp = tfopen(fn, _T("rb"));
	if (fp!=NULL) {
		ret = TRUE;
		fclose(fp);
	}

#else
	ret = file_exist((char*)fn);

#endif

	return ret;
}




CString  jbxwl::get_file_name_t(LPCTSTR str)
{
	CString buf = _T("");

#ifdef _UNICODE
	char* mbstr = ts2mbs(str);
	char* fn = get_file_name(mbstr);
	buf = mbs2ts(fn);
	::free(mbstr);

#else
	char* fnm = get_file_name((char*)str);
	buf = (LPTSTR)fnm;

#endif

	return buf;
}




CString  jbxwl::numbering_name_t(LPCTSTR fmt, int n)
{
    TCHAR  fname[LNAME];

	sntprintf(fname, LNAME-1, fmt, n);	
	CString ret = fname;
    return ret;
}




tList*  jbxwl::get_dir_files_t(LPCTSTR dirn)
{
	tList* lp = NULL;
	tList* ln = NULL;

	WIN32_FIND_DATA  FindFileData;
	HANDLE hFind;
	CString dirstr = dirn;

	dirstr += _T("\\*");
	hFind = FindFirstFile((LPCTSTR)dirstr, &FindFileData);
	if (hFind!=INVALID_HANDLE_VALUE) {
		Buffer tmp;	
		do {
			tmp = ts2Buffer(dirn);
			cat_s2Buffer("\\", &tmp);
			cat_ts2Buffer(FindFileData.cFileName, &tmp);
			ln = add_tList_node_str(ln, NULL, tmp.buf);
			if (lp==NULL) lp = ln;
			free_Buffer(&tmp);
		} while (FindNextFile(hFind, &FindFileData));

		FindClose(hFind);
	}

	return lp;
}




void  jbxwl::setResourceLocale(void)
{
	CString locale = LoadString_byID(IDS_STR_LOCALE);
	_tsetlocale(LC_ALL, (LPCTSTR)locale);
	return;
}



void  jbxwl::setSystemLocale(void)
{
	_tsetlocale(LC_ALL, _T(""));
	return;
}




////////////////////////////////////////////////////////////////////////////////////////
//
//  Parameter
//

CString  jbxwl::get_tstr_param_tList(tList* lt, char* key, LPCTSTR dflt)
{
	Buffer buf = search_key_tList(lt, key, 1);
	if (buf.buf!=NULL) {
		CString ret = mbs2ts((char*)buf.buf);
		free_Buffer(&buf);
		return ret;
	}
	return (CString)dflt;
}





////////////////////////////////////////////////////////////////////////////////////////
//
// User
//

#pragma comment(lib, "userenv.lib")
#pragma comment(lib, "imagehlp.lib")


CString  jbxwl::GetCurrentUserHomeFolder(void)
{
	HANDLE  token;
	DWORD   size = (DWORD)LDATA;
	TCHAR   dirn[LDATA];
	CString ret = _T("");

	OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token);
	BOOL rslt = GetUserProfileDirectory(token, dirn, &size);

	if (rslt && size<=LDATA) ret = dirn;
	return ret;
}



CString  jbxwl::GetDefaultUserHomeFolder(void)
{
	DWORD  size = (DWORD)LDATA;
	TCHAR  dirn[LDATA];
	CString ret = _T("");

	BOOL rslt = GetDefaultUserProfileDirectory(dirn, &size);	
	if (rslt && size<=LDATA) ret = dirn;
	return ret;
}



CString  jbxwl::MakeWorkingFolderPath(LPCTSTR fnm, BOOL local, LPCTSTR dir, BOOL make)
{
	CString path = GetCurrentUserHomeFolder();

	if (local) path += _T("\\AppData\\Local");
	else       path += _T("\\AppData\\Roaming");

	if (dir!=NULL) path += dir;
	else           path += _T("\\");

	if (make) {
		char* mbstr = ts2mbs(path);
		MakeSureDirectoryPathExists(mbstr);
		::free(mbstr);
	}
	if (fnm!=NULL) path += fnm;

	return path;
}





////////////////////////////////////////////////////////////////////////////////////////
//
// Mouse
//

static TCHAR* MouseCursolTable[] = {
	IDC_APPSTARTING,	// 標準の矢印カーソルと小さい砂時計カーソル
	IDC_ARROW,			// 標準の矢印カーソル
	IDC_CROSS,			// 十字カーソル
	IDC_HAND,			// Windows 2000：ハンドカーソル
	IDC_HELP,			// ヘルプカーソル（矢印と疑問符）
	IDC_IBEAM,			// アイビーム（縦線）カーソル
	IDC_NO,				// 禁止カーソル（円に左上から右下への斜線）
	IDC_SIZEALL,		// 4 方向の矢印カーソル
	IDC_SIZENESW,		// 右上と左下を指す両方向矢印カーソル
	IDC_SIZENS,			// 上下を指す両方向矢印カーソル
	IDC_SIZENWSE,		// 左上と右下を指す両方向矢印カーソル
	IDC_SIZEWE,			// 左右を指す両方向矢印カーソル
	IDC_UPARROW,		// 上を指す垂直の矢印カーソル
	IDC_WAIT,			// 砂時計カーソル
	IDI_APPLICATION,	// アプリケーションアイコン
	IDI_ASTERISK,		// 情報アイコン（吹き出しの中に i）
	IDI_EXCLAMATION,	// 感嘆符のアイコン
	IDI_HAND,			// ストップマークのアイコン（米国の歩行者用信号の赤と同じで、手を開いて制止しているデザインです）
	IDI_QUESTION,		// 疑問符のアイコン
	IDI_WINLOGO,		// Windows ロゴのアイコン
	NULL
};



TCHAR*  jbxwl::GetMouseCursorType()
{
	CURSORINFO ci;

	ci.cbSize = sizeof(CURSORINFO);
	GetCursorInfo(&ci);

	if (ci.flags!=0) {
		TCHAR** table = MouseCursolTable;
		while (*table!=NULL) {
			if (ci.hCursor==LoadCursor(NULL, (LPTSTR)*table)) return *table;
			table++;
		}
		return NULL;
	}

	return NULL;
}






////////////////////////////////////////////////////////////////////////////////////////
//
//  Time
//

// 1分計 0-59999ms を返す．
unsigned short jbxwl::GetMsecondsTimer()
{
	SYSTEMTIME tm;
	GetLocalTime(&tm);

	unsigned short nm = tm.wSecond*(unsigned short)1000 + tm.wMilliseconds;
	return nm;
}



unsigned short jbxwl::GetMsecondsLapTimer(unsigned short pm, unsigned short* nt)
{
	SYSTEMTIME tm;
	GetLocalTime(&tm);

	unsigned short nm  = tm.wSecond*(unsigned short)1000 + tm.wMilliseconds;
	unsigned short ret;
	if (pm>nm) ret = nm + ((unsigned short)60000 - pm);
	else       ret = nm - pm;

	if (nt!=NULL) *nt = nm;
	return ret;
}






////////////////////////////////////////////////////////////////////////////////////////
//
// MENU Tool
//

/**
	メニューでリソースID id を持つものを探す．

*/
CMenu*  jbxwl::GetMenu_byID(CMenu* pMenu, UINT id)
{
	if (pMenu==NULL) return NULL;

	UINT n = pMenu->GetMenuItemCount();
	for (UINT i=0; i<n; i++){
		if (pMenu->GetMenuItemID(i)==id) return pMenu;

		CMenu* pSub = GetMenu_byID(pMenu->GetSubMenu(i), id);
		if (pSub!=NULL) return pSub;
	}
	return NULL;
}




CMenu*  jbxwl::GetMenu_byStringID(CMenu* pMenu, UINT id)
{
	if (pMenu==NULL) return NULL;

	CString str = LoadString_byID(id);
	if (str=="" || str.IsEmpty()) return NULL;

	return GetMenu_byName(pMenu, str);
}




CMenu*  jbxwl::GetMenu_byName(CMenu* pMenu, LPCTSTR name)
{
	if (pMenu==NULL) return NULL;
	CString str;

	UINT n = pMenu->GetMenuItemCount();
	for (UINT i=0; i<n; i++){
		pMenu->GetMenuString(i, str, MF_BYPOSITION);
		if (str==(CString)name) return pMenu->GetSubMenu(i);

		CMenu* pSub = GetMenu_byName(pMenu->GetSubMenu(i), name);
		if (pSub!=NULL) return pSub;
	}
	return NULL;
}





////////////////////////////////////////////////////////////////////////////////////////
//
// ディスパッチャー	
//

#ifndef va_start
	#include <stdarg.h>
#endif



/**
void  DisPatcher(int sno=0, unsigned int signal1, unsigned int signal2, ...);
  
  機能：シグナル（メッセージ）キューに溜まったシグナル（メッセージ）をディスパッチする．
  		引数に，無視する（ディスパッチしない）シグナル（メッセージ）を複数（可変）個指定可能．
  		プログラム自体を終了させるシグナル（メッセージ）がキューにあった場合は，プログラムを
  		強制終了させる．Windowsの場合は WM_QUIT (0x0111)
  
  		Windows 用のみ実装．Linux の処理の仕方は知らない.......（不勉強です）
  
  引数：無視するシグナル（メッセージ）の数，無視するシグナル１，無視するシグナル２，.........
  		シグナル（メッセージ）自体は unsigned int で指定する．
  		無視するシグナル（メッセージ）を指定しない場合は，引数無しで呼び出し可能
  
  例  ：DisPatcher(1, WM_NCLBUTTONDOWN);
  		DisPatcher();    DisPatcher(0) と同じ  
*/
void	jbxwl::DisPatcher(int signalno, ...)
{
	int   i;
	unsigned int*  ign_signal = NULL;

	va_list args;	
	va_start(args, signalno);

	if (signalno>0) ign_signal = (unsigned int*)malloc(signalno*sizeof(int));
	if (ign_signal==NULL) signalno = 0;
	for (i=0; i<signalno; i++) {
		ign_signal[i] = va_arg(args, unsigned int);
	}


	MSG msg;
	while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)){
		TranslateMessage(&msg);
		if (msg.message==WM_QUIT) exit(1);			//	強制終了
		for (i=0; i<signalno; i++) { 
			if (msg.message==ign_signal[i]) {
				msg.message = WM_NULL;
				break;
			}
		}
		DispatchMessage(&msg);
	}

	free(ign_signal);
	va_end(args);
	return;
}




////////////////////////////////////////////////////////////////////////////////////////
//
// メッセージ	
//

void	jbxwl::SendWinMessage(UINT mesg)
{
	CWinApp* app = AfxGetApp();
	if (app!=NULL) {
		CWnd* wnd = app->m_pMainWnd;
		if (wnd!=NULL) wnd->SendMessage(mesg);
	}
}





////////////////////////////////////////////////////////////////////////////////////////
//
// プログラムの再起動
//

void  jbxwl::RebootProgram(void)
{
	TCHAR path[LDATA];
	GetModuleFileName(NULL, (LPTSTR)path, (DWORD)LDATA);

	CString arg;
	arg.Format(_T("/waitpid %u"), GetCurrentProcessId());
	ShellExecute(NULL, NULL, (LPCTSTR)path, (LPCTSTR)arg, NULL, SW_SHOWNORMAL);

	SendWinMessage(WM_CLOSE);
}




BOOL  jbxwl::WaitPidTerm(int tm)
{
	DWORD pid = 0;

	for (int i=1; i<__argc; i++) {
		if (!tcscmp(__targv[i], _T("/waitpid"))) {
			if (i+1<__argc) {
				pid = ttoi(__targv[i+1]);
				break;
			}
		}
	}
	if (pid==0) return TRUE;

	HANDLE hdl = OpenProcess(SYNCHRONIZE, FALSE, pid);
	if (hdl!=NULL) {
		if (WaitForSingleObject(hdl, tm*1000)==WAIT_TIMEOUT) return FALSE;
	}

	return TRUE;
}





////////////////////////////////////////////////////////////////////////////////////////
//
// EventHandler
//

EventHandler::EventHandler(void)
{
	m_handle   = NULL;
	m_wait_err = 0;
}



void  EventHandler::free(void)
{
	if (m_handle!=NULL) {
		CloseHandle(m_handle);
		m_handle = NULL;
	}

	return;
}



HANDLE  EventHandler::create(BOOL manual, BOOL initial, LPCTSTR hname, LPSECURITY_ATTRIBUTES secu)
{
	if (m_handle!=NULL) return NULL;

	m_handle = CreateEvent(secu, manual, initial, hname);
	return m_handle;
}



/**
BOOL  EventHandler::wait(DWORD msec=INFINITE)

	m_wait_err：
		WAIT_OBJECT_0
		WAIT_TIMEOUT
		WAIT_FAILED
		WAIT_ABANDONED
*/
BOOL  EventHandler::wait(DWORD msec)
{
	m_wait_err = WAIT_FAILED;
	if (m_handle==NULL) return FALSE;

	m_wait_err = WaitForSingleObject(m_handle, msec);
	
	if (m_wait_err!=WAIT_OBJECT_0) return FALSE;
	return TRUE;
}



