//////////////////////////////////////////
// FileHandlerProc.h
//Copyright (c) 8/10/2022 by ECCSkelton
//////////////////////////////////////////

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

	//コモンコントロールの初期化
	InitCommonControls();

	//ツールバー登録−Init(hWnd, hIinstance, ID, (以下省略可）Style)
	TBar.Init(m_hWnd, m_hInstance, TOOLBAR);
	//ツールバーボタン用カスタムビットマップ追加
	TBar.AddBmp(m_hInstance, MAKEINTRESOURCE(IDI_TBAR), 7);
	//ツールバーボタン追加
	TBBUTTON tbb[11];
	ZeroMemory(tbb, sizeof(tbb));
	tbb[0].iBitmap = TBar.m_id + 0;
	tbb[0].fsState = TBSTATE_ENABLED;
	tbb[0].fsStyle = TBSTYLE_BUTTON;
	tbb[0].idCommand = IDM_EXIT;
	tbb[1].fsStyle = TBSTYLE_SEP;	//セパレーター
	tbb[2].iBitmap = TBar.m_id + 1;
	tbb[2].fsState = TBSTATE_ENABLED;
	tbb[2].fsStyle = TBSTYLE_BUTTON;
	tbb[2].idCommand = IDM_EXE;
	tbb[3].fsStyle = TBSTYLE_SEP;	//セパレーター
	tbb[4].iBitmap = TBar.m_id + 2;
	tbb[4].fsState = TBSTATE_ENABLED;
	tbb[4].fsStyle = TBSTYLE_BUTTON;
	tbb[4].idCommand = IDM_DEL;
	tbb[5].fsStyle = TBSTYLE_SEP;	//セパレーター
	tbb[6].iBitmap = TBar.m_id + 4;
	tbb[6].fsState = TBSTATE_ENABLED;
	tbb[6].fsStyle = TBSTYLE_BUTTON;
	tbb[6].idCommand = IDM_CUT;
	tbb[7].iBitmap = TBar.m_id + 3;
	tbb[7].fsState = TBSTATE_ENABLED;
	tbb[7].fsStyle = TBSTYLE_BUTTON;
	tbb[7].idCommand = IDM_COPY;
	tbb[8].iBitmap = TBar.m_id + 5;
	tbb[8].fsState = TBSTATE_ENABLED;
	tbb[8].fsStyle = TBSTYLE_BUTTON;
	tbb[8].idCommand = IDM_RENAME;
	tbb[9].fsStyle = TBSTYLE_SEP;	//セパレーター
	tbb[10].iBitmap = TBar.m_id + 6;
	tbb[10].fsState = TBSTATE_ENABLED;
	tbb[10].fsStyle = TBSTYLE_BUTTON;
	tbb[10].idCommand = IDM_VERSION;
	TBar.AddButtons(11, tbb);

	//ステータスバー登録−Init(hWnd, hIinstance, ID, (以下省略可）Style)
	SBar.Init(m_hWnd, m_hInstance, STATUSBAR);
	//ステータスバー区画設定
	int sec[2] = {120, -1};
	SBar.SetSection(2, sec);
	//ステータスバー文字列設定
	SBar.SetText(0, L"FileHandler Ver 1.3");

	//スプリッターの作成
	g_Split.Create(m_hWnd, m_hInstance, (HMENU)IDC_SPLIT);
	//スプリッターの境界の設定
	g_Split.SetBorders(300);
	
	//ツリービューの作成
	g_tv.Create(m_hWnd, m_hInstance, (HMENU)IDC_TREEVIEW);
	g_tv.SetFont(9, L"ＭＳ 明朝");
	//スプリッターの第１ペインにツリービューを張り付ける
	g_Split.SetCtrl(0, IDC_TREEVIEW);
	//リストービューの作成
	g_lv.Create(m_hWnd, m_hInstance, (HMENU)IDC_LISTVIEW);
	//スプリッターの第２ペインにリストービューを張り付ける
	g_Split.SetCtrl(1, IDC_LISTVIEW);

	//ファイルシステムオブジェクト情報からイメージリストを作成
	HIMAGELIST hImglist;
	SHFILEINFO shFileInfo;
	hImglist = (HIMAGELIST)SHGetFileInfo(L"C:\\", 0, &shFileInfo, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
	//イメージリストをリストビュー、ツリービューに設定
	ListView_SetImageList(g_lv.GetHandle(), hImglist, LVSIL_SMALL);		//LVSIL_SMALL->Image list with small icons
	TreeView_SetImageList(g_tv.GetHandle(), hImglist, TVSIL_NORMAL);	//LVSIL_SMALL->Image list with small icons

	//シェルの初期化
	g_Shell.SetHandles(g_tv.GetHandle(), g_lv.GetHandle());	//関連付けるツリービュ―、リストビューを登録
	//リストビュー、ツリービューの初期化
	g_Shell.InsertTreeItem(g_Shell.GetDesktop(), TVI_ROOT, g_Root.ToChar(), SFGAO_HASSUBFOLDER);	//ツリービュ―にデスクトップをルート設定
	g_Shell.ResetListViewColumn(g_Shell.GetShellFolder());	//リストビューの列初期設定（フォールダーによって異なる）
	g_Shell.SetSHChangeNoticeRegister(m_hWnd);				//シェル変更通知の設定

	//メニューハンドルの取得
	g_hPopup = GetSubMenu(GetMenu(m_hWnd), 0);

	return TRUE;
}

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

	LPNMHDR lpNmhdr = (LPNMHDR)lParam;
	if((int)wParam == IDC_TREEVIEW) {	//ツリービューからのメッセージ
		switch(lpNmhdr->code) {
			LPTVITEM lp;
		case TVN_ITEMEXPANDING:			//ツリービュ―の展開
			lp = &((LPNMTREEVIEW)lParam)->itemNew;
			//初めての展開の場合、（第3引数がFALSE）なのでリストビューはいじらず列挙する
			if(!(lp->state & TVIS_EXPANDEDONCE))
				g_Shell.ViewEnumItem((PIDLIST_ABSOLUTE)lp->lParam, m_hWnd, FALSE, lp->hItem, CompareFunc);
			break;
		case TVN_DELETEITEM: 			//ツリービュ―アイテムが削除される場合
			lp = &((LPNMTREEVIEW)lParam)->itemOld;
			CoTaskMemFree((LPVOID)lp->lParam);		//PIDLのメモリーを解放
			break;
		case TVN_SELCHANGED:			//ツリービュ―の選択アイテムが変更
			//itemNew = 新しい選択アイテム
			lp = &((LPNMTREEVIEW)lParam)->itemNew;
			//新しい選択アイテムのPIDLを記録
			g_Shell.SetCurFolder((PIDLIST_ABSOLUTE)lp->lParam);
			//lp->lParam（新しい選択アイテムの絶対PIDLIST）からパスを取得
			SHGetPathFromIDListW((PCIDLIST_ABSOLUTE)lp->lParam, g_CurrentPath);
			//アイテム選択（即ちファイルパス）の変更に伴い、旧パスのリストビューで選択したファイル名バッファを初期化する
			*g_FileName = NULL;						//ファイル名バッファを初期化
			g_SelectedFile = g_CurrentPath;
			g_SelectedFile = g_SelectedFile + L"\\" + g_FileName;
			//ステータスバーへ表示（フォールダーだけ）
			SBar.SetText(1, g_SelectedFile.ToChar());
			SBar.SendMsg(SB_SETTIPTEXT, 1, (LPARAM)g_SelectedFile.ToChar());	//ToolTipをつける
			//リストビューにその「子供」を表示（第3引数がTRUE）
			g_Shell.ViewEnumItem((PIDLIST_ABSOLUTE)lp->lParam, m_hWnd, TRUE, NULL, CompareFunc);
			break;
/*
		case TVN_ENDLABELEDIT:
			//旧ファイルパス・名を記録
			CSTR OldPathName = g_SelectedFile;
			//ラベル編集完了
			TreeView_SetItem(g_tv.GetHandle(), &((TV_DISPINFO*)lParam)->item);
			//改めてパスを取得
			LPTVITEM lp = &((LPNMTREEVIEW)lParam)->itemNew;	//itemNew = 新しい選択アイテム
			//lp->lParam（新しい選択アイテムの絶対PIDLIST）からパスを取得
			SHGetPathFromIDList((PCIDLIST_ABSOLUTE)lp->lParam, g_CurrentPath);
			//選択ファイル名を新しい名に変更
			g_SelectedFile = g_CurrentPath;
			g_SelectedFile = g_SelectedFile + L"\\" + g_FileName;
			//ファイルを新ファイル名に変更
			g_Shell.FileOperation(m_hWnd, 'R', OldPathName.ToChar(), g_SelectedFile.ToChar());
			//新ファイル名をステータスバーに表示
			SBar.SetText(1, g_SelectedFile.ToChar());	//新ファイル名に変更
			SBar.SendMsg(SB_SETTIPTEXT, 1, (LPARAM)g_SelectedFile.ToChar());	//ToolTipをつける
			//ラベル編集を不可に戻す
			g_Style ^= TVS_EDITLABELS;
			SetWindowLong(g_tv.GetHandle(), GWL_STYLE, g_Style);
			//ラベル編集ボタンを利用可能にする
			SendMessage(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_RENAME, MAKELONG(TRUE, 0));
			break;
		case NM_RCLICK:
			SetContextMenu(lpNmhdr, lParam);
			break;
*/
		default:
			break;
		}
	}
	else if((int)wParam == IDC_LISTVIEW) {	//リストビューからのメッセージ
		//リストビューの通知メッセージによる処理
		switch(((LPNMLISTVIEW)lParam)->hdr.code) {
			static HWND hEdit;	//リストビューラベル編集用エディットコントロール
		case LVN_COLUMNCLICK:	//列見出しがクリックされたら
			if(sortsubno[((LPNMLISTVIEW)lParam)->iSubItem] == UP)
				sortsubno[((LPNMLISTVIEW)lParam)->iSubItem] = DOWN;
			else
				sortsubno[((NM_LISTVIEW*)lParam)->iSubItem] = UP;
			g_lv.SortItem(CompProc, ((LPNMLISTVIEW)lParam)->iSubItem);
			break;
		case LVN_DELETEITEM:
			//item.lParam = 削除アイテムのpidl
			LVITEM item;
			item.mask  = LVIF_PARAM;
			item.iItem = ((LPNMLISTVIEW)lParam)->iItem;
			ListView_GetItem(g_lv.GetHandle(), &item);
			CoTaskMemFree((LPVOID)item.lParam);
			break;
		case LVN_BEGINLABELEDIT:
			hEdit = ListView_GetEditControl(g_lv.GetHandle());
			break;
		case LVN_ENDLABELEDIT:
			GetWindowTextW(hEdit, g_FileName, sizeof(g_FileName));
			ListView_SetItemText(g_lv.GetHandle(), ((LPNMLISTVIEW)lParam)->iItem, 0, g_FileName);
			g_SelectedFile = g_CurrentPath;
			g_SelectedFile = g_SelectedFile + L"\\" + g_FileName;
			//ステータスバーへ表示（フォールダーだけ）
			SBar.SetText(1, g_SelectedFile.ToChar());
			SBar.SendMsg(SB_SETTIPTEXT, 1, (LPARAM)g_SelectedFile.ToChar());	//ToolTipをつける
			//ラベル編集を不可に戻す
			g_Style ^= TVS_EDITLABELS;
			SetWindowLong(g_lv.GetHandle(), GWL_STYLE, g_Style);
			//ラベル編集ボタンを利用可能にする
			SendMessage(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_RENAME, MAKELONG(TRUE, 0));
			break;
		case NM_CLICK:		//左クリックの場合
			//アイテムが選択されていればステータスバーへ表示
		case NM_DBLCLK:		//左ダブルクリックの場合
			//表示に加え、OnExeへ
			if((g_SelRow = g_lv.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED | LVNI_FOCUSED)) != -1) {
				g_lv.GetItemText(g_SelRow, 0, g_FileName, MAX_PATH);
				g_SelectedFile = g_CurrentPath;
				g_SelectedFile = g_SelectedFile + L"\\" + g_FileName;
				//ステータスバーへ表示（フォールダーだけ）
				SBar.SetText(1, g_SelectedFile.ToChar());
				SBar.SendMsg(SB_SETTIPTEXT, 1, (LPARAM)g_SelectedFile.ToChar());	//ToolTipをつける
				if(((LPNMLISTVIEW)lParam)->hdr.code == NM_DBLCLK) OnExe();			//OnExeへ
			}
			break;
		case NM_RCLICK:		//右クリックの場合
			if(g_Context)
				SetContextMenu(lpNmhdr, lParam);
			else {
				//ウインドウの位置情報を取得
				RECT rec;
				GetWindowRect(m_hWnd, &rec);
				//ポップアップメニューの表示場所を設定
				POINT pt;
				GetCursorPos(&pt);
				//ポップアップメニューの表示
				TrackPopupMenu(g_hPopup, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON, pt.x, pt.y, 0, m_hWnd, &rec);
			}
			break;
		default:
			break;
		}
	}
	else if(lpNmhdr->code == TTN_NEEDTEXT) {
		((LPTOOLTIPTEXT)lParam)->hinst = m_hInstance;
		switch(((LPTOOLTIPTEXT)lParam)->hdr.idFrom) {
		case IDM_EXE:
			((LPTOOLTIPTEXT)lParam)->lpszText = L"実行";
			break;
		case IDM_DEL:
			((LPTOOLTIPTEXT)lParam)->lpszText = L"削除";
			break;
		case IDM_CUT:
			((LPTOOLTIPTEXT)lParam)->lpszText = L"ファイルの移動";
			break;
		case IDM_COPY:
			((LPTOOLTIPTEXT)lParam)->lpszText = L"ファイルのコピー";
			break;
		case IDM_RENAME:
			((LPTOOLTIPTEXT)lParam)->lpszText = L"ファイル名変更";
			break;
		case IDM_VERSION:
			((LPTOOLTIPTEXT)lParam)->lpszText = L"バージョン情報";
			break;
		case IDM_EXIT:
			((LPTOOLTIPTEXT)lParam)->lpszText = L"終了";
			break;
		}
	}

	return TRUE;
}

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

	//ツールバー、ステータスバーを親のクライアント領域に合わせる
	TBar.AutoSize();
	SBar.AutoSize();
	//スプリッターを親のクライアント領域に合わせる
	g_Split.AutoSize(SBar.m_hWnd, TBar.m_hWnd);
	return TRUE;
}

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

	if(MessageBox(m_hWnd, L"終了しますか", L"終了確認",
					MB_YESNO | MB_ICONQUESTION) == IDYES) {
		//処理をするとDestroyWindow、PostQuitMessageが呼ばれる
		return TRUE;
	}
	else
		//そうでなければウィンドウではDefWindowProc関数をreturn、ダイアログではreturn FALSEとなる。
		return FALSE;
}

//////////////////////////
//シェル通知メッセージ処理
//////////////////////////
bool CMyWnd::OnShellChange(WPARAM wParam, LPARAM lParam) {

	LONG				lEvent;
	HANDLE				hLock;
	PIDLIST_ABSOLUTE	*pidlAbsolute;
	//処理中は通知を停止する
	hLock = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &pidlAbsolute, &lEvent);
	if(hLock != NULL) {
		if(ILIsParent(g_Shell.GetCurFolder(), pidlAbsolute[0], TRUE))	//現在のフォールダーはイベント発生フォールダーの親か？
			g_Shell.NotifyShellChange(pidlAbsolute[0], pidlAbsolute[1], lEvent);
	//通知を再開する
		SHChangeNotification_Unlock(hLock);
		return TRUE;
	}
	return FALSE;
}

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

	g_Context = !g_Context;
	if(g_Context)
		 ModifyMenu(g_hPopup, IDM_POPUP, MF_BYCOMMAND, IDM_POPUP, L"ポップアップメニュー(&P)");
	else
		 ModifyMenu(g_hPopup, IDM_POPUP, MF_BYCOMMAND, IDM_POPUP, L"コンテキストメニュー(&C)");

	return TRUE;
}

bool CMyWnd::OnExe() {

	if(!*g_FileName) {
		MessageBox(m_hWnd, L"ファイルが選択されていません", L"エラー", MB_OK | MB_ICONERROR);
		return FALSE;
	}
	do{
		if(!*g_CurrentPath) {	//
			CSTR errmsg(g_FileName);
			errmsg = errmsg + L"が選択されましたが、仮想フォールダーのファイルなので実行できません";
			MessageBox(m_hWnd, errmsg.ToChar(), L"仮想フォールダーファイル", MB_OK | MB_ICONERROR);
			return FALSE;
		}
		//選択したアイテムがディレクトリーの場合の処理
		if(GetFileAttributes(g_SelectedFile.ToChar()) & FILE_ATTRIBUTE_DIRECTORY) {
			g_tv.Expand(g_tv.GetSelection(), TVE_EXPAND);
			g_tv.SelectItem(g_tv.FindItem(g_tv.GetSelection(), g_FileName));
		}
		//選択したアイテムがファイルの場合の処理
		else {
			g_lv.GetItemText(g_SelRow, 0, g_FileName, MAX_PATH);
			g_SelectedFile = g_CurrentPath;
			g_SelectedFile = g_SelectedFile + L"\\" + g_FileName;
			if(ShellExecuteW(NULL, L"open", g_SelectedFile.ToChar(), NULL, NULL, SW_SHOWNORMAL) <= (HINSTANCE)32) {	//L"open" or L"runas"
				if(MessageBox(m_hWnd, L"実行可能ファイルではありません。関連付けられたプログラムがあればそれで開きますか？",
					L"エラー", MB_YESNO | MB_ICONEXCLAMATION) == IDYES) {
					WCHAR Path[MAX_PATH];
					lstrcpy(Path, g_SelectedFile.ToChar());
	                WCHAR *pt = StrStrW(Path, g_FileName);
					if(pt--) *pt = 0;
					WCHAR ExeFile[MAX_PATH];
					if((int)FindExecutableW(g_FileName, Path, ExeFile) > 32) {
						CSTR Cmd = L"\"";				//実行ファイルパス、名を「"」で囲む
						Cmd = Cmd + ExeFile;
						Cmd = Cmd + L"\" \"";			//データファイルパス、名を「"」で囲む
						Cmd = Cmd + g_SelectedFile;
						Cmd = Cmd + L"\"";
						ShellExecuteW(NULL, L"open", Cmd.ToChar(), NULL, NULL, SW_SHOWNORMAL);	//L"open" or L"runas"
					}
					else
						MessageBox(m_hWnd, L"関連付けられたプログラムがありません", L"エラー", MB_OK | MB_ICONERROR);
				}
			}
		}
	} while((g_SelRow = g_lv.GetNextItem(g_SelRow, LVNI_ALL | LVNI_SELECTED)) != -1);

	return TRUE;
}

bool CMyWnd::OnDel() {

	if(!*g_FileName) {
		MessageBox(m_hWnd, L"ファイルが選択されていません", L"エラー", MB_OK | MB_ICONERROR);
		return FALSE;
	}
	else {
		CSTR msg = g_SelectedFile;
		msg = msg + L"\nを削除します。よろしいですか？";
		if(MessageBox(m_hWnd, msg.ToChar(), L"ファイル削除", MB_YESNO | MB_ICONWARNING) == IDYES) {
			g_Shell.FileOperation(m_hWnd, 'D', g_SelectedFile.ToChar());
			return TRUE;
		}
	}
}

bool CMyWnd::OnCut() {

	if(!*g_FileName) {
		MessageBox(m_hWnd, L"ファイルが選択されていません", L"エラー", MB_OK | MB_ICONERROR);
		return FALSE;
	}
	//対象ファイルが選択されていたら
	else {
		WCHAR Target[MAX_PATH] = {0};
		lstrcpy(Target, cmndlg.GetPath(m_hWnd, L"移動先"));
		if(!*Target) {
			MessageBox(m_hWnd, L"移動先が指定されませんでした", L"移動先指定失敗", MB_OK | MB_ICONERROR);
			return FALSE;
		}
		//ファイルの移動
		g_Shell.FileOperation(m_hWnd, 'M', g_SelectedFile.ToChar(), Target);
		return TRUE;
	}
}

bool CMyWnd::OnCopy() {

	if(!*g_FileName) {
		MessageBox(m_hWnd, L"ファイルが選択されていません", L"エラー", MB_OK | MB_ICONERROR);
		return FALSE;
	}
	//対象ファイルが選択されていたら
	else {
		WCHAR Target[MAX_PATH] = {0};
		lstrcpy(Target, cmndlg.GetPath(m_hWnd, L"コピー先"));
		if(!*Target) {
			MessageBox(m_hWnd, L"コピー先が指定されませんでした", L"コピー先指定失敗", MB_OK | MB_ICONERROR);
			return FALSE;
		}
		//ファイルのコピー
		g_Shell.FileOperation(m_hWnd, 'C', g_SelectedFile.ToChar(), Target);
		return TRUE;
	}
}

bool CMyWnd::OnRename() {

	if(!*g_FileName) {
		MessageBox(m_hWnd, L"ファイルが選択されていません", L"エラー", MB_OK | MB_ICONERROR);
		return FALSE;
	}
	else {
/*		//ラベル編集を可能にする
		g_Style = GetWindowLong(g_tv.GetHandle(), GWL_STYLE);
		g_Style |= TVS_EDITLABELS;
		SetWindowLong(g_tv.GetHandle(), GWL_STYLE, g_Style);
		//ラベル編集開始
		TreeView_EditLabel(g_tv.GetHandle(), g_hSelected);
		//ラベル編集ボタンを利用不可にする
		SendMessage(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_RENAME, MAKELONG(FALSE, 0));
		return TRUE;
*/
		//ラベル編集を可能にする
		g_Style = GetWindowLong(g_lv.GetHandle(), GWL_STYLE);
		g_Style |= LVS_EDITLABELS;
		SetWindowLong(g_lv.GetHandle(), GWL_STYLE, g_Style);
		//ラベル編集開始
		ListView_EditLabel(g_lv.GetHandle(), g_SelRow);
		//ラベル編集ボタンを利用不可にする
		SendMessage(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_RENAME, MAKELONG(FALSE, 0));
		return TRUE;
	}
	return FALSE;
}

bool CMyWnd::OnExit() {

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

bool CMyWnd::OnVersion() {

	versiondlg.DoModal(m_hWnd, L"IDD_VERSION", GetInstance());
	return TRUE;
}

///////////////////////////////
//ユーザーダイアログの関数定義
//コントロール関数
///////////////////////////////
bool VERSIONDLG::OnIdok() {

	EndModal(TRUE);
	return TRUE;
}
