#include "stdafx.h"
#include "rnsf7.h"
#include "cpp_func.h"
#include "symbol.h"

using namespace std;
using namespace boost;

// 正規表現にマッチしているかを調べる
unsigned int cpp_regex_match(const char *str, const char *re, const char *option)
{
	bool re_opt_i = 0;		// 大文字・小文字を無視する
	bool re_opt_s = 0;		// すべてを一行として扱う
	bool re_opt_g = 0;		// 全マッチ

	if ( str == NULL || re == NULL ) { // 引数チェック
		return ERRORVALUE;
	}

	if ( option ) { // オプションの解析
		if ( strchr(option, 'i') != NULL )
			re_opt_i = 1;
		if ( strchr(option, 's') != NULL )
			re_opt_s = 1;
		if ( strchr(option, 'g') != NULL )
			re_opt_g = 1;
	}

	try {
		vector<wchar_t> vw;		// ワークエリア

		// 正規表現文字列の準備
		// Boostのregexは、そのままではMultiByteに対応しない
		// いったん WideChar に変換する

		int i = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, re, -1, NULL, 0);
		if ( i == 0 ) {
			return ERRORVALUE;
		}
		vw.resize(i+1);
		if ( 0 == MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, re, -1, &vw[0], i+1) ) {
			return ERRORVALUE;
		}
		wstring w_re = &vw[0];
		wregex wre(w_re, (re_opt_i ? wregex::icase : wregex::normal));

		// 検索対象文字列の準備
		// 同様の理由により WideChar に変換する

		i = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, str, -1, NULL, 0);
		if ( i == 0 ) {
			return ERRORVALUE;
		}
		vw.resize(i+1);
		if ( 0 == MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, str, -1, &vw[0], i+1) ) {
			return ERRORVALUE;
		}
		wstring w_str = &vw[0];

		regex_constants::match_flag_type flags = regex_constants::match_default;
		if ( re_opt_s )
			flags |= regex_constants::match_single_line;
		if ( re_opt_g )
			flags |= regex_constants::match_any;

		return regex_match(w_str, wre, flags) ? TRUE : FALSE;
	}
	catch(...) {
		return ERRORVALUE;
	}
}

// Unicode な文字列の文字数を、Shift-JISな文字数にして返す（内部用関数）
unsigned int wclen2mblen(const char *str, unsigned int po)
{
	unsigned int i;

	for(i=0 ; str[i] ; ++i ) {
		if ( po-- == 0  ) {
            break;
		}
		if ( ISKANJI1M(str[i]) ) {
			++i;
			if ( str[i] == 0 )
				break;
		}
	}

	return i;
}

// 正規表現でサーチを行う
unsigned int cpp_regex_search(const char *str, const char *re, const char *option, const char *startpoints, const char *lengths)
{
	bool re_opt_i = 0;		// 大文字・小文字を無視する
	bool re_opt_s = 0;		// すべてを一行として扱う
	bool re_opt_g = 0;		// 全マッチ

	if ( str == NULL || re == NULL ) { // 引数チェック
		return ERRORVALUE;
	}

	if ( option ) { // オプションの解析
		if ( strchr(option, 'i') != NULL )
			re_opt_i = 1;
		if ( strchr(option, 's') != NULL )
			re_opt_s = 1;
		if ( strchr(option, 'g') != NULL )
			re_opt_g = 1;
	}

	try {
		vector<wchar_t> vw;		// ワークエリア

		// 正規表現文字列の準備
		// Boostのregexは、そのままではMultiByteに対応しない
		// いったん WideChar に変換する

		int i = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, re, -1, NULL, 0);
		if ( i == 0 ) {
			return ERRORVALUE;
		}
		vw.resize(i+1);
		if ( 0 == MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, re, -1, &vw[0], i+1) ) {
			return ERRORVALUE;
		}
		wstring w_re = &vw[0];
		wregex wre(w_re, (re_opt_i ? wregex::icase : wregex::normal));

		// 検索対象文字列の準備
		// 同様の理由により WideChar に変換する

		i = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, str, -1, NULL, 0);
		if ( i == 0 ) {
			return ERRORVALUE;
		}
		vw.resize(i+1);
		if ( 0 == MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, str, -1, &vw[0], i+1) ) {
			return ERRORVALUE;
		}
		wstring w_str = &vw[0];

		regex_constants::match_flag_type flags = regex_constants::match_default;
		if ( re_opt_s )
			flags |= regex_constants::match_single_line;
		if ( re_opt_g )
			flags |= regex_constants::match_any;

		wsmatch wresult;
		unsigned num = 0;

		wsregex_iterator it( w_str.begin(), w_str.end(), wre, flags );
		wsregex_iterator end;

		if ( startpoints && lengths ) {
			resize_variables(startpoints, 0);
			resize_variables(lengths, 0);
		}

		for(; it!=end; ++it) {
			++num;
			if ( startpoints && lengths ) {
				unsigned ip = (unsigned)it->position(), ip2;
				unsigned il = (unsigned)it->length();

				resize_variables(startpoints, num);
				resize_variables(lengths, num);

				setVariable_a(startpoints, num-1, ip2 = wclen2mblen(str, ip));
				setVariable_a(lengths, num-1, wclen2mblen(str+ip2, il));
			}
		}

		return num;
	}
	catch(...) {
		return ERRORVALUE;
	}
}

// 正規表現で文字列置換を行う
char *cpp_regex_replace(const char *str, const char *re, const char *rep, const char *option)
{
	bool re_opt_i = 0;		// 大文字・小文字を無視する
	bool re_opt_s = 0;		// すべてを一行として扱う
	bool re_opt_g = 0;		// 全マッチ

	if ( str == NULL || re == NULL || rep == NULL ) { // 引数チェック
		return NULL;
	}

	if ( option ) { // オプションの解析
		if ( strchr(option, 'i') != NULL )
			re_opt_i = 1;
		if ( strchr(option, 's') != NULL )
			re_opt_s = 1;
		if ( strchr(option, 'g') != NULL )
			re_opt_g = 1;
	}

	try {
		vector<wchar_t> vw;		// ワークエリア

		// 正規表現文字列の準備
		// Boostのregexは、そのままではMultiByteに対応しない
		// いったん WideChar に変換する

		int i = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, re, -1, NULL, 0);
		if ( i == 0 ) {
			return NULL;
		}
		vw.resize(i+1);
		if ( 0 == MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, re, -1, &vw[0], i+1) ) {
			return NULL;
		}
		wstring w_re = &vw[0];
		wregex wre(w_re, (re_opt_i ? wregex::icase : wregex::normal));

		// 検索対象文字列の準備
		// 同様の理由により WideChar に変換する

		i = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, str, -1, NULL, 0);
		if ( i == 0 ) {
			return NULL;
		}
		vw.resize(i+1);
		if ( 0 == MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, str, -1, &vw[0], i+1) ) {
			return NULL;
		}
		wstring w_str = &vw[0];

		// 置換後文字列の準備
		// 同様の理由により WideChar に変換する

		i = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, rep, -1, NULL, 0);
		if ( i == 0 ) {
			return NULL;
		}
		vw.resize(i+1);
		if ( 0 == MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, rep, -1, &vw[0], i+1) ) {
			return NULL;
		}
		wstring w_rep = &vw[0];

		regex_constants::match_flag_type flags = regex_constants::match_default;
		if ( re_opt_s )
			flags |= regex_constants::match_single_line;
		if ( re_opt_g )
			flags |= regex_constants::match_any;

		wstring w_after = regex_replace(w_str, wre, w_rep, flags);
		// 置換後文字列はWideCharであるため、MultiByteに変換する

		i = WideCharToMultiByte(GetACP(), 0, w_after.c_str(), -1, NULL, 0, NULL, NULL);
		if ( i == 0 ) {
			return NULL;
		}

		vector<char> vc;
		vc.resize(i+1);

		if ( 0 == WideCharToMultiByte(GetACP(), 0, w_after.c_str(), -1, &vc[0], i+1, NULL, NULL) ) {
			return NULL;
		}

		return _strdup(&vc[0]);
	}
	catch(...) {
		return NULL;
	}
}

static LPCSTR DlgProc_ShowOutputDlg_szMessage;
static LPCSTR DlgProc_ShowOutputDlg_szTitle;
static LPCSTR DlgProc_ShowOutputDlg_szOutput;
static int    DlgProc_ShowOutputDlg_flag;

// アーカイバDLLの出力メッセージを表示するためのダイアログ
static LRESULT CALLBACK DlgProc_ShowOutputDlg(HWND hDlg, UINT message, WPARAM wParam, LPARAM)
{
	switch( message ) {
		case WM_INITDIALOG:
			{
				LPSTR iKindIcon = 0;

				// flagから表示すべきアイコンの種類を確定
				if ( DlgProc_ShowOutputDlg_flag & MB_ICONINFORMATION ) {
					iKindIcon = IDI_INFORMATION;
				}
				else if ( DlgProc_ShowOutputDlg_flag & MB_ICONQUESTION ) {
					iKindIcon = IDI_QUESTION;
				}
				else if ( DlgProc_ShowOutputDlg_flag & MB_ICONEXCLAMATION ) {
					iKindIcon = IDI_WARNING;
				}
				else if ( DlgProc_ShowOutputDlg_flag & MB_ICONSTOP ) {
					iKindIcon = IDI_ERROR;
				}

				// 標準アイコンを読み出して設定
				if ( iKindIcon ) {
					HICON hIcon = LoadIcon(NULL, iKindIcon);
					if ( hIcon ) {
						SendDlgItemMessage(hDlg, IDC_STATIC_ICON, STM_SETICON, (WPARAM)hIcon, NULL);
					}
				}

				// メッセージを表示
				SetWindowText(GetDlgItem(hDlg, IDC_STATIC_TEXT), DlgProc_ShowOutputDlg_szMessage);

				// タイトルバーを設定
				SetWindowText(hDlg, DlgProc_ShowOutputDlg_szTitle);

				// 出力メッセージを設定
				SetWindowText(GetDlgItem(hDlg, IDC_OUTPUTLOG), DlgProc_ShowOutputDlg_szOutput);

				// カーソルを一番最後に移動
				SendDlgItemMessage(hDlg, IDC_OUTPUTLOG, EM_LINESCROLL, 0, lstrlen(DlgProc_ShowOutputDlg_szOutput));
				SendDlgItemMessage(hDlg, IDC_OUTPUTLOG, EM_SETSEL, (WPARAM)-1, (LPARAM)-1);
			}
			break;

		case WM_COMMAND:
			switch ( LOWORD(wParam) ) {
				case IDCANCEL:
					EndDialog(hDlg, LOWORD(wParam));
					return TRUE;
			}
			break;
	}
    return FALSE;	
}

INT_PTR ShowOutputDlg( HWND hDlg, LPCSTR szMessage, LPCSTR szTitle, LPCSTR szOutput, int flag )
{
	DlgProc_ShowOutputDlg_szMessage = szMessage ? szMessage : "";
	DlgProc_ShowOutputDlg_szTitle   = szTitle   ? szTitle   : "";
	DlgProc_ShowOutputDlg_szOutput  = szOutput  ? szOutput  : "";
	DlgProc_ShowOutputDlg_flag      = flag;

	return DialogBox(hInst, (LPCTSTR)IDD_OUTPUTDLG, hDlg, (DLGPROC)DlgProc_ShowOutputDlg);
}

// フォルダの中のファイル・フォルダを再帰的に削除する。書込禁止属性は解除する。使用中等で削除できない場合は無視して処理続行
// 指定フォルダそのものを削除するのではなく、指定フォルダの中身を空にする事に注意。
// 戻り値：-1=パラメタエラー/処理異常 0=1つ以上のファイル・フォルダで削除失敗(全部失敗or部分成功)  1:成功
int emptyDir(const char *folder, FILETIME *bf_ft)
{
	int iResult = 1;

	if (folder == NULL || folder[0] == 0) {
		return -1;
	}

	// NT系の場合はUnicodeでフォルダ・ファイル名を扱うと見なして、Unicode用関数の取得を行う。
	if (isNT) {
		// Unicodeが使える環境における処理
		wchar_t *wzFolder = mb2wc(folder);
		if (wzFolder == NULL) return -1;
		iResult = emptyDirectoryW(wzFolder, bf_ft);
		safefree(wzFolder);
	}
	else {
		// ANSI環境での処理
		iResult = emptyDirectoryA(folder, bf_ft);
	}

	return iResult;
}
