//////////////////////////////////////////
// RenamerProc.h
// Copyright (c) 05/06/2020 by ECCSkelton
//////////////////////////////////////////

/////////////////////////////////
//主ウィンドウCMyWndの関数の定義
//ウィンドウメッセージ関数
/////////////////////////////////
bool CMyWnd::OnInit(WPARAM wParam, LPARAM lParam) {

	//IDC_PATHにツールチップをつける
	g_Tip.SetToolTip(m_hWnd, IDC_PATH, L"フォールダーを選択してください", TRUE);
	//ファイル名変更ダイアログボタンを無効化する
	CheckList();
	//ヘルプファイルの設定
	CARG arg;
	g_HelpFile = arg.Path();
	g_HelpFile = g_HelpFile + L"\\RenamerHelp.chm";
	//ログファイルフォールダーの存在確認（ない場合は作成する）
	g_LogPath = arg.Path();
	g_LogPath = g_LogPath + L"\\RenameLog\\";
	if(!PathFileExistsW(g_LogPath.ToChar()))
		CreateDirectoryW(g_LogPath.ToChar(), NULL);
	//ドラッグアンドドロップを許可する
	DragAcceptFiles(m_hWnd, TRUE);
	return TRUE;
}

bool CMyWnd::OnDropFiles(WPARAM wParam, LPARAM lParam) {

	//入替か追加の確認
	int res = MessageBoxW(m_hWnd, L"ファイルを入れ替えますか（はい）、または追加しますか（いいえ）",
						L"入替か追加の確認", MB_YESNOCANCEL | MB_ICONQUESTION);
	if(res == IDYES) {
		//g_Pathを初期化
		g_Path = L"";
		//リストボックス内掃除
		int i = SendItemMsg(IDC_LISTBOX, LB_GETCOUNT, 0, 0);
    	if(i > 0)
			for(--i; i >= 0; i--)
				SendItemMsg(IDC_LISTBOX, LB_DELETESTRING, (WPARAM)i, 0);
	}
	else if(res == IDCANCEL)
		return FALSE;
	//ドラッグアンドドロップされたファイル名取得と処理
	WCHAR fn[MAX_PATH];
	//ドラッグアンドドロップされたファイルの数取得
	int num = DragQueryFileW((HDROP)wParam, 0xFFFFFFFF, NULL, 0);
	//ドラッグアンドドロップされたファイル名取得と処理
	for(int i = 0; i < num; i++) {
		DragQueryFileW((HDROP)wParam, i, fn, sizeof(fn));
		//リストボックスにファイルを追加する
		WCHAR** pathname = GetPathName(fn);
		if(*g_Path.ToChar() && g_Path != pathname[0])
			MessageBoxW(m_hWnd, L"異なるフォールダーのファイルを追加できません。", pathname[1], MB_OK | MB_ICONERROR);
		else {
			if(!*g_Path.ToChar()) {
				g_Path = pathname[0];
				SendItemMsg(IDC_PATH, WM_SETTEXT, 0, (LPARAM)pathname[0]);
				g_Tip.UpdateText(pathname[0]);
			}
			SendItemMsg(IDC_LISTBOX, LB_ADDSTRING, 0, (LPARAM)pathname[1]);
		}
	}
	DragFinish((HDROP)wParam);
	//ファイル名変更ボタンを有効化する
	CheckList();
	return TRUE;
}

bool CMyWnd::OnClose(WPARAM wPram, LPARAM lParam) {

	//終了確認
	if(MessageBoxW(m_hWnd, L"終了しますか", L"終了確認",
				MB_YESNO | MB_ICONINFORMATION) == IDYES) {
	//処理をするとDestroyWindow、PostQuitMessageが呼ばれる
		Destroy();
		return TRUE;
	}
	else
		return FALSE;
}

bool CMyWnd::OnDestroy(WPARAM wPram, LPARAM lParam) {

	//ダイアログベースの場合はこれが必要
	PostQuitMessage(0);
	return TRUE;
}

/////////////////////////////////
//主ウィンドウCMyWndの関数の定義
//メニュー項目、コントロール関数
/////////////////////////////////
bool CMyWnd::OnSelect() {

	//フォールダー選択とフォールダー内ファイルのリストボックス登録
	WCHAR *fp = g_CmnDlg.GetPath(m_hWnd, L"ファイルパスの選択");
	if(fp)
		g_Path = fp;
	else {
		MessageBoxW(m_hWnd, L"パスが選択されていません", L"エラー", MB_OK | MB_ICONERROR);
		return FALSE;
	}
	//リストボックス表示
	RenewListBox();
	//g_OrgFilesを更新し、ファイル名変更ダイアログボタンを有効化する
	CheckList();
	return TRUE;
}

bool CMyWnd::OnListBox(WPARAM wParam) {

	if(HIWORD(wParam) == LBN_SELCHANGE) {
		//ポップアップメニューを読みこむ
		HMENU hMenu = LoadMenuW(m_hInstance, L"IDM_POPUP");
		HMENU hPopupMenu = GetSubMenu(hMenu, 0);
		//ポップアップメニューの表示
		POINT pt;
		GetCursorPos(&pt);
		TrackPopupMenu(hPopupMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
					  pt.x, pt.y, 0, m_hWnd, NULL);
		//メニューリソースの開放
		DestroyMenu(hMenu);
		return TRUE;
	}
	return FALSE;
}

bool CMyWnd::OnReplace() {

	subdlg.DoModal(m_hWnd, L"IDD_SUB", GetInstance());
	//結果確認のためにカレントフォールダーを表示
	RenewListBox();
	return TRUE;
}

bool CMyWnd::OnSerial() {

	sub2dlg.DoModal(m_hWnd, L"IDD_SUB", GetInstance());
	//結果確認のためにカレントフォールダーを表示
	RenewListBox();
	return TRUE;
}

bool CMyWnd::OnHelp() {

	CSTR cmd = L"hh";
	if(ShellExecuteW(m_hWnd, L"open", cmd.ToChar(), g_HelpFile.ToChar(), NULL, SW_SHOWNORMAL) <= (HINSTANCE)32) {	//L"open" or L"runas"
		MessageBoxW(m_hWnd, L"ヘルプファイルが開けませんでした", L"エラー", MB_OK | MB_ICONERROR);
		return FALSE;
	}
	else
		return TRUE;
}

bool CMyWnd::OnExit() {

	SendMsg(WM_CLOSE, 0, 0);
	return TRUE;
}

bool CMyWnd::OnDel() {

	int sel = SendItemMsg(IDC_LISTBOX, LB_GETCURSEL, 0, 0);
	SendItemMsg(IDC_LISTBOX, LB_DELETESTRING, (WPARAM)sel, 0);
	CheckList();
	return TRUE;
}

bool CMyWnd::OnAdd() {

	WCHAR *fn = g_CmnDlg.GetFileName(m_hWnd, L"すべてのファイル\0*.*\0\0", TRUE);
	if(!fn) {
		MessageBoxW(m_hWnd, L"キャンセルされました。", L"エラー", MB_OK | MB_ICONERROR);
		return FALSE;
	}
	WCHAR** pathname = GetPathName(fn);
	if(*g_Path.ToChar() && g_Path != pathname[0]) {
		MessageBoxW(m_hWnd, L"異なるフォールダーのファイルを追加できません。", pathname[1], MB_OK | MB_ICONERROR);
		return FALSE;
	}
	else {
		SendItemMsg(IDC_LISTBOX, LB_ADDSTRING, 0, (LPARAM)pathname[1]);
		CheckList();
		return TRUE;
	}
}

////////////////////
//ユーザー関数定義
/////////////////////////////////
//pathnameをpathとnameに分解して
//ポインター配列を返す
/////////////////////////////////
WCHAR** CMyWnd::GetPathName(WCHAR* pathname) {

	static WCHAR buffer[MAX_PATH], *ret[2];
	lstrcpyW(buffer, pathname);
	WCHAR* lastBackSlash;
	for(WCHAR* cp = buffer; *cp; cp++)
		if(*cp == '\\')
			lastBackSlash = cp;
	*lastBackSlash = L'\0';
	ret[0] = buffer;
	ret[1] = ++lastBackSlash;
	return ret;
}

/////////////////////////////////////////
//path内のファイルをリストボックスに表示
//同時にg_OrgFilesにファイル名をコンマ区
//切り文字列で記録
/////////////////////////////////////////
void CMyWnd::RenewListBox() {

	//リストボックス内掃除
	int i = SendItemMsg(IDC_LISTBOX, LB_GETCOUNT, 0, 0);
    if(i > 0) {
		for(--i; i >= 0; i--)
			SendItemMsg(IDC_LISTBOX, LB_DELETESTRING, (WPARAM)i, 0);
	}
	//リストボックスにカレントフォールダーのファイル名を表示
	CSTR path = g_Path + L"\\*.*";		//ファイル名ベースにしないと機能しない
	MakeOrgFileList(path.ToChar());
	//変更予定ファイル名の登録
	ListFiles(m_hWnd, IDC_LISTBOX, &g_OrgFiles);
}

/////////////////////////////////////////
//カレントフォールダーのファイルをリスト
//ボックスに表示
/////////////////////////////////////////
bool CMyWnd::MakeOrgFileList(WCHAR* path) {

	WIN32_FIND_DATAW fd;
	HANDLE hFind = FindFirstFileW(path, &fd);
	int i = 0;				//ファイル数カウンター
	if (hFind == INVALID_HANDLE_VALUE) {
		MessageBoxW(m_hWnd, L"ファイル情報取得失敗", L"エラー", MB_OK | MB_ICONERROR);
		return FALSE;
	}
	else {
		g_OrgFiles = L"";
		do {
			if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);	// Directory
			else {													// Files
				g_OrgFiles = g_OrgFiles + L"\"" + fd.cFileName + L"\",";	//引用符で括る
			}
		} while (FindNextFileW(hFind, &fd));
	}
	FindClose(hFind);
	return (bool)i;
}

///////////////////////////////////////////////
//リストボックスのファイルを数え、g_OrgFilesを
//更新し、ファイル名変更ボタンを有無効化する
///////////////////////////////////////////////
bool CMyWnd::CheckList() {

	//リストボックス内のファイル数を確認
	int n = SendItemMsg(IDC_LISTBOX, LB_GETCOUNT, 0, 0);
	if(n) {
		//IDC_PATHにファイル名を表示し、ツールチップをつける
		SendItemMsg(IDC_PATH, WM_SETTEXT, 0, (LPARAM)g_Path.ToChar());
		g_Tip.UpdateText(g_Path.ToChar());
		//g_OrgFilesを更新する
		g_OrgFiles = L"";
		WCHAR str[MAX_PATH];
		for(int i = 0; i < n; i++) {
			g_OrgFiles = g_OrgFiles + L"\"";
			SendItemMsg(IDC_LISTBOX, LB_GETTEXT, i, (LPARAM)str);
			g_OrgFiles = g_OrgFiles + str + L"\",";
		}
		//ファイル名変更ダイアログボタンを有効化する
		EnableWindow(GetDlgItem(m_hWnd, IDC_REPLACE), TRUE);
		EnableWindow(GetDlgItem(m_hWnd, IDC_SERIAL), TRUE);
	}
	else {
		//IDC_PATHとツールチップを初期化する
		g_Path = L"";
		SendItemMsg(IDC_PATH, WM_SETTEXT, 0, (LPARAM)g_Path.ToChar());
		g_Tip.UpdateText(L"フォールダーを選択してください");
		//ファイル名変更ダイアログボタンを無効化する
		EnableWindow(GetDlgItem(m_hWnd, IDC_REPLACE), FALSE);
		EnableWindow(GetDlgItem(m_hWnd, IDC_SERIAL), FALSE);
	}
	return (bool)n;
}

//////////////////////////////
//SUBダイアログの関数の定義
//コントロール関数
//////////////////////////////
bool SUBDLG::OnInit(WPARAM wParam, LPARAM lParam) {

	//「大文字小文字を区別」にチェックを入れる
	SendItemMsg(IDC_CHECKUORL, BM_SETCHECK, BST_CHECKED, (LPARAM)0);
	//「変換実行」ボタンを無効にする
	EnableWindow(GetDlgItem(m_hWnd, IDOK), FALSE);
	//変更予定ファイル名の登録
	ListFiles(m_hWnd, IDC_LISTBOX, &g_OrgFiles);
	return TRUE;
}

bool SUBDLG::OnPreview() {

	//「大文字小文字を区別」の状態を確認し、記録UorLに記録
	LRESULT UorL = SendItemMsg(IDC_CHECKUORL, BM_GETCHECK, 0, (LPARAM)0);
	//リストボックスから元のファイル名を取得
	int n = SendItemMsg(IDC_LISTBOX, LB_GETCOUNT, 0, 0);
    if(!n) {
		MessageBoxW(m_hWnd, L"ファイルがありません", L"エラー", MB_OK | MB_ICONERROR);
		return FALSE;
	}
	else {
		//検索文字、置換文字と作業バッファ
		WCHAR ToRep[MAX_PATH], RepWith[MAX_PATH], buff[MAX_PATH];
		//検索文字をエディットボックスから取得
		GetWindowTextW(GetDlgItem(m_hWnd, IDC_TOREPLACE), ToRep, (LPARAM)MAX_PATH);
		if(!*ToRep) {
			MessageBoxW(m_hWnd, L"置換対象文字が未入力です。", L"エラー", MB_OK | MB_ICONERROR);
			return FALSE;
		}
		else
			if(UorL == BST_UNCHECKED)	//大文字小文字を区別しない場合、ToRepを小文字化する
				CharLowerW(ToRep);
		//置換文字をエディットボックスから取得
		GetWindowTextW(GetDlgItem(m_hWnd, IDC_REPLACEWITH), RepWith, (LPARAM)MAX_PATH);
		if(!*RepWith) {
			MessageBoxW(m_hWnd, L"置換文字が未入力です。", L"エラー", MB_OK | MB_ICONERROR);
			return FALSE;
		}
		//元のコンマ（','）区切りファイル名リスト(g_OrgFiles)でg_OldFilesを初期化
		g_OldFiles = g_OrgFiles;	//初期化
		g_OrgFiles = L"";			//初期化
		g_NewFiles = L"";			//初期化
		CSTR Name, work;			//コンマ区切りファイル名切り出し変数と小文字変換用変数
		for(int i = 0; g_OldFiles.Next(Name); i++) {
			work = Name;							//Nameを保持し、workを作業用に使う
			if(UorL == BST_UNCHECKED)				//大文字小文字を区別しないならば、
				CharLowerW(work.ToChar());			//workの文字列を小文字化する
			//置換して、新しいファイル名リスト(g_NewFiles)をコンマ（','）区切りで作成
			if(InstrRep(work.ToChar(), ToRep, RepWith, buff)) {
				g_OrgFiles = g_OrgFiles + L"\"";			//引用符括り
				g_OrgFiles = g_OrgFiles + Name.ToChar();	//置換対象後ファイル名
				g_OrgFiles = g_OrgFiles + L"\",";			//引用符括りとコンマ区切り
				g_NewFiles = g_NewFiles + L"\"";			//引用符括り
				g_NewFiles = g_NewFiles + buff;				//変更後ファイル名
				g_NewFiles = g_NewFiles + L"\",";			//引用符括りとコンマ区切り
			}
		}
		ListFiles(m_hWnd, IDC_LISTBOX, &g_NewFiles);
		//「変換実行」ボタンを有効にする
		EnableWindow(GetDlgItem(m_hWnd, IDOK), TRUE);
		return TRUE;
	}
}

bool SUBDLG::OnOk() {

	if(MessageBoxW(m_hWnd, L"RenameLogフォールダーにShift-JISで（はい）\r\nまたはUTF-8で（いいえ）\r\nログファイルを記録します。",
					L"ログファイル形式確認", MB_YESNO | MB_ICONQUESTION) == IDYES) {
		if(RenameFiles(TRUE))
			MessageBoxW(m_hWnd, L"RenameLogフォールダーにログファイルをSJISで記録しました。", L"ログ保存確認", MB_OK | MB_ICONINFORMATION);
		else
			MessageBoxW(m_hWnd, L"ファイル名変更に失敗しました。", L"エラー", MB_OK | MB_ICONERROR);
	}
	else {
		if(RenameFiles(FALSE))
			MessageBoxW(m_hWnd, L"RenameLogフォールダーにログファイルをUTF-8で記録しました。", L"ログ保存確認", MB_OK | MB_ICONINFORMATION);
		else
			MessageBoxW(m_hWnd, L"ファイル名変更に失敗しました。", L"エラー", MB_OK | MB_ICONERROR);
	}
	EndModal(TRUE);
	return TRUE;
}

bool SUBDLG::OnCancel() {

	EndModal(FALSE);
	return TRUE;
}

///////////////////
//ユーザー定義関数
///////////////////////////////////////////////////////////////////
//文字列（Old）内の検索文字列（ToFind）を置換文字列（ToReplace）で
//１回置き換え、その結果を新文字列（New）に書き込む
//【戻り値】
//置換に成功した場合：検索文字列が見つかったアドレス
//置換に失敗した場合：0
///////////////////////////////////////////////////////////////////
WCHAR* SUBDLG::InstrRep(WCHAR* Old, WCHAR* ToFind, WCHAR* ToReplace, WCHAR* New) {

	if(!(*Old & *ToFind & *ToReplace))			// Error check
		return 0;
	WCHAR *p1 = Old, *p2 = ToFind, *findp = 0;	// Setting work pointers
	do {
		if(findp) {								// In the course of matching
			if(!*p2) {							// If Matching completes,
				int i;
				for(i = 0; i < (findp - Old); i++)
					New[i] = Old[i];			// Copy Old to New till findp
				New[i] = 0;						// Add null termination
				wcscat(New, ToReplace);			// Copying ToReplace in place of ToFind
				wcscat(New, p1);				// Copying the rest of Old
				return findp;
			}
			else 								// In case that Matching fails
				if(*p1 != *p2) {
					p2 = ToFind;				// Reset pointers and repeat
					findp = 0;
				}
		}
		if(*p1 == *p2) {						// If matching begins,
			if(!findp)							// For the 1st time,
				findp = p1;						// Record p1 where ToFind is found
			++p2;								// p2 proceeds, as p1 does
		}
	} while(*p1++);
	return 0;
}

//////////////////////////////
//SUB2ダイアログの関数の定義
//コントロール関数
//////////////////////////////
bool SUB2DLG::OnInit(WPARAM wParam, LPARAM lParam) {

	//ダイアログタイトルの変更
	SendMsg(WM_SETTEXT, 0, (LPARAM)L"同一ファイル名で連番付け");
	//使わないコントロールを隠す
	ShowWindow(GetDlgItem(m_hWnd, IDC_CHECKUORL), SW_HIDE);
	ShowWindow(GetDlgItem(m_hWnd, IDC_REPLACEWITH), SW_HIDE);
	SendItemMsg(IDC_LABEL1, WM_SETTEXT, 0, (LPARAM)L"統一ファイル名");
	SendItemMsg(IDC_LABEL2, WM_SETTEXT, 0, (LPARAM)L"注：拡張子(.*)は付けない");
	//「変換実行」ボタンを無効にする
	EnableWindow(GetDlgItem(m_hWnd, IDOK), FALSE);
	//変更予定ファイル名の登録
	ListFiles(m_hWnd, IDC_LISTBOX, &g_OrgFiles);
	return TRUE;
}

bool SUB2DLG::OnPreview() {

	//リストボックスから元のファイル名を取得
	int n = SendItemMsg(IDC_LISTBOX, LB_GETCOUNT, 0, 0);
    if(!n) {
		MessageBoxW(m_hWnd, L"ファイルがありません", L"エラー", MB_OK | MB_ICONERROR);
		return FALSE;
	}
	else {
		//統一ファイル名と連番文字列（L"(???)\0"−6桁）
		WCHAR ToRep[MAX_PATH], num[6];
		//検索文字をエディットボックスから取得
		GetWindowTextW(GetDlgItem(m_hWnd, IDC_TOREPLACE), ToRep, (LPARAM)MAX_PATH);
		if(!*ToRep) {
			MessageBoxW(m_hWnd, L"統一ファイル名が未入力です。", L"エラー", MB_OK | MB_ICONERROR);
			return FALSE;
		}
		//元のコンマ（','）区切りファイル名リスト(g_OrgFiles)でg_OldFilesを初期化
		g_OldFiles = g_OrgFiles;	//初期化
		g_NewFiles = L"";			//初期化
		CSTR Name;					//コンマ区切りファイル名切り出し変数
		for(int i = 0; g_OldFiles.Next(Name); i++) {
			//拡張子があればそのアドレスを、なければ0をfoundに入れる
			WCHAR* found = Name.ToChar() + lstrlenW(Name.ToChar());
			while(found > Name.ToChar() && *found != L'.')
				found--;
			if(found == Name.ToChar())
				found = 0;
			//置換して、新しいファイル名リスト(g_NewFiles)をコンマ（','）区切りで作成
			g_NewFiles = g_NewFiles + L"\"";		//引用符括り
			g_NewFiles = g_NewFiles + ToRep;		//変更後ファイル名（拡張子無し）
			wsprintfW(num, L"(%03d)", i);			//'0'でサプレスされた連番
			g_NewFiles = g_NewFiles + num;			//変更後ファイル名
			if(found)								//拡張子があるファイル
				g_NewFiles = g_NewFiles + found;	//「'.'以下拡張子」を付加
			g_NewFiles = g_NewFiles + L"\",";		//引用符括りとコンマ区切り
		}
		ListFiles(m_hWnd, IDC_LISTBOX, &g_NewFiles);
		//「変換実行」ボタンを有効にする
		EnableWindow(GetDlgItem(m_hWnd, IDOK), TRUE);
		return TRUE;;
	}
}
