generic_string PathAppend(generic_string& strDest, const generic_string& str2append)
{
	if (strDest.empty() && str2append.empty()) // "" + ""
	{
		strDest = TEXT("\\");
		return strDest;
	}

	if (strDest.empty() && not str2append.empty()) // "" + titi
	{
		strDest = str2append;
		return strDest;
	}

	if (strDest[strDest.length() - 1] == '\\' && (not str2append.empty() && str2append[0] == '\\')) // toto\ + \titi
	{
		strDest.erase(strDest.length() - 1, 1);
		strDest += str2append;
		return strDest;
	}

	if ((strDest[strDest.length() - 1] == '\\' && (not str2append.empty() && str2append[0] != '\\')) // toto\ + titi
		|| (strDest[strDest.length() - 1] != '\\' && (not str2append.empty() && str2append[0] == '\\'))) // toto + \titi
	{
		strDest += str2append;
		return strDest;
	}

	// toto + titi
	strDest += TEXT("\\");
	strDest += str2append;

	return strDest;
}
bool FunctionListPanel::serialize(const generic_string & outputFilename)
{
	generic_string fname;
	if (outputFilename.empty()) // if outputFilename is not given, get the current file path by adding the file extension
	{
		Buffer* currentBuf = (*_ppEditView)->getCurrentBuffer();
		const TCHAR *fullFilePath = currentBuf->getFullPathName();

		// Export function list from an existing file 
		bool exportFuncntionList = (NppParameters::getInstance())->doFunctionListExport();
		if (exportFuncntionList && ::PathFileExists(fullFilePath))
		{
			fname = fullFilePath;
			fname += TEXT(".result");
		}
		else
			return false;
	}
	else
	{
		fname = outputFilename;
	}

	FILE * f = generic_fopen(fname.c_str(), TEXT("w+"));
	if (!f)
		return false;

	for (const auto & info : _foundFuncInfos)
	{
		generic_string entryName;
		if (!info._data2.empty())
		{
			entryName = info._data2;
			entryName += TEXT("=>");
		}
		entryName += info._data;
		entryName += TEXT("\n");

		WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance();
		UINT cp = static_cast<UINT>((*_ppEditView)->execute(SCI_GETCODEPAGE));
		const char *textA = wmc->wchar2char(entryName.c_str(), cp);
		string entryNameA = textA;

		fwrite(entryNameA.c_str(), sizeof(entryNameA.c_str()[0]), entryNameA.length(), f);
	}
	fflush(f);
	fclose(f);
	return true;
}
DWORD WINAPI FolderUpdater::watching(void *params)
{
	FolderUpdater *thisFolderUpdater = (FolderUpdater *)params;

	generic_string dir2Watch = (thisFolderUpdater->_rootFolder)._rootPath;
	if (dir2Watch[dir2Watch.length() - 1] != '\\')
		dir2Watch += TEXT("\\"); // CReadDirectoryChanges will add another '\' so we will get "\\" as a separator (of monitored root) in the notification

	const DWORD dwNotificationFlags = FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_FILE_NAME;

	// Create the monitor and add directory to watch.
	CReadDirectoryChanges changes;
	changes.AddDirectory(dir2Watch.c_str(), true, dwNotificationFlags);

	HANDLE changeHandles[] = { thisFolderUpdater->_EventHandle, changes.GetWaitHandle() };

	bool toBeContinued = true;

	while (toBeContinued)
	{
		DWORD waitStatus = ::WaitForMultipleObjects(_countof(changeHandles), changeHandles, FALSE, INFINITE);
		switch (waitStatus)
		{
			case WAIT_OBJECT_0 + 0:
			// Mutex was signaled. User removes this folder or file browser is closed
				toBeContinued = false;
				break;

			case WAIT_OBJECT_0 + 1:
			// We've received a notification in the queue.
			{
				DWORD dwAction;
				CStringW wstrFilename;
				if (changes.CheckOverflow())
					printStr(L"Queue overflowed.");
				else
				{
					changes.Pop(dwAction, wstrFilename);
					static generic_string oldName;
					static std::vector<generic_string> file2Change;
					file2Change.clear();

					switch (dwAction)
					{
						case FILE_ACTION_ADDED:
							file2Change.push_back(wstrFilename.GetString());
							//thisFolderUpdater->updateTree(dwAction, file2Change);
							::SendMessage((thisFolderUpdater->_pFileBrowser)->getHSelf(), FB_ADDFILE, (WPARAM)nullptr, (LPARAM)&file2Change);
							oldName = TEXT("");
							break;

						case FILE_ACTION_REMOVED:
							file2Change.push_back(wstrFilename.GetString());
							//thisFolderUpdater->updateTree(dwAction, file2Change);
							::SendMessage((thisFolderUpdater->_pFileBrowser)->getHSelf(), FB_RMFILE, (WPARAM)nullptr, (LPARAM)&file2Change);
							oldName = TEXT("");
							break;

						case FILE_ACTION_MODIFIED:
							oldName = TEXT("");
							break;

						case FILE_ACTION_RENAMED_OLD_NAME:
							oldName = wstrFilename.GetString();
							break;

						case FILE_ACTION_RENAMED_NEW_NAME:
							if (not oldName.empty())
							{
								file2Change.push_back(oldName);
								file2Change.push_back(wstrFilename.GetString());
								//thisFolderUpdater->updateTree(dwAction, file2Change);
								::SendMessage((thisFolderUpdater->_pFileBrowser)->getHSelf(), FB_RNFILE, (WPARAM)nullptr, (LPARAM)&file2Change);
							}
							oldName = TEXT("");
							break;

						default:
							oldName = TEXT("");
							break;
					}
				}
			}
			break;

			case WAIT_IO_COMPLETION:
				// Nothing to do.
				break;
		}
	}

	// Just for sample purposes. The destructor will
	// call Terminate() automatically.
	changes.Terminate();
	//printStr(L"Quit watching thread");
	return EXIT_SUCCESS;
}