// CaplFindInCtrlDlg.cpp : implementation file
//

#include "stdafx.h"
#include "apl_gui.h"
#include "CaplFindInCtrlDlg.h"


CaplFindInCtrlDlg  st_FindInCtrlDlg;


void aplShowFindInCtrl(CWnd *ctrl)  // Выводит диалог поиска в контроле  (Если диалог уже был отображен - переключает на другой контрол
{
	st_FindInCtrlDlg.Show(ctrl);
}

void aplInstallFindInCtrl(CWnd *ctrl)  // Добавляетдля окна обработчик, который по CTRL+F отображает диалог поиска (aplShowFindInCtrl)
{
	if(0==ctrl) return;
	if(0==ctrl->m_hWnd) return;
	if(!IsWindow(ctrl->m_hWnd))return;

	CaplFindInCtrlDlg::Install(ctrl);
}

void aplDeInstallFindInCtrl(CWnd *ctrl)
{
	if(0==ctrl) return;
	CaplFindInCtrlDlg::DeInstall(ctrl);
	st_FindInCtrlDlg.Hide();
}



// CaplFindInCtrlDlg dialog

IMPLEMENT_DYNAMIC(CaplFindInCtrlDlg, CaplTranslateDialog)

CaplFindInCtrlDlg::CaplFindInCtrlDlg(CWnd* pParent /*=NULL*/)
	: CaplTranslateDialog(CaplFindInCtrlDlg::IDD, pParent)
{
	m_wnd4Find=0;
}

CaplFindInCtrlDlg::~CaplFindInCtrlDlg()
{
}

void CaplFindInCtrlDlg::DoDataExchange(CDataExchange* pDX)
{
	CaplTranslateDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_TEXT, m_text_ctrl);
	DDX_Control(pDX, IDC_FIND_FIRST, m_btnFindFirst);
	DDX_Control(pDX, IDC_FIND_NEXT, m_btnFindNext);
	DDX_Control(pDX, IDC_FIND_PREV, m_btnFindPrev);
}


BEGIN_MESSAGE_MAP(CaplFindInCtrlDlg, CaplTranslateDialog)
	ON_BN_CLICKED(IDC_FIND_FIRST, &CaplFindInCtrlDlg::OnBnClickedFindFirst)
	ON_BN_CLICKED(IDC_FIND_NEXT, &CaplFindInCtrlDlg::OnBnClickedFindNext)
	ON_BN_CLICKED(IDC_FIND_PREV, &CaplFindInCtrlDlg::OnBnClickedFindPrev)
	ON_WM_CLOSE()
END_MESSAGE_MAP()


// CaplFindInCtrlDlg message handlers


void CaplFindInCtrlDlg::Show(CWnd *wnd4find)
{
	if(0==wnd4find) return;
	if(0==m_hWnd)
	{
		CaplSetResourceHandle setres(module_inst);
		if(!Create(IDD_FIND_IN_CTRL,0)) return;
		UpdateData(FALSE);
		m_btnFindFirst.SetFlat(FALSE); m_btnFindFirst.SetWindowText(_T(""));
		m_btnFindNext.SetFlat(FALSE); m_btnFindNext.SetWindowText(_T(""));
		m_btnFindPrev.SetFlat(FALSE); m_btnFindPrev.SetWindowText(_T(""));
		m_btnFindFirst.SetIcon(GetAplTableIco((APL_TABLE_FIND)));
		m_btnFindNext.SetIcon(GetAplTableIco((APL_TABLE_BOTTOM)));
		m_btnFindPrev.SetIcon(GetAplTableIco((APL_TABLE_TOP)));

		m_toolTip.Create(this);
		m_toolTip.SetDelayTime(0);
		m_toolTip.AddTool(&m_btnFindFirst,APL_T("Найти с начала"));
		m_toolTip.AddTool(&m_btnFindNext,APL_T("Найти следующее"));
		m_toolTip.AddTool(&m_btnFindPrev,APL_T("Найти предыдущее"));
		m_toolTip.Activate(TRUE);
	}
	m_wnd4Find=wnd4find;
	RECT rect,rect1;
	wnd4find->GetClientRect(&rect);
	wnd4find->ClientToScreen(&rect);
	GetWindowRect(&rect1);
	rect.left=rect.right-(rect1.right-rect1.left);
	rect.bottom=rect.top+(rect1.bottom-rect1.top);
	MoveWindow(&rect);
	ShowWindow(SW_SHOW);
}

void CaplFindInCtrlDlg::Hide()
{
	if(0==m_hWnd) return;
	OnClose();
}

void CaplFindInCtrlDlg::OnClose()
{
	// TODO: Add your message handler code here and/or call default
	ShowWindow(SW_HIDE);
	if(0!=m_wnd4Find) m_wnd4Find->SetFocus();
	//CaplTranslateDialog::OnClose();
}


void CaplFindInCtrlDlg::OnBnClickedFindFirst(){FindNextItem(0);}
void CaplFindInCtrlDlg::OnBnClickedFindNext() {FindNextItem(1);}
void CaplFindInCtrlDlg::OnBnClickedFindPrev() {FindNextItem(-1);}


void CaplFindInCtrlDlg::FindNextItem(int delta)
{
	if(0==m_wnd4Find )   return;
	if(!IsWindow(m_wnd4Find->m_hWnd)) return;
	CString text;
	m_text_ctrl.GetWindowText(text);
	if(text==""){AfxMessageBox(APL_T("Не задана подстрока!"),MB_OK|MB_ICONWARNING);m_text_ctrl.SetFocus(); return;}
	text.MakeLower();


	if(m_wnd4Find->IsKindOf(RUNTIME_CLASS(CTreeCtrl)))CaplFindInCtrlDlg::FindNextTreeItem((CTreeCtrl*)m_wnd4Find,text,delta);
	else if(m_wnd4Find->IsKindOf(RUNTIME_CLASS(CTreeView)))
	{
		CTreeCtrl *tree=&(((CTreeView*)m_wnd4Find)->GetTreeCtrl());
		CaplFindInCtrlDlg::FindNextTreeItem(tree,text,delta);
	}
	else if(m_wnd4Find->IsKindOf(RUNTIME_CLASS(CaplTreeListCtrl)))CaplFindInCtrlDlg::FindNextTreeListItem((CaplTreeListCtrl*)m_wnd4Find,text,delta);
	else if(m_wnd4Find->IsKindOf(RUNTIME_CLASS(CaplTreeListCtrlView)))
	{
		CaplTreeListCtrlWithToolTip *tr_wtt=&(((CaplTreeListCtrlView*)m_wnd4Find)->m_tree);
		CaplFindInCtrlDlg::FindNextTreeListItem((CaplTreeListCtrl*)tr_wtt,text,delta);
	}
	else if(m_wnd4Find->IsKindOf(RUNTIME_CLASS(CListCtrl)))CaplFindInCtrlDlg::FindNextListItem((CListCtrl*)m_wnd4Find,text,delta);
	else if(m_wnd4Find->IsKindOf(RUNTIME_CLASS(CListView)))
	{
		CListCtrl *list=&(((CListView*)m_wnd4Find)->GetListCtrl());
		CaplFindInCtrlDlg::FindNextListItem(list,text,delta);
	}
	else AfxMessageBox(APL_T("В этом окне я искать не умею!"),MB_OK|MB_ICONSTOP);
}



void CaplFindInCtrlDlg::FindNextTreeListItem(CaplTreeListCtrl *treelist, LPCTSTR text, int delta)
{
	if(0==treelist) return;
	if(!IsWindow(treelist->m_hWnd)) return;
	
	if(0==text)  return;
	if(text[0]==_T('\0'))  return;

	HTREEITEM cur_hitem=0; //TVI_ROOT;
	if(1==delta || -1==delta) cur_hitem=treelist->GetSelectedItem();

	CString buf;
	if(0==delta) delta=1;
	while(true)
	{
		cur_hitem=aplGetNextTreeItem(treelist,cur_hitem,delta);
		if(0==cur_hitem) return;
		bool bFound=false;
		int i;
		for (i=0;i<treelist->GetColumnsNum(); i++)
		{
			buf=treelist->GetItemText(cur_hitem,i);
			buf.MakeLower();
			if(buf.Find(text)>=0) {treelist->SingleSelectItem(cur_hitem); return;}
		}
	}
}

void CaplFindInCtrlDlg::FindNextTreeItem(CTreeCtrl *tree, LPCTSTR text, int delta)
{
	if(0==tree) return;
	if(!IsWindow(tree->m_hWnd)) return;
	if(0==text)  return;
	if(text[0]==_T('\0'))  return;

	HTREEITEM cur_hitem=0; //TVI_ROOT;
	if(1==delta || -1==delta) cur_hitem=tree->GetSelectedItem();

	CString buf;
	if(0==delta) delta=1;
	while(true)
	{
		cur_hitem=aplGetNextTreeItem(tree,cur_hitem,delta);
		if(0==cur_hitem) return;
		bool bFound=false;
		buf=tree->GetItemText(cur_hitem);
		buf.MakeLower();
		if(buf.Find(text)>=0)
		{
			tree->SelectItem(cur_hitem); 
			tree->SelectDropTarget(cur_hitem);
			tree->EnsureVisible(cur_hitem);
			return;
		}
	}
}

void CaplFindInCtrlDlg::FindNextListItem(CListCtrl *list, LPCTSTR text, int delta)
{
	if(0==list) return;
	if(0==list->m_hWnd) return;
	if(!IsWindow(list->m_hWnd)) return;
	if(0==text)  return;
	if(text[0]==_T('\0'))  return;

	int cur_list_item=-1;

	if(1==delta || -1==delta) cur_list_item=list->GetNextItem ( -1, LVIS_SELECTED | LVIS_FOCUSED ); 

	CString buf;
	if(0==delta) delta=1;

	while(true)
	{
		cur_list_item+=delta;
		if(cur_list_item<0 || cur_list_item > list->GetItemCount()) return;
		bool bFound=false;
		int i;
		CHeaderCtrl *header=list->GetHeaderCtrl();
		if(0==header) return;
		for (i=0;i<header->GetItemCount(); i++)
		{
			buf=list->GetItemText(cur_list_item,i);
			buf.MakeLower();
			if(buf.Find(text)>=0) 
			{
				// Снимаем выделение
				POSITION pos = list->GetFirstSelectedItemPosition();
				while (pos)
				{
					int nItem = list->GetNextSelectedItem(pos);
					list->SetItemState(nItem,0,LVIS_SELECTED|LVIS_FOCUSED); 
				}
				// Ставим новое
				list->SetItemState(cur_list_item,LVIS_SELECTED|LVIS_FOCUSED,LVIS_SELECTED|LVIS_FOCUSED); 
				list->EnsureVisible(cur_list_item,FALSE);
				return;
			}
		}
	}
}


HHOOK CaplFindInCtrlDlg_HookProc_hk =0;
CaplMap CaplFindInCtrlDlg_map_wnd;  // Считаем что таких окон будет десятки

LRESULT  CALLBACK  CaplFindInCtrlDlg_HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	//MessageBox(NULL,"Hook","Hook",MB_OK);

	char c=(char)LOWORD(wParam);
	if(c==_T('f') || c==_T('F')|| c==_T('а') || c==_T('А'))
	{
		if (GetKeyState(VK_CONTROL) < 0 )
		{
			HWND hWnd=GetFocus();
			if(0!=hWnd)
			{
				if(CaplFindInCtrlDlg_map_wnd.QFindByIn((long)hWnd)>=0)
				{
					CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
					st_FindInCtrlDlg.Show(pWnd);
					return 0;
				}
			}
		}
	}
	return CallNextHookEx(CaplFindInCtrlDlg_HookProc_hk, nCode, wParam, lParam);
}


void CaplFindInCtrlDlg::Install (CWnd *wnd4find)
{
	if(0==CaplFindInCtrlDlg_HookProc_hk) CaplFindInCtrlDlg_HookProc_hk = SetWindowsHookEx(WH_KEYBOARD,&CaplFindInCtrlDlg_HookProc, 0, GetCurrentThreadId());
	CaplFindInCtrlDlg_map_wnd.Add((long)(wnd4find->m_hWnd),0);

	if(wnd4find->IsKindOf(RUNTIME_CLASS(CaplTreeListCtrlView)))
	{
		CaplFindInCtrlDlg_map_wnd.Add((long)((((CaplTreeListCtrlView*)wnd4find)->m_tree).m_hWnd),0);
	}
	else if(wnd4find->IsKindOf(RUNTIME_CLASS(CListView)))
	{
		CaplFindInCtrlDlg_map_wnd.Add((long)(((CListView*)wnd4find)->GetListCtrl().m_hWnd),0);
	}
}

void CaplFindInCtrlDlg::DeInstall (CWnd *wnd4find)
{
	int i=CaplFindInCtrlDlg_map_wnd.FindByIn((long)(wnd4find->m_hWnd));
	if(i>=0) CaplFindInCtrlDlg_map_wnd.Remove(i);

	if(wnd4find->IsKindOf(RUNTIME_CLASS(CaplTreeListCtrlView)))
	{
		i=CaplFindInCtrlDlg_map_wnd.FindByIn((long)((((CaplTreeListCtrlView*)wnd4find)->m_tree).m_hWnd));
		if(i>=0) CaplFindInCtrlDlg_map_wnd.Remove(i);
	}
	else if(wnd4find->IsKindOf(RUNTIME_CLASS(CListView)))
	{
		i=CaplFindInCtrlDlg_map_wnd.FindByIn((long)(((CListView*)wnd4find)->GetListCtrl().m_hWnd));
		if(i>=0) CaplFindInCtrlDlg_map_wnd.Remove(i);
	}
}

BOOL CaplFindInCtrlDlg::PreTranslateMessage(MSG* pMsg)
{
	// TODO: Add your specialized code here and/or call the base class
	m_toolTip.RelayEvent(pMsg);

	return CaplTranslateDialog::PreTranslateMessage(pMsg);
}


WNDPROC CaplFindInCtrlDlg::st_DefEditProc=0; // Исходим из ттго, что экземпляр каласса всегда будет только один
WNDPROC  CaplFindInCtrlDlg::st_DefProcbtnFindFirst=0;;
WNDPROC  CaplFindInCtrlDlg::st_DefProcbtnFindNext=0; 
WNDPROC  CaplFindInCtrlDlg::st_DefProcbtnFindPrev=0;

LRESULT CaplFindInCtrlDlg::UniversalKeyProc(WNDPROC proc, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	if(0==proc) return 0;
	if(uMsg==WM_KEYDOWN)
	{
		if(VK_F3==wParam)
		{
			if (GetKeyState(VK_LSHIFT)<0 || GetKeyState(VK_LSHIFT)<0)
				st_FindInCtrlDlg.OnBnClickedFindPrev();

			else st_FindInCtrlDlg.OnBnClickedFindNext();
			return 0;
		}
	}
	return CallWindowProc(proc, hwnd, uMsg, wParam, lParam);
}

LRESULT CaplFindInCtrlDlg::EditKeyProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	return UniversalKeyProc(st_DefEditProc, hwnd, uMsg, wParam, lParam);
}
LRESULT CaplFindInCtrlDlg::btnFindFirstKeyProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	return UniversalKeyProc(st_DefProcbtnFindFirst, hwnd, uMsg, wParam, lParam);
}
LRESULT CaplFindInCtrlDlg::btnFindNextKeyProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	return UniversalKeyProc(st_DefProcbtnFindNext, hwnd, uMsg, wParam, lParam);
}
LRESULT CaplFindInCtrlDlg::btnFindPrevKeyProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	return UniversalKeyProc(st_DefProcbtnFindPrev, hwnd, uMsg, wParam, lParam);
}

BOOL CaplFindInCtrlDlg::OnInitDialog()
{
	CaplTranslateDialog::OnInitDialog();
	st_DefEditProc=(WNDPROC)SetWindowLong(m_text_ctrl.m_hWnd, GWL_WNDPROC, (long) (&(CaplFindInCtrlDlg::EditKeyProc)));
	st_DefProcbtnFindFirst=(WNDPROC)SetWindowLong(m_btnFindFirst.m_hWnd, GWL_WNDPROC, (long) (&(CaplFindInCtrlDlg::EditKeyProc)));
	st_DefProcbtnFindNext=(WNDPROC)SetWindowLong(m_btnFindNext.m_hWnd, GWL_WNDPROC, (long) (&(CaplFindInCtrlDlg::EditKeyProc)));
	st_DefProcbtnFindPrev=(WNDPROC)SetWindowLong(m_btnFindPrev.m_hWnd, GWL_WNDPROC, (long) (&(CaplFindInCtrlDlg::EditKeyProc)));

	return TRUE;  // return TRUE unless you set the focus to a control
	// EXCEPTION: OCX Property Pages should return FALSE
}

