//this file is part of notepad++
//Copyright (C)2003 Don HO ( donho@altern.org )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#include "FindReplaceDlg.h"
#include "ScintillaEditView.h"
#include "Notepad_plus_msgs.h"
#include "constant.h"

// need this header for SHBrowseForFolder
#include <Shlobj.h>

void addText2Combo(const char * txt2add, HWND hCombo, bool isUTF8)
{	
	if (!hCombo) return;
	if (!strcmp(txt2add, "")) return;

	char text[MAX_PATH];
	int count = ::SendMessage(hCombo, CB_GETCOUNT, 0, 0);
	bool hasFound = false;
	int i = 0;

	for ( ; i < count ; i++)
	{
		::SendMessage(hCombo, CB_GETLBTEXT, i, (LPARAM)text);
		if (!strcmp(txt2add, text))
		{
			hasFound = true;
			break;
		}
	}

	if (!hasFound)
	{
		if (!isUTF8)
			i = ::SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)txt2add);
		else
		{
			WCHAR wchars[256];
			::MultiByteToWideChar(CP_UTF8, 0, txt2add, -1, wchars, 256 / sizeof(WCHAR));
			i = ::SendMessageW(hCombo, CB_ADDSTRING, 0, (LPARAM)wchars);
		}
	}

	::SendMessage(hCombo, CB_SETCURSEL, i, 0);
}

string getTextFromCombo(HWND hCombo, bool isUnicode)
{	
	char str[MAX_PATH];
	if (isUnicode)
	{
		WCHAR wchars[MAX_PATH];
		::SendMessageW(hCombo, WM_GETTEXT, MAX_PATH, (LPARAM)wchars);
		::WideCharToMultiByte(CP_UTF8, 0, wchars, -1, str, 256, NULL, NULL);
	}
	else
	{
		::SendMessage(hCombo, WM_GETTEXT, MAX_PATH, (LPARAM)str);
	}
	return string(str);
}

// Set a call back with the handle after init to set the path.
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/callbackfunctions/browsecallbackproc.asp
static int __stdcall BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM, LPARAM pData)
{
	if (uMsg == BFFM_INITIALIZED)
		::SendMessage(hwnd, BFFM_SETSELECTION, TRUE, pData);
	return 0;
};

// important : to activate all styles
const int STYLING_MASK = 255;

void FindInFilesDlg::doDialog(bool isRTL) 
{
	if (!isCreated())
		create(IDD_FINDINFILES_DLG, isRTL);
	char dir[MAX_PATH];
	::GetCurrentDirectory(sizeof(dir), dir);
	::SetDlgItemText(_hSelf, IDD_FINDINFILES_DIR_COMBO, dir);

	LangType lt;
 	::SendMessage(_hParent, WM_COMMAND, IDC_GETCURRENTDOCTYPE, (LPARAM)&lt);
	const char *ext = NppParameters::getInstance()->getLangExtFromLangType(lt);
	if (ext && ext[0])
	{
		string filtres = "";
		vector<string> vStr;
		cutString(ext, vStr);
		for (size_t i = 0 ; i < vStr.size() ; i++)
		{
			filtres += "*.";
			filtres += vStr[i] + " ";
		}
		::SetDlgItemText(_hSelf, IDD_FINDINFILES_FILTERS_COMBO, filtres.c_str());
	}
	display();
}

BOOL CALLBACK FindInFilesDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message) 
	{
		case WM_COMMAND : 
		{
			switch (wParam)
			{
				case IDCANCEL :
					display(false);
					return TRUE;

				case IDOK :
				{
					char filters[256];
					char directory[MAX_PATH];
					::GetDlgItemText(_hSelf, IDD_FINDINFILES_FILTERS_COMBO, filters, sizeof(filters));
					addText2Combo(filters, ::GetDlgItem(_hSelf, IDD_FINDINFILES_FILTERS_COMBO));
					_filters = filters;

					::GetDlgItemText(_hSelf, IDD_FINDINFILES_DIR_COMBO, directory, sizeof(directory));
					addText2Combo(directory, ::GetDlgItem(_hSelf, IDD_FINDINFILES_DIR_COMBO));
					_directory = directory;
					if (directory[strlen(directory)-1] != '\\')
						_directory += "\\";

					::SendMessage(_hParent, WM_COMMAND, IDC_FINDINFILES_LAUNCH, 0);
					display(false);
					return TRUE;
				}

				case IDD_FINDINFILES_BROWSE_BUTTON :
				{
					// This code was copied and slightly modifed from:
					// http://www.bcbdev.com/faqs/faq62.htm

					// SHBrowseForFolder returns a PIDL. The memory for the PIDL is
					// allocated by the shell. Eventually, we will need to free this
					// memory, so we need to get a pointer to the shell malloc COM
					// object that will free the PIDL later on.
					LPMALLOC pShellMalloc = 0;
					if (::SHGetMalloc(&pShellMalloc) == NO_ERROR)
					{
						// If we were able to get the shell malloc object,
						// then proceed by initializing the BROWSEINFO stuct
						BROWSEINFO info;
						memset(&info, 0, sizeof(info));
						info.hwndOwner = _hSelf;
						info.pidlRoot = NULL;
						char szDisplayName[MAX_PATH];
						info.pszDisplayName = szDisplayName;
						string title = "Select a folder to search from";
						info.lpszTitle = title.c_str();
						info.ulFlags = 0;
						info.lpfn = BrowseCallbackProc;
						char directory[MAX_PATH];
						::GetDlgItemText(_hSelf, IDD_FINDINFILES_DIR_COMBO, directory, sizeof(directory));
						info.lParam = reinterpret_cast<LPARAM>(directory);

						// Execute the browsing dialog.
						LPITEMIDLIST pidl = ::SHBrowseForFolder(&info);

						// pidl will be null if they cancel the browse dialog.
						// pidl will be not null when they select a folder.
						if (pidl) 
						{
							// Try to convert the pidl to a display string.
							// Return is true if success.
							char szDir[MAX_PATH];
							if (::SHGetPathFromIDList(pidl, szDir))
								// Set edit control to the directory path.
								::SetDlgItemText(_hSelf, IDD_FINDINFILES_DIR_COMBO, szDir);
							pShellMalloc->Free(pidl);
						}
						pShellMalloc->Release();
					}
					return TRUE;
				}
			}
		}
	}
	return FALSE;
}

void FindReplaceDlg::create(int dialogID, bool isRTL) 
{
	StaticDialog::create(dialogID, isRTL);
	_currentStatus = REPLACE;

	initOptionsFromDlg();

	if ((NppParameters::getInstance())->isTransparentAvailable())
	{
		::ShowWindow(::GetDlgItem(_hSelf, IDC_TRANSPARENT_CHECK), SW_SHOW);
		::ShowWindow(::GetDlgItem(_hSelf, IDC_PERCENTAGE_SLIDER), SW_SHOW);
		
		::SendDlgItemMessage(_hSelf, IDC_PERCENTAGE_SLIDER, TBM_SETRANGE, FALSE, MAKELONG(20, 200));
		::SendDlgItemMessage(_hSelf, IDC_PERCENTAGE_SLIDER, TBM_SETPOS, TRUE, 150);
		if (!isCheckedOrNot(IDC_PERCENTAGE_SLIDER))
			::EnableWindow(::GetDlgItem(_hSelf, IDC_PERCENTAGE_SLIDER), FALSE);
	}
	RECT rect;
	::GetWindowRect(_hSelf, &rect);
	_findW = _replaceW = rect.right - rect.left;
	_findH = _replaceH = rect.bottom - rect.top;

	_findInFilesDlg.init(_hInst, _hSelf);

	goToCenter();
}

void FindReplaceDlg::updateCombos()
{
	bool isUnicode = (*_ppEditView)->getCurrentBuffer().getUnicodeMode() != uni8Bit;
	HWND hReplaceCombo = ::GetDlgItem(_hSelf, IDREPLACEWITH);
	addText2Combo(getTextFromCombo(hReplaceCombo, isUnicode).c_str(), hReplaceCombo);

	HWND hFindCombo = ::GetDlgItem(_hSelf, IDFINDWHAT);
	addText2Combo(getTextFromCombo(hFindCombo, isUnicode).c_str(), hFindCombo);
}

bool FindReplaceDlg::notify(SCNotification *notification)
{
  switch (notification->nmhdr.code) 
  {
	case SCN_DOUBLECLICK :
	{
		try {
			// in getInfo() method the previous line is renew as current for next call
			const FoundInfo &fInfo = _pFinder->getInfo();

			int markedLine = _pFinder->getCurrentMarkedLine();

			// now we clean the previous mark
			if (markedLine != -1)
				(*_ppEditView)->execute(SCI_MARKERDELETE, markedLine, MARK_SYMBOLE);

			// After cleaning the previous mark, we can swich to another document
			::SendMessage(_hParent, WM_DOOPEN, 0, (LPARAM)fInfo._fullPath.c_str());
			(*_ppEditView)->execute(SCI_SETSEL, fInfo._start, fInfo._end);

			// we set the current mark here
			int nb = (*_ppEditView)->getCurrentLineNumber();
			_pFinder->setCurrentMarkedLine(nb);
			(*_ppEditView)->execute(SCI_MARKERADD, nb, MARK_SYMBOLE);

			// Then we colourise the double clicked line
			_pFinder->setFinderStyle();
			//_pFinder->showMargin(ScintillaEditView::_SC_MARGE_FOLDER, false);
			_pFinder->execute(SCI_SETLEXER, SCLEX_NULL);
			_pFinder->execute(SCI_STYLESETEOLFILLED, SCE_UNIVERSAL_FOUND_STYLE, true);
			int lno = _pFinder->getCurrentLineNumber();
			int start = _pFinder->execute(SCI_POSITIONFROMLINE, lno);
			int end = _pFinder->execute(SCI_GETLINEENDPOSITION, lno);
			// 
			_pFinder->execute(SCI_STARTSTYLING,  start,  STYLING_MASK);
			_pFinder->execute(SCI_SETSTYLING,  end - start + 2, SCE_UNIVERSAL_FOUND_STYLE);
			_pFinder->execute(SCI_COLOURISE,start, end + 1);
			_pFinder->execute(SCI_SETCURRENTPOS, start);
			_pFinder->execute(SCI_SETANCHOR, start);
			return true;

		} catch(...){
		}
		break;
	}

	default :
		break;
  }
  return false;
}

BOOL CALLBACK FindReplaceDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message) 
	{
		
		case WM_INITDIALOG :
		{
			// Wrap arround active by default
			::SendDlgItemMessage(_hSelf, IDWRAP, BM_SETCHECK, BST_CHECKED, 0);
			return TRUE;
		}
		
		case WM_HSCROLL :
		{
			if ((HWND)lParam == ::GetDlgItem(_hSelf, IDC_PERCENTAGE_SLIDER))
			{
				int percent = ::SendDlgItemMessage(_hSelf, IDC_PERCENTAGE_SLIDER, TBM_GETPOS, 0, 0);
				(NppParameters::getInstance())->SetTransparent(_hSelf, percent);
			}
			return TRUE;
		}
		
		case WM_SIZE:
		{
			resizeFinder();
			resizeStatusBar();
			return FALSE;
		}

		case WM_NOTIFY:
		{
			if (notify(reinterpret_cast<SCNotification *>(lParam)))
			{
				//::SendMessage((*_ppEditView)->getHSelf(), WM_KILLFOCUS, (WPARAM)::GetDlgItem(_hSelf, IDFINDWHAT), 0);
				//::SendMessage(::GetDlgItem(_hSelf, IDFINDWHAT), WM_SETFOCUS, (WPARAM)(*_ppEditView)->getHSelf(), 0);

				//::SetFocus(::GetDlgItem(_hSelf, IDC_IN_SELECTION_CHECK));
				//::MessageBox(NULL, "", "Ben!", MB_OK);
			}
			return FALSE;
		}
		
		case WM_ACTIVATE :
		{
			CharacterRange cr = (*_ppEditView)->getSelection();
			bool isSelected = (cr.cpMax - cr.cpMin) != 0;
			if (!isSelected)
			{
				::SendDlgItemMessage(_hSelf, IDC_IN_SELECTION_CHECK, BM_SETCHECK, BST_UNCHECKED, 0);
				_isInSelection = false;
			}
			::EnableWindow(::GetDlgItem(_hSelf, IDC_IN_SELECTION_CHECK), isSelected);
			return TRUE;
		}
		case WM_MODELESSDIALOG :
			return ::SendMessage(_hParent, WM_MODELESSDIALOG, wParam, lParam);

		case WM_COMMAND : 
		{
			switch (wParam)
			{
				case IDCANCEL : // Close
					display(false);
					if (_findInFilesDlg.isCreated())
						_findInFilesDlg.display(false);
					return TRUE;

				case IDOK : // Find Next
				{
					bool isUnicode = (*_ppEditView)->getCurrentBuffer().getUnicodeMode() != uni8Bit;
					HWND hFindCombo = ::GetDlgItem(_hSelf, IDFINDWHAT);
					string str2Search = getTextFromCombo(hFindCombo, isUnicode);
					addText2Combo(str2Search.c_str(), hFindCombo);
					processFindNext(str2Search.c_str());
				}
				return TRUE;

				case IDREPLACE :
				{
					updateCombos();

					processReplace();
					return TRUE;
				}

				case IDSWITCH :
					_currentStatus = !_currentStatus;
					doDialog(_currentStatus);
					return TRUE;

				case IDREPLACEALL :
				{
					updateCombos();

					(*_ppEditView)->execute(SCI_BEGINUNDOACTION);
					int nbReplaced = processAll(REPLACE_ALL);
					(*_ppEditView)->execute(SCI_ENDUNDOACTION);

					char result[64];
					if (nbReplaced < 0)
						strcpy(result, "The regular expression to search is formed badly");
					else
					{
						itoa(nbReplaced, result, 10);
						strcat(result, " tokens are replaced.");
					}
					::MessageBox(_hSelf, result, "", MB_OK);
					return TRUE;
				}

				case IDC_REPLACE_OPENEDFILES :
					updateCombos();
					replaceAllInOpenedDocs();
					return TRUE;

				case IDC_FINDALL_OPENEDFILES :
					updateCombo(IDFINDWHAT);
					findAllIn(ALL_OPEN_DOCS);
					return TRUE;

				case IDC_FINDINFILES :
					_findInFilesDlg.doDialog(_isRTL);
					return TRUE;

				case IDC_GETCURRENTDOCTYPE :
					*((LangType *)lParam) = (*_ppEditView)->getCurrentDocType();
					return TRUE;

				case IDC_FINDINFILES_LAUNCH : // Virtual Control which don't exist
				{
					updateCombo(IDFINDWHAT);
					findAllIn(FILES_IN_DIR);
					return TRUE;
				}


				case IDCMARKALL :
				{
					updateCombo(IDFINDWHAT);
					int nbMarked = processAll(MARK_ALL);
					char result[64];
					if (nbMarked < 0)
						strcpy(result, "The regular expression to search is formed badly");
					else
					{
						itoa(nbMarked, result, 10);
						strcat(result, " tokens are found and marked");
					}

					::MessageBox(_hSelf, result, "", MB_OK);
					return TRUE;
				}

				case IDC_CLEAR_ALL :
				{
					LangType lt = (*_ppEditView)->getCurrentDocType();
                    if (lt == L_TXT)
                            (*_ppEditView)->defineDocType(L_CPP); 
					(*_ppEditView)->defineDocType(lt);
					(*_ppEditView)->execute(SCI_MARKERDELETEALL, MARK_SYMBOLE);
					return TRUE;
				}

				case IDCCOUNTALL :
				{
					int nbCounted = processAll(COUNT_ALL);
					char result[64];
					if (nbCounted < 0)
						strcpy(result, "The regular expression to search is formed badly");
					else
					{
						itoa(nbCounted, result, 10);
						strcat(result, " tokens are found.");
					}
					::MessageBox(_hSelf, result, "", MB_OK);
					return TRUE;
				}

				case IDWHOLEWORD :
					_options._isWholeWord = isCheckedOrNot(IDWHOLEWORD);
					return TRUE;

				case IDMATCHCASE :
					_options._isMatchCase = isCheckedOrNot(IDMATCHCASE);
					return TRUE;

				case IDREGEXP :
					_options._isRegExp = isCheckedOrNot(IDREGEXP);

					if (_options._isRegExp)
						_options._isWholeWord = false;
					::SendDlgItemMessage(_hSelf, IDWHOLEWORD, BM_SETCHECK, _options._isWholeWord?BST_CHECKED:BST_UNCHECKED, 0);
					::EnableWindow(::GetDlgItem(_hSelf, IDWHOLEWORD), (BOOL)!_options._isRegExp);

					::SendDlgItemMessage(_hSelf, IDDIRECTIONUP, BM_SETCHECK, BST_UNCHECKED, 0);
					::EnableWindow(::GetDlgItem(_hSelf, IDDIRECTIONUP), (BOOL)!_options._isRegExp);
					::SendDlgItemMessage(_hSelf, IDDIRECTIONDOWN, BM_SETCHECK, BST_CHECKED, 0);
					_options._whichDirection = DIR_DOWN;
					return TRUE;

				case IDWRAP :
					_options._isWrapAround = isCheckedOrNot(IDWRAP);
					return TRUE;

				case IDDIRECTIONUP :
				case IDDIRECTIONDOWN :
					_options._whichDirection = (BST_CHECKED == ::SendMessage(::GetDlgItem(_hSelf, IDDIRECTIONDOWN), BM_GETCHECK, BST_CHECKED, 0));
					::EnableWindow(::GetDlgItem(_hSelf, IDC_DISPLAYPOS_STATIC), (BOOL)(_options._whichDirection == DIR_DOWN));
					::EnableWindow(::GetDlgItem(_hSelf, IDC_DISPLAYPOS_TOP), (BOOL)(_options._whichDirection == DIR_DOWN));
					::EnableWindow(::GetDlgItem(_hSelf, IDC_DISPLAYPOS_MIDDLE), (BOOL)(_options._whichDirection == DIR_DOWN));
					::EnableWindow(::GetDlgItem(_hSelf, IDC_DISPLAYPOS_BOTTOM), (BOOL)(_options._whichDirection == DIR_DOWN));
					return TRUE;

				case IDC_PURGE_CHECK :
					_doPurge = isCheckedOrNot(IDC_PURGE_CHECK);
					return TRUE;

				case IDC_MARKLINE_CHECK :
					_doMarkLine = isCheckedOrNot(IDC_MARKLINE_CHECK);
					::EnableWindow(::GetDlgItem(_hSelf, IDCMARKALL), (_doMarkLine || _doStyleFoundToken));
					return TRUE;

				case IDC_STYLEFOUND_CHECK :
					_doStyleFoundToken = isCheckedOrNot(IDC_STYLEFOUND_CHECK);
					::EnableWindow(::GetDlgItem(_hSelf, IDCMARKALL), (_doMarkLine || _doStyleFoundToken));
					return TRUE;

				case IDC_IN_SELECTION_CHECK :
					_isInSelection = isCheckedOrNot(IDC_IN_SELECTION_CHECK);
					return TRUE;

				case IDC_TRANSPARENT_CHECK :
				{
					bool isChecked = isCheckedOrNot(IDC_TRANSPARENT_CHECK);
					if (isChecked)
					{
						int percent = ::SendDlgItemMessage(_hSelf, IDC_PERCENTAGE_SLIDER, TBM_GETPOS, 0, 0);
						(NppParameters::getInstance())->SetTransparent(_hSelf, percent);
					}
					else
						(NppParameters::getInstance())->removeTransparent(_hSelf);

					::EnableWindow(::GetDlgItem(_hSelf, IDC_PERCENTAGE_SLIDER), isChecked);
					return TRUE;
				}

				default :
					break;
			}
		}
	}
	return FALSE;
}

// return value :
// true  : the text2find is found
// false : the text2find is not found
bool FindReplaceDlg::processFindNext(const char *txt2find, FindOption *options)
{
	if (!txt2find || !txt2find[0])
		return false;

	const char *pText = txt2find;
	FindOption *pOptions = options?options:&_options;

	int docLength = int((*_ppEditView)->execute(SCI_GETLENGTH));
	CharacterRange cr = (*_ppEditView)->getSelection();

	int startPosition = cr.cpMax;
	int endPosition = docLength;

	if (pOptions->_whichDirection == DIR_UP)
	{
		startPosition = cr.cpMin - 1;
		endPosition = 0;
	}

	if (pOptions->_isIncremental)
	{
		startPosition = 0;
		endPosition = docLength;	
	}

	int flags = (pOptions->_isWholeWord ? SCFIND_WHOLEWORD : 0) |
	            (pOptions->_isMatchCase ? SCFIND_MATCHCASE : 0) |
	            (pOptions->_isRegExp ? SCFIND_REGEXP|SCFIND_POSIX : 0);

	(*_ppEditView)->execute(SCI_SETTARGETSTART, startPosition);
	(*_ppEditView)->execute(SCI_SETTARGETEND, endPosition);
	(*_ppEditView)->execute(SCI_SETSEARCHFLAGS, flags);

	
	//char translatedText[FIND_REPLACE_STR_MAX];

	/*
	if (_isRegExp)
	{
		formatType f = (*_ppEditView)->getCurrentBuffer().getFormat();
		pText = translate2SlashN(translatedText, f);
	}
	*/

	int posFind = int((*_ppEditView)->execute(SCI_SEARCHINTARGET, strlen(pText), (LPARAM)pText));
	if (posFind == -1) //return;
	{
		if (pOptions->_isWrapAround) 
		{
			if (pOptions->_whichDirection == DIR_DOWN)
			{
				startPosition = 0;
				endPosition = docLength;
			}
			else
			{
				startPosition = docLength;
				endPosition = 0;
			}

			(*_ppEditView)->execute(SCI_SETTARGETSTART, startPosition);
			(*_ppEditView)->execute(SCI_SETTARGETEND, endPosition);
			int posFind = int((*_ppEditView)->execute(SCI_SEARCHINTARGET, strlen(pText), (LPARAM)pText));
			if (posFind == -1)
			{
				if (pOptions->_isIncremental)
					return false;
				
				::MessageBox(_hSelf, "Can't find the word", "Find", MB_OK);
				// if the dialog is not shown, pass the focus to his parent(ie. Notepad++)
				if (!::IsWindowVisible(_hSelf))
					::SetFocus((*_ppEditView)->getHSelf());

				return false;
			}
			int start = int((*_ppEditView)->execute(SCI_GETTARGETSTART));
			int end = int((*_ppEditView)->execute(SCI_GETTARGETEND));
			(*_ppEditView)->execute(SCI_SETSEL, start, end);

			// to make sure the found result is visible
			int lineno = (*_ppEditView)->getCurrentLineNumber();
			(*_ppEditView)->execute(SCI_ENSUREVISIBLEENFORCEPOLICY, lineno);
		}
		else
		{
			if (pOptions->_isIncremental)
				return false;

			::MessageBox(_hSelf, "Can't find the word", "Find", MB_OK);

			// if the dialog is not shown, pass the focus to his parent(ie. Notepad++)
			if (!::IsWindowVisible(_hSelf))
				::SetFocus((*_ppEditView)->getHSelf());

			return false;
		}
	}


	int start = int((*_ppEditView)->execute(SCI_GETTARGETSTART));
	int end = int((*_ppEditView)->execute(SCI_GETTARGETEND));

	int displayPos = getDisplayPos();
	(*_ppEditView)->execute(SCI_SETSEL, start, end);

	// to make sure the found result is visible
	int lineno = (*_ppEditView)->getCurrentLineNumber();
	(*_ppEditView)->execute(SCI_ENSUREVISIBLEENFORCEPOLICY, lineno);

	if ((displayPos != DISPLAY_POS_BOTTOM) && (_options._whichDirection == DIR_DOWN))
	{
		int firstVisibleLine = (*_ppEditView)->execute(EM_GETFIRSTVISIBLELINE);
		int currentlineNumber = (*_ppEditView)->execute(SCI_LINEFROMPOSITION, posFind);
		int nbColumn2Scroll;

		if (displayPos == DISPLAY_POS_TOP)
			nbColumn2Scroll = currentlineNumber-firstVisibleLine;
		else //(displayPos == DISPLAY_POS_MIDDLE)
			nbColumn2Scroll = (currentlineNumber-firstVisibleLine)/2;

		(*_ppEditView)->scroll(0, nbColumn2Scroll);
	}
	return true;
}

// return value :
// true  : the text is replaced, and find the next occurrence
// false : the text2find is not found, so the text is NOT replace
//      || the text is replaced, and do NOT find the next occurrence
bool FindReplaceDlg::processReplace()
{
	if ((*_ppEditView)->getCurrentBuffer().isReadOnly()) return false;

	//getSearchTexts();
	//getReplaceTexts();
	bool isUnicode = (*_ppEditView)->getCurrentBuffer().getUnicodeMode() != uni8Bit;
	string str2Search = getTextFromCombo(::GetDlgItem(_hSelf, IDFINDWHAT), isUnicode);
	string str2Relace = getTextFromCombo(::GetDlgItem(_hSelf, IDREPLACEWITH), isUnicode);

	
	int flags = (_options._isWholeWord ? SCFIND_WHOLEWORD : 0) |
	            (_options._isMatchCase ? SCFIND_MATCHCASE : 0) |
	            (_options._isRegExp ? SCFIND_REGEXP|SCFIND_POSIX : 0);

	CharacterRange cr = (*_ppEditView)->getSelection();
	
	(*_ppEditView)->execute(SCI_SETTARGETSTART, cr.cpMin);
	(*_ppEditView)->execute(SCI_SETTARGETEND, cr.cpMax);
	(*_ppEditView)->execute(SCI_SETSEARCHFLAGS, flags);

	int posFind = int((*_ppEditView)->execute(SCI_SEARCHINTARGET, (WPARAM)str2Search.length(), (LPARAM)str2Search.c_str()));

	if (posFind != -1)
	{
		if (_options._isRegExp)
		{
			//For the rare re exp case. ex: replace ^ by AAA
			int start = int((*_ppEditView)->execute(SCI_GETTARGETSTART));
			int end = int((*_ppEditView)->execute(SCI_GETTARGETEND));
			int foundTextLen = (end >= start)?end - start:start - end;

			int replacedLen = (*_ppEditView)->execute(SCI_REPLACETARGETRE, str2Relace.length(), (LPARAM)str2Relace.c_str());
			
			if (!foundTextLen)
				(*_ppEditView)->execute(SCI_SETSEL, start, start + replacedLen);
		}
		else
		{
			(*_ppEditView)->execute(SCI_REPLACESEL, str2Relace.length(), (LPARAM)str2Relace.c_str());
		}
	}
	return processFindNext(str2Search.c_str());
}

int FindReplaceDlg::processAll(int op, bool isEntire, const char *dir2search)
{
	int nbReplaced = 0;
	
	if (!isCreated()) return nbReplaced;

	if ((op == REPLACE_ALL) && (*_ppEditView)->getCurrentBuffer().isReadOnly())
		return nbReplaced;

	FindOption *pOptions = &_options;

	bool isUnicode = (*_ppEditView)->getCurrentBuffer().getUnicodeMode() != uni8Bit;
	string str2Search = getTextFromCombo(::GetDlgItem(_hSelf, IDFINDWHAT), isUnicode);
	string str2Relace = getTextFromCombo(::GetDlgItem(_hSelf, IDREPLACEWITH), isUnicode);
	
	int docLength = int((*_ppEditView)->execute(SCI_GETLENGTH));

	CharacterRange cr = (*_ppEditView)->getSelection();

	// Par default : 
	//        direction : bas
	//        commence par : cursor pos
	//        fini par : fin doc
	int startPosition = cr.cpMin;
	int endPosition = docLength;


	if (pOptions->_whichDirection == DIR_UP)
	{
		startPosition = cr.cpMax;
		endPosition = 0;
	}

	bool direction = pOptions->_whichDirection;
	
	if ((pOptions->_isWrapAround || isEntire) || (op == COUNT_ALL))
	{		
		startPosition = 0;
		endPosition = docLength;
		direction = DIR_DOWN;
	}

	if ((_isInSelection) && ((op == MARK_ALL) || ((op == REPLACE_ALL) && (!isEntire))))
	{
		CharacterRange cr = (*_ppEditView)->getSelection();
		startPosition = cr.cpMin;
		endPosition = cr.cpMax;
	}
	
	int flags = (pOptions->_isWholeWord ? SCFIND_WHOLEWORD : 0) |
	            (pOptions->_isMatchCase ? SCFIND_MATCHCASE : 0) |
	            (pOptions->_isRegExp ? SCFIND_REGEXP|SCFIND_POSIX : 0);

	(*_ppEditView)->execute(SCI_SETTARGETSTART, startPosition);
	(*_ppEditView)->execute(SCI_SETTARGETEND, endPosition);
	(*_ppEditView)->execute(SCI_SETSEARCHFLAGS, flags);

	/*addText2Combo(_text2Find, ::GetDlgItem(_hSelf, IDFINDWHAT), (*_ppEditView)->getCurrentBuffer().getUnicodeMode() != uni8Bit);
	if (!_text2Find[0])
		return nbReplaced;*/

	if (op == MARK_ALL)
	{
		if (_doStyleFoundToken)
		{
			if (_doPurge)
			{
				LangType lt = (*_ppEditView)->getCurrentDocType();
                if (lt == L_TXT)
					(*_ppEditView)->defineDocType(L_CPP); 
				(*_ppEditView)->defineDocType(lt);
			}
			(*_ppEditView)->execute(SCI_SETLEXER, SCLEX_NULL);
		}
		if ((_doMarkLine) && (_doPurge))
		{
			(*_ppEditView)->execute(SCI_MARKERDELETEALL, MARK_SYMBOLE);
		}
	}

	int posFind = int((*_ppEditView)->execute(SCI_SEARCHINTARGET, (WPARAM)str2Search.length(), (LPARAM)str2Search.c_str()));
	
	while (posFind != -1)
	{
		int posFindBefore = posFind;
		int start = int((*_ppEditView)->execute(SCI_GETTARGETSTART));
		int end = int((*_ppEditView)->execute(SCI_GETTARGETEND));
		int foundTextLen = (end >= start)?end - start:start - end;

		// Si on a trouvé une occurence vide, y'a un pb!!!
		if (!foundTextLen)
			return -1;
		
		if (op == REPLACE_ALL)
		{
			(*_ppEditView)->execute(SCI_SETTARGETSTART, start);
			(*_ppEditView)->execute(SCI_SETTARGETEND, end);
			int replacedLength = (*_ppEditView)->execute(pOptions->_isRegExp?SCI_REPLACETARGETRE:SCI_REPLACETARGET, (WPARAM)-1, (LPARAM)str2Relace.c_str());

			startPosition = (direction == DIR_UP)?posFind - replacedLength:posFind + replacedLength;
			if ((_isInSelection) && (!isEntire))
			{
				endPosition = endPosition - foundTextLen + replacedLength;
			}
			else
			{
				if (direction == DIR_DOWN)
					endPosition = docLength = docLength - foundTextLen + replacedLength;
			}
			
		}
		else if (op == MARK_ALL)
		{
			if (_doStyleFoundToken)
			{
				(*_ppEditView)->execute(SCI_STARTSTYLING,  start,  STYLING_MASK);
				(*_ppEditView)->execute(SCI_SETSTYLING,  end - start,  SCE_UNIVERSAL_FOUND_STYLE);
				(*_ppEditView)->execute(SCI_COLOURISE, start, end+1);
			}

			if (_doMarkLine)
			{
				int lineNumber = (*_ppEditView)->execute(SCI_LINEFROMPOSITION, posFind);
				int state = (*_ppEditView)->execute(SCI_MARKERGET, lineNumber);

				if (!(state & (1 << MARK_SYMBOLE)))
					(*_ppEditView)->execute(SCI_MARKERADD, lineNumber, MARK_SYMBOLE);
			}
			startPosition = (direction == DIR_UP)?posFind - foundTextLen:posFind + foundTextLen;
		}
		else if (op == COUNT_ALL)
		{
			startPosition = posFind + foundTextLen;
		}
		else if (op == FIND_ALL)
		{
			int lineNumber = (*_ppEditView)->execute(SCI_LINEFROMPOSITION, posFind);
			int lend = (*_ppEditView)->execute(SCI_GETLINEENDPOSITION, lineNumber);
			int lstart = (*_ppEditView)->execute(SCI_POSITIONFROMLINE, lineNumber);
			int nbChar = lend - lstart;
			char *line = new char[nbChar + 3];
			(*_ppEditView)->execute(SCI_GETLINE, lineNumber, (LPARAM)line);
			line[nbChar] = 0x0D;
			line[nbChar+1] = 0x0A;
			line[nbChar+2] = '\0';
			_pFinder->add(FoundInfo(start, end, line, (*_ppEditView)->getCurrentBuffer().getFileName()), lineNumber + 1, dir2search);

			delete [] line;

			startPosition = posFind + foundTextLen;
		}
		else
			return nbReplaced;

        
		(*_ppEditView)->execute(SCI_SETTARGETSTART, startPosition);
		(*_ppEditView)->execute(SCI_SETTARGETEND, endPosition);

		posFind = int((*_ppEditView)->execute(SCI_SEARCHINTARGET, (WPARAM)str2Search.length(), (LPARAM)str2Search.c_str()));
		nbReplaced++;
	}

	return nbReplaced;
}

void FindReplaceDlg::replaceAllInOpenedDocs()
{
	::SendMessage(_hParent, WM_REPLACEALL_INOPENEDDOC, 0, 0);
}

void FindReplaceDlg::resizeFinder()
{
	RECT wrapRect, sliderRect, scintEditRect, findRect;
	POINT pointScintEdit;
	//get screen coordonnees (x,y)
	::GetWindowRect(::GetDlgItem(_hSelf, IDWRAP), &wrapRect);
	::GetWindowRect(::GetDlgItem(_hSelf, IDC_PERCENTAGE_SLIDER), &sliderRect);
	
	::GetWindowRect(_hSelf, &findRect);
	// get the width of FindDlg
	if (_currentStatus == FIND)
	{
		_findW = findRect.right - findRect.left;
		_findH = findRect.bottom - findRect.top;
	}

	// set point (x,y)
	pointScintEdit.x = wrapRect.left - 2;
	pointScintEdit.y = sliderRect.bottom + 10;

	// calculate the space for scintEdit
	int scintEditHeight = findRect.bottom - pointScintEdit.y - 22;
	int scintEditWidth = findRect.right - findRect.left;
	// convert screen coordonnees to client coordonnees
	::ScreenToClient(_hSelf, &pointScintEdit);
	
	scintEditRect.left = pointScintEdit.x;
	scintEditRect.top = pointScintEdit.y;
	scintEditRect.right = pointScintEdit.x + scintEditWidth- 20;
	scintEditRect.bottom = pointScintEdit.y + scintEditHeight;
	
	::MoveWindow(_pFinder->getHSelf(), scintEditRect.left, scintEditRect.top, scintEditRect.right - scintEditRect.left, scintEditRect.bottom - scintEditRect.top, TRUE);
}

void FindReplaceDlg::resizeStatusBar()
{
	RECT rect;
	int h = _statusBar.getHeight();
	::GetWindowRect(_hSelf, &rect);
	rect.top = rect.top + rect.bottom - h;
	::MoveWindow(_statusBar.getHSelf(), rect.left, rect.top, rect.right - rect.left, h, TRUE);
}

void FindReplaceDlg::findAllIn(InWhat op)
{
	if (!_pFinder)
	{
		_pFinder = new Finder;
		_pFinder->init(_hInst, _hSelf);
		_statusBar.init(_hInst, _hSelf, 0);
		RECT findRect;

		const int scintEditInitHeight = 130;

		// get the width of FindDlg
		::GetWindowRect(_hSelf, &findRect);
		findRect.bottom += scintEditInitHeight;

		::MoveWindow(_hSelf, findRect.left, findRect.top, findRect.right - findRect.left, findRect.bottom - findRect.top, TRUE);

		// resizeFinder() will be called in WM_SIZE

		_pFinder->showMargin(ScintillaEditView::_SC_MARGE_SYBOLE, false);
		_pFinder->setFinderStyle();
		_pFinder->showMargin(ScintillaEditView::_SC_MARGE_FOLDER, false);
		_pFinder->execute(SCI_SETZOOM, _pFinder->execute(SCI_GETZOOM) - 2);
		_pFinder->display();
		_statusBar.display();

		long style = ::GetWindowLong(_hSelf, GWL_STYLE);
		style |= WS_SIZEBOX;
		::SetWindowLong(_hSelf, GWL_STYLE, style);

	}

	::SendMessage(_hParent, (op==ALL_OPEN_DOCS)?WM_FINDALL_INOPENEDDOC:WM_FINDINFILES, 0, 0);
	char text2show[64] = "Found : ";
	if (_findAllResult < 0)
		strcat(text2show, "The regular expression to search is formed badly");
	else
	{
		char result[10];
		itoa(_findAllResult, result, 10);
		strcat(text2show, result);
	}
	
	_statusBar.setText(text2show, 0);
}

void FindReplaceDlg::enableReplaceFunc(bool isEnable) 
{
	_currentStatus = isEnable;
	int hideOrShow = isEnable?SW_SHOW:SW_HIDE;
	// replce controls
	::ShowWindow(::GetDlgItem(_hSelf, ID_STATICTEXT_REPLACE),hideOrShow);
	::ShowWindow(::GetDlgItem(_hSelf, IDREPLACE),hideOrShow);
	::ShowWindow(::GetDlgItem(_hSelf, IDREPLACEWITH),hideOrShow);
	::ShowWindow(::GetDlgItem(_hSelf, IDREPLACEALL),hideOrShow);
	::ShowWindow(::GetDlgItem(_hSelf, IDREPLACEINSEL),hideOrShow);
	::ShowWindow(::GetDlgItem(_hSelf, IDC_REPLACE_OPENEDFILES),hideOrShow);
	::ShowWindow(::GetDlgItem(_hSelf, IDC_REPLACEINSELECTION),hideOrShow);

	// find controls
	::ShowWindow(::GetDlgItem(_hSelf, IDC_FINDALL_OPENEDFILES), !hideOrShow);
	::ShowWindow(::GetDlgItem(_hSelf, IDCCOUNTALL),!hideOrShow);
	::ShowWindow(::GetDlgItem(_hSelf, IDC_FINDALL_STATIC),!hideOrShow);
	::ShowWindow(::GetDlgItem(_hSelf, IDCMARKALL),!hideOrShow);
	::ShowWindow(::GetDlgItem(_hSelf, IDC_MARKLINE_CHECK),!hideOrShow);
	::ShowWindow(::GetDlgItem(_hSelf, IDC_STYLEFOUND_CHECK),!hideOrShow);
	::ShowWindow(::GetDlgItem(_hSelf, IDC_PURGE_CHECK),!hideOrShow);
	::ShowWindow(::GetDlgItem(_hSelf, IDC_CLEAR_ALL),!hideOrShow);
	::ShowWindow(::GetDlgItem(_hSelf, IDC_FINDINFILES),!hideOrShow);

	long style = ::GetWindowLong(_hSelf, GWL_STYLE);
	style &= ~WS_SIZEBOX;
	::SetWindowText(_hSelf, isEnable?"Replace":"Find");
	if (_pFinder)
	{
		_pFinder->display(!isEnable);
		_statusBar.display(!isEnable);
	}
	RECT rect;
	::GetWindowRect(_hSelf, &rect);
	::MoveWindow(_hSelf, rect.left, rect.top, isEnable?_replaceW:_findW, isEnable?_replaceH:_findH, TRUE);
	if ((!isEnable)&&(_pFinder))
		style |= WS_SIZEBOX;

	::SetWindowLong(_hSelf, GWL_STYLE, style);
}

void FindReplaceDlg::getPatterns(vector<string> & patternVect)
{
	cutString((_findInFilesDlg.getFilters()).c_str(), patternVect);
}

void Finder::setFinderStyle()
{
    StyleArray & stylers = _pParameter->getMiscStylerArray();
    int iStyleDefault = stylers.getStylerIndexByID(STYLE_DEFAULT);
    if (iStyleDefault != -1)
    {
        Style & styleDefault = stylers.getStyler(iStyleDefault);
	    setStyle(styleDefault._styleID, styleDefault._fgColor, styleDefault._bgColor, styleDefault._fontName, styleDefault._fontStyle, styleDefault._fontSize);
    }

    execute(SCI_STYLECLEARALL);

	//StyleArray & stylers = _pParameter->getMiscStylerArray();
    int iFind = stylers.getStylerIndexByID(SCE_UNIVERSAL_FOUND_STYLE);
    if (iFind != -1)
    {
        Style & styleFind = stylers.getStyler(iFind);
	    setStyle(styleFind._styleID, styleFind._fgColor, styleFind._bgColor, styleFind._fontName, styleFind._fontStyle, styleFind._fontSize);
    }

	iFind = stylers.getStylerIndexByID(SCE_UNIVERSAL_SELECT_STYLE);
    if (iFind != -1)
    {
        Style & styleFind = stylers.getStyler(iFind);
	    setStyle(styleFind._styleID, styleFind._fgColor, styleFind._bgColor, styleFind._fontName, styleFind._fontStyle, styleFind._fontSize);
    }

	execute(SCI_SETSTYLEBITS, 5);
    setCppLexer(L_CPP);
	execute(SCI_COLOURISE, 0, -1);
}

BOOL CALLBACK FindIncrementDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message) 
	{
		case WM_COMMAND : 
		{
			bool isUnicode = (*(_pFRDlg->_ppEditView))->getCurrentBuffer().getUnicodeMode() != uni8Bit;
			switch (LOWORD(wParam))
			{
				case IDCANCEL :
					display(false);
					return TRUE;

				case IDC_INCFINDPREVOK :
				case IDC_INCFINDNXTOK :
				{
					FindOption fo;
					fo._isWholeWord = false;
					fo._isMatchCase = (BST_CHECKED == ::SendDlgItemMessage(_hSelf, IDC_INCFINDMATCHCASE, BM_GETCHECK, 0, 0));
					if (LOWORD(wParam) == IDC_INCFINDPREVOK)
						fo._whichDirection = DIR_UP;
					
					string str2Search = getTextFromCombo(::GetDlgItem(_hSelf, IDC_INCFINDTEXT), isUnicode);
					_pFRDlg->processFindNext(str2Search.c_str(), &fo);
				}
				return TRUE;

				case IDC_INCFINDTEXT :
					if ((wParam >> 16) == 0x0300)
					{
						if (_doSearchFromBegin)
						{
							FindOption fo;
							fo._isWholeWord = false;
							fo._isIncremental = true;
							fo._isMatchCase = (BST_CHECKED == ::SendDlgItemMessage(_hSelf, IDC_INCFINDMATCHCASE, BM_GETCHECK, 0, 0));

							string str2Search = getTextFromCombo(::GetDlgItem(_hSelf, IDC_INCFINDTEXT), isUnicode);
							_pFRDlg->processFindNext(str2Search.c_str(), &fo);
						}
						else
							_doSearchFromBegin = true;
					}
					return TRUE;

			}
		}
	}
	return FALSE;
}

void FindIncrementDlg::goToLowerLeft()
{
    RECT rc;
    ::GetClientRect(_hParent, &rc);
	//RECT rcSelf;
	//::GetClientRect(_hSelf, &rcSelf);
	int selfHeight = _rc.bottom - _rc.top;
	int selfWidth = _rc.right - _rc.left;

    POINT llpoint;
    llpoint.x = rc.left;
	llpoint.y = rc.bottom - selfHeight;
    ::ClientToScreen(_hParent, &llpoint);
	
	::SetWindowPos(_hSelf, HWND_TOP, llpoint.x, llpoint.y, selfWidth, selfHeight, SWP_SHOWWINDOW);
}
