/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"

#include <com/sun/star/util/SearchOptions.hpp>
#include <com/sun/star/util/SearchFlags.hpp>

#define _SVSTDARR_USHORTS
#define _SVSTDARR_ULONGS
#include <svl/svstdarr.hxx>

#include <vcl/svapp.hxx>
#include <vcl/window.hxx>

#include <txatritr.hxx>
#include <fldbas.hxx>
#include <fmtfld.hxx>
#include <txtatr.hxx>
#include <txtfld.hxx>
#include <swcrsr.hxx>
#include <doc.hxx>
#include <IDocumentUndoRedo.hxx>
#include <pamtyp.hxx>
#include <ndtxt.hxx>
#include <swundo.hxx>
#include <UndoInsert.hxx>
#include <breakit.hxx>

#include <docsh.hxx>
#include <PostItMgr.hxx>
#include <viewsh.hxx>

using namespace ::com::sun::star;
using namespace util;

String *ReplaceBackReferences( const SearchOptions& rSearchOpt, SwPaM* pPam );


String& lcl_CleanStr(
    const SwTxtNode& rNd,
    const xub_StrLen nStart,
    xub_StrLen& rEnde,
    SvULongs& rArr,
    String& rRet,
    const bool bRemoveSoftHyphen )
{
    rRet = rNd.GetTxt();
    if( rArr.Count() )
        rArr.Remove( 0, rArr.Count() );

    const SwpHints *pHts = rNd.GetpSwpHints();

    sal_uInt16 n = 0;
    xub_StrLen nSoftHyphen = nStart;
    xub_StrLen nHintStart = STRING_LEN;
    bool bNewHint       = true;
    bool bNewSoftHyphen = true;
    const xub_StrLen nEnd = rEnde;
    SvUShorts aReplaced;

    do
    {
        if ( bNewHint )
            nHintStart = pHts && n < pHts->Count() ?
                         *(*pHts)[n]->GetStart() :
                         STRING_LEN;

        if ( bNewSoftHyphen )
            nSoftHyphen = bRemoveSoftHyphen ?
                          rNd.GetTxt().Search( CHAR_SOFTHYPHEN, nSoftHyphen ) :
                          STRING_LEN;

        bNewHint       = false;
        bNewSoftHyphen = false;

        xub_StrLen nStt = 0;

        // Check if next stop is a hint.
        if ( STRING_LEN != nHintStart && nHintStart < nSoftHyphen && nHintStart < nEnd )
        {
            nStt = nHintStart;
            bNewHint = true;
        }
        // Check if next stop is a soft hyphen.
        else if ( STRING_LEN != nSoftHyphen && nSoftHyphen < nHintStart && nSoftHyphen < nEnd )
        {
            nStt = nSoftHyphen;
            bNewSoftHyphen = true;
        }
        // If nSoftHyphen == nHintStart, the current hint *must* be a hint with an end.
        else if ( STRING_LEN != nSoftHyphen && nSoftHyphen == nHintStart )
        {
            nStt = nSoftHyphen;
            bNewHint = true;
            bNewSoftHyphen = true;
        }
        else
            break;

        const xub_StrLen nAkt = nStt - rArr.Count();

        if ( bNewHint )
        {
            const SwTxtAttr* pHt = (*pHts)[n];
            if ( pHt->HasDummyChar() && (nStt >= nStart) )
            {
                switch( pHt->Which() )
                {
                case RES_TXTATR_FLYCNT:
                case RES_TXTATR_FTN:
                case RES_TXTATR_FIELD:
                case RES_TXTATR_ANNOTATION:
                case RES_TXTATR_REFMARK:
                case RES_TXTATR_TOXMARK:
                case RES_TXTATR_META:
                case RES_TXTATR_METAFIELD:
                    {
                        const bool bEmpty =
                            ( pHt->Which() != RES_TXTATR_FIELD
                              && pHt->Which() != RES_TXTATR_ANNOTATION )
                            || !(static_cast<SwTxtFld const*>(pHt)->GetFmtFld().GetField()->ExpandField(true).Len());
                        if ( bEmpty && nStart == nAkt )
                        {
                            rArr.Insert( nAkt, rArr.Count() );
                            --rEnde;
                            rRet.Erase( nAkt, 1 );
                        }
                        else
                        {
                            if ( bEmpty )
                                aReplaced.Insert( nAkt, aReplaced.Count() );
                            rRet.SetChar( nAkt, '\x7f' );
                        }
                    }
                    break;
                default:
                    ASSERT( false, "unknown case in lcl_CleanStr" )
                    break;
                }
            }
            ++n;
        }

        if ( bNewSoftHyphen )
        {
            rArr.Insert( nAkt, rArr.Count() );
            --rEnde;
            rRet.Erase( nAkt, 1 );
            ++nSoftHyphen;
        }
    }
    while ( true );

    for( sal_uInt16 i = aReplaced.Count(); i; )
    {
        const xub_StrLen nTmp = aReplaced[ --i ];
        if( nTmp == rRet.Len() - 1 )
        {
            rRet.Erase( nTmp );
            rArr.Insert( nTmp, rArr.Count() );
            --rEnde;
        }
    }

    return rRet;
}

// skip all non SwPostIts inside the array
xub_StrLen GetPostIt(xub_StrLen aCount,const SwpHints *pHts)
{
    xub_StrLen aIndex = 0;
    while (aCount)
    {
        for (xub_StrLen i = 0; i <pHts->Count();i++)
        {
            aIndex++;
            const SwTxtAttr* pTxtAttr = (*pHts)[i];
            if ( pTxtAttr->Which() == RES_TXTATR_ANNOTATION )
            {
                aCount--;
                if (!aCount)
                    break;
            }
        }
    }
    // throw away all following non postits
    for (xub_StrLen i = aIndex; i <pHts->Count();i++)
    {
        const SwTxtAttr* pTxtAttr = (*pHts)[i];
        if ( pTxtAttr->Which() == RES_TXTATR_ANNOTATION )
            break;
        else
            aIndex++;
    }
    return aIndex;
}

sal_uInt8 SwPaM::Find( const SearchOptions& rSearchOpt, sal_Bool bSearchInNotes , utl::TextSearch& rSTxt,
					SwMoveFn fnMove, const SwPaM * pRegion,
					sal_Bool bInReadOnly )
{
	if( !rSearchOpt.searchString.getLength() )
		return sal_False;

	SwPaM* pPam = MakeRegion( fnMove, pRegion );
	sal_Bool bSrchForward = fnMove == fnMoveForward;
	SwNodeIndex& rNdIdx = pPam->GetPoint()->nNode;
	SwIndex& rCntntIdx = pPam->GetPoint()->nContent;

	// Wenn am Anfang/Ende, aus dem Node moven
	// beim leeren Node nicht weiter
	if( bSrchForward
		? ( rCntntIdx.GetIndex() == pPam->GetCntntNode()->Len() &&
			rCntntIdx.GetIndex() )
		: !rCntntIdx.GetIndex() && pPam->GetCntntNode()->Len() )
	{
		if( !(*fnMove->fnNds)( &rNdIdx, sal_False ))
        {
			delete pPam;
			return sal_False;
		}
		SwCntntNode *pNd = rNdIdx.GetNode().GetCntntNode();
		xub_StrLen nTmpPos = bSrchForward ? 0 : pNd->Len();
		rCntntIdx.Assign( pNd, nTmpPos );
	}

	/*
	 * Ist bFound == sal_True, dann wurde der String gefunden und in
	 * nStart und nEnde steht der gefundenen String
	 */
	sal_Bool bFound = sal_False;
	/*
	 * StartPostion im Text oder Anfangsposition
	 */
	sal_Bool bFirst = sal_True;
	SwCntntNode * pNode;
	//testarea
	//String sCleanStr;
	//SvULongs aFltArr;
	//const SwNode* pSttNd = &rNdIdx.GetNode();

	xub_StrLen nStart, nEnde, nTxtLen;

	sal_Bool bRegSearch = SearchAlgorithms_REGEXP == rSearchOpt.algorithmType;
	sal_Bool bChkEmptyPara = bRegSearch && 2 == rSearchOpt.searchString.getLength() &&
						( !rSearchOpt.searchString.compareToAscii( "^$" ) ||
						  !rSearchOpt.searchString.compareToAscii( "$^" ) );
    sal_Bool bChkParaEnd = bRegSearch && 1 == rSearchOpt.searchString.getLength() &&
                      !rSearchOpt.searchString.compareToAscii( "$" );

//    LanguageType eLastLang = 0;
	while( 0 != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ) ))
	{
		if( pNode->IsTxtNode() )
		{
			nTxtLen = ((SwTxtNode*)pNode)->GetTxt().Len();
			if( rNdIdx == pPam->GetMark()->nNode )
				nEnde = pPam->GetMark()->nContent.GetIndex();
			else
				nEnde = bSrchForward ? nTxtLen : 0;
			nStart = rCntntIdx.GetIndex();

			/* #i80135# */
			// if there are SwPostItFields inside our current node text, we split the text into seperate pieces
			// and search for text inside the pieces as well as inside the fields
			const SwpHints *pHts = ((SwTxtNode*)pNode)->GetpSwpHints();

			// count postitfields by looping over all fields
			xub_StrLen aNumberPostits = 0;
			xub_StrLen aIgnore = 0;
			if (pHts && bSearchInNotes)
			{
				if (!bSrchForward)
				{
					xub_StrLen swap = nEnde;
					nEnde = nStart;
					nStart = swap;
				}

                for (xub_StrLen i = 0; i <pHts->Count();i++)
                {
                    const xub_StrLen aPos = *(*pHts)[i]->GetStart();
                    const SwTxtAttr* pTxtAttr = (*pHts)[i];
                    if ( pTxtAttr->Which()==RES_TXTATR_ANNOTATION )
                    {
                        if ( (aPos >= nStart) && (aPos <= nEnde) )
                            aNumberPostits++;
                        else
                        {
                            if (bSrchForward)
                                aIgnore++;
                        }
                    }
                }

				if (!bSrchForward)
				{
					xub_StrLen swap = nEnde;
					nEnde = nStart;
					nStart = swap;
				}

			}

            SwDocShell *const pDocShell = pNode->GetDoc()->GetDocShell();
            ViewShell *const pWrtShell = (pDocShell) ? (ViewShell*)(pDocShell->GetWrtShell()) : 0;
            SwPostItMgr *const pPostItMgr = (pWrtShell) ? pWrtShell->GetPostItMgr() : 0;

			xub_StrLen aStart = 0;
			// do we need to finish a note?
            if (pPostItMgr && pPostItMgr->HasActiveSidebarWin())
			{
				if (bSearchInNotes)
				{
					if (bSrchForward)
						aStart++;
					else
					{
						if (aNumberPostits)
							--aNumberPostits;
					}
					//search inside and finsih and put focus back into the doc
					if (pPostItMgr->FinishSearchReplace(rSearchOpt,bSrchForward))
					{
						bFound = true ;
						break;
					}
				}
				else
				{
                    pPostItMgr->SetActiveSidebarWin(0);
				}
			}

			if (aNumberPostits)
			{
				// now we have to split
				xub_StrLen nStartInside = 0;
				xub_StrLen nEndeInside = 0;
				sal_Int16 aLoop= bSrchForward ? aStart : aNumberPostits;

				while ( (aLoop>=0) && (aLoop<=aNumberPostits))
				{
					if (bSrchForward)
					{
						nStartInside =  aLoop==0 ? nStart : *(*pHts)[GetPostIt(aLoop+aIgnore-1,pHts)]->GetStart()+1;
						nEndeInside = aLoop==aNumberPostits? nEnde : *(*pHts)[GetPostIt(aLoop+aIgnore,pHts)]->GetStart();
						nTxtLen = nEndeInside-nStartInside;
					}
					else
					{
						nStartInside =  aLoop==aNumberPostits ? nStart : *(*pHts)[GetPostIt(aLoop+aIgnore,pHts)]->GetStart();
						nEndeInside = aLoop==0 ? nEnde : *(*pHts)[GetPostIt(aLoop+aIgnore-1,pHts)]->GetStart()+1;
						nTxtLen = nStartInside-nEndeInside;
					}
					// search inside the text between a note
					bFound = DoSearch(rSearchOpt,rSTxt,fnMove,bSrchForward,bRegSearch,bChkEmptyPara,bChkParaEnd,
								nStartInside,nEndeInside,nTxtLen, pNode,pPam);
					if (bFound)
						break;
					else
					{
						// we should now be right in front of a note, search inside
						if ( (bSrchForward && (GetPostIt(aLoop + aIgnore,pHts) < pHts->Count()) ) || ( !bSrchForward && (aLoop!=0) ))
						{
							const SwTxtAttr* pTxtAttr = bSrchForward ?  (*pHts)[GetPostIt(aLoop+aIgnore,pHts)] : (*pHts)[GetPostIt(aLoop+aIgnore-1,pHts)];
							if ( pPostItMgr && pPostItMgr->SearchReplace(((SwTxtFld*)pTxtAttr)->GetFmtFld(),rSearchOpt,bSrchForward) )
							{
								bFound = true ;
								break;
							}
						}
					}
					aLoop = bSrchForward ? aLoop+1 : aLoop-1;
				}
			}
			else
			{
				// if there is no SwPostItField inside or searching inside notes is disabled, we search the whole length just like before
				bFound = DoSearch(rSearchOpt,rSTxt,fnMove,bSrchForward,bRegSearch,bChkEmptyPara,bChkParaEnd,
							nStart,nEnde,nTxtLen, pNode,pPam);
			}
			if (bFound)
				break;
		}
	}
	delete pPam;
	return bFound;
}

bool SwPaM::DoSearch( const SearchOptions& rSearchOpt, utl::TextSearch& rSTxt,
					SwMoveFn fnMove,
					sal_Bool bSrchForward, sal_Bool bRegSearch, sal_Bool bChkEmptyPara, sal_Bool bChkParaEnd,
					xub_StrLen &nStart, xub_StrLen &nEnde, xub_StrLen nTxtLen,SwNode* pNode, SwPaM* pPam)
{
	bool bFound = false;
	SwNodeIndex& rNdIdx = pPam->GetPoint()->nNode;
	const SwNode* pSttNd = &rNdIdx.GetNode();
	String sCleanStr;
	SvULongs aFltArr;
	LanguageType eLastLang = 0;
	// if the search string contains a soft hypen, we don't strip them from the text:
	bool bRemoveSoftHyphens = true;
    if ( bRegSearch )
    {
        const rtl::OUString a00AD( rtl::OUString::createFromAscii( "\\x00AD" ) );
        if ( -1 != rSearchOpt.searchString.indexOf( a00AD ) )
             bRemoveSoftHyphens = false;
    }
    else
    {
        if ( 1 == rSearchOpt.searchString.getLength() &&
             CHAR_SOFTHYPHEN == rSearchOpt.searchString.toChar() )
             bRemoveSoftHyphens = false;
    }

    if( bSrchForward )
		lcl_CleanStr( *(SwTxtNode*)pNode, nStart, nEnde,
						aFltArr, sCleanStr, bRemoveSoftHyphens );
	else
		lcl_CleanStr( *(SwTxtNode*)pNode, nEnde, nStart,
						aFltArr, sCleanStr, bRemoveSoftHyphens );

    SwScriptIterator* pScriptIter = 0;
    sal_uInt16 nSearchScript = 0;
    sal_uInt16 nCurrScript = 0;

    if ( SearchAlgorithms_APPROXIMATE == rSearchOpt.algorithmType &&
         pBreakIt->GetBreakIter().is() )
    {
        pScriptIter = new SwScriptIterator( sCleanStr, nStart, bSrchForward );
        nSearchScript = pBreakIt->GetRealScriptOfText( rSearchOpt.searchString, 0 );
    }

    xub_StrLen nStringEnd = nEnde;
    while ( (bSrchForward && nStart < nStringEnd) ||
            (! bSrchForward && nStart > nStringEnd) )
    {
        // SearchAlgorithms_APPROXIMATE works on a per word base
        // so we have to provide the text searcher with the correct
        // locale, because it uses the breakiterator
        if ( pScriptIter )
        {
            nEnde = pScriptIter->GetScriptChgPos();
            nCurrScript = pScriptIter->GetCurrScript();
            if ( nSearchScript == nCurrScript )
            {
                const LanguageType eCurrLang =
                        ((SwTxtNode*)pNode)->GetLang( bSrchForward ?
                                                      nStart :
                                                      nEnde );

                if ( eCurrLang != eLastLang )
                {
                    const lang::Locale aLocale(
                            pBreakIt->GetLocale( eCurrLang ) );
                    rSTxt.SetLocale( rSearchOpt, aLocale );
                    eLastLang = eCurrLang;
                }
            }
            pScriptIter->Next();
        }

        if( nSearchScript == nCurrScript &&
			(rSTxt.*fnMove->fnSearch)( sCleanStr, &nStart, &nEnde, 0 ))
        {
            // setze den Bereich richtig
            *GetPoint() = *pPam->GetPoint();
            SetMark();

            // Start und Ende wieder korrigieren !!
            if( aFltArr.Count() )
            {
                xub_StrLen n, nNew;
                // bei Rueckwaertssuche die Positionen temp. vertauschen
                if( !bSrchForward ) { n = nStart; nStart = nEnde; nEnde = n; }

                for( n = 0, nNew = nStart;
                    n < aFltArr.Count() && aFltArr[ n ] <= nStart;
                    ++n, ++nNew )
                    ;
                nStart = nNew;
                for( n = 0, nNew = nEnde;
                    n < aFltArr.Count() && aFltArr[ n ] < nEnde;
                    ++n, ++nNew )
                    ;
                nEnde = nNew;

                // bei Rueckwaertssuche die Positionen temp. vertauschen
                if( !bSrchForward ) { n = nStart; nStart = nEnde; nEnde = n; }
            }
            GetMark()->nContent = nStart;       // Startposition setzen
            GetPoint()->nContent = nEnde;

            if( !bSrchForward )         // rueckwaerts Suche?
                Exchange();             // Point und Mark tauschen
            bFound = sal_True;
            break;
        }

		nStart = nEnde;
    } // end of script while

    delete pScriptIter;

    if ( bFound )
        return true;
    else if( ( bChkEmptyPara && !nStart && !nTxtLen ) || bChkParaEnd )
    {
        *GetPoint() = *pPam->GetPoint();
        GetPoint()->nContent = bChkParaEnd ? nTxtLen : 0;
        SetMark();
        if( (bSrchForward || pSttNd != &rNdIdx.GetNode()) &&
            Move( fnMoveForward, fnGoCntnt ) &&
            (!bSrchForward || pSttNd != &GetPoint()->nNode.GetNode()) &&
            1 == Abs( (int)( GetPoint()->nNode.GetIndex() -
                            GetMark()->nNode.GetIndex()) ) )
        {
            if( !bSrchForward )         // rueckwaerts Suche?
                Exchange();             // Point und Mark tauschen
            //bFound = sal_True;
            //break;
			return true;
        }
	}
	return bFound;
}

// Parameter fuers Suchen und Ersetzen von Text
struct SwFindParaText : public SwFindParas
{
	const SearchOptions& rSearchOpt;
	SwCursor& rCursor;
	utl::TextSearch aSTxt;
	sal_Bool bReplace;
	sal_Bool bSearchInNotes;

	SwFindParaText( const SearchOptions& rOpt, sal_Bool bSearchNotes, int bRepl, SwCursor& rCrsr )
		: rSearchOpt( rOpt ), rCursor( rCrsr ), aSTxt( rOpt ), bReplace( 0 != bRepl ), bSearchInNotes( bSearchNotes )
	{}
	virtual int Find( SwPaM* , SwMoveFn , const SwPaM*, sal_Bool bInReadOnly );
	virtual int IsReplaceMode() const;
    virtual ~SwFindParaText();
};

SwFindParaText::~SwFindParaText()
{
}

int SwFindParaText::Find( SwPaM* pCrsr, SwMoveFn fnMove,
							const SwPaM* pRegion, sal_Bool bInReadOnly )
{
	if( bInReadOnly && bReplace )
		bInReadOnly = sal_False;

	sal_Bool bFnd = (sal_Bool)pCrsr->Find( rSearchOpt, bSearchInNotes, aSTxt, fnMove, pRegion, bInReadOnly );

	/*	 #i80135# if we found something in a note, Mark and Point is the same
	if( bFnd && *pCrsr->GetMark() == *pCrsr->GetPoint() )
		return FIND_NOT_FOUND;
	*/

	if( bFnd && bReplace )			// String ersetzen ??
	{
		// Replace-Methode vom SwDoc benutzen
        const bool bRegExp(SearchAlgorithms_REGEXP == rSearchOpt.algorithmType);
		SwIndex& rSttCntIdx = pCrsr->Start()->nContent;
		xub_StrLen nSttCnt = rSttCntIdx.GetIndex();
		// damit die Region auch verschoben wird, in den Shell-Cursr-Ring
		// mit aufnehmen !!
		Ring *pPrev(0);
		if( bRegExp )
		{
			pPrev = pRegion->GetPrev();
			((Ring*)pRegion)->MoveRingTo( &rCursor );
		}

        ::std::auto_ptr<String> pRepl( (bRegExp)
                ? ReplaceBackReferences( rSearchOpt, pCrsr ) : 0 );
        rCursor.GetDoc()->ReplaceRange( *pCrsr,
            (pRepl.get()) ? *pRepl : String(rSearchOpt.replaceString),
            bRegExp );
		rCursor.SaveTblBoxCntnt( pCrsr->GetPoint() );

		if( bRegExp )
		{
			// und die Region wieder herausnehmen:
			Ring *p, *pNext = (Ring*)pRegion;
			do {
				p = pNext;
				pNext = p->GetNext();
				p->MoveTo( (Ring*)pRegion );
			} while( p != pPrev );
		}
		pCrsr->Start()->nContent = nSttCnt;
		return FIND_NO_RING;
	}
	return bFnd ? FIND_FOUND : FIND_NOT_FOUND;
}


int SwFindParaText::IsReplaceMode() const
{
	return bReplace;
}


sal_uLong SwCursor::Find( const SearchOptions& rSearchOpt, sal_Bool bSearchInNotes,
						SwDocPositions nStart, SwDocPositions nEnde,
                        sal_Bool& bCancel,
						FindRanges eFndRngs, int bReplace )
{
	// OLE-Benachrichtigung abschalten !!
	SwDoc* pDoc = GetDoc();
	Link aLnk( pDoc->GetOle2Link() );
	pDoc->SetOle2Link( Link() );

    bool const bStartUndo = pDoc->GetIDocumentUndoRedo().DoesUndo() && bReplace;
    if (bStartUndo)
    {
        pDoc->GetIDocumentUndoRedo().StartUndo( UNDO_REPLACE, NULL );
    }

	sal_Bool bSearchSel = 0 != (rSearchOpt.searchFlag & SearchFlags::REG_NOT_BEGINOFLINE);
	if( bSearchSel )
		eFndRngs = (FindRanges)(eFndRngs | FND_IN_SEL);
	SwFindParaText aSwFindParaText( rSearchOpt, bSearchInNotes, bReplace, *this );
    sal_uLong nRet = FindAll( aSwFindParaText, nStart, nEnde, eFndRngs, bCancel );
	pDoc->SetOle2Link( aLnk );
	if( nRet && bReplace )
		pDoc->SetModified();

    if (bStartUndo)
    {
        SwRewriter rewriter(MakeUndoReplaceRewriter(
                nRet, rSearchOpt.searchString, rSearchOpt.replaceString));
        pDoc->GetIDocumentUndoRedo().EndUndo( UNDO_REPLACE, & rewriter );
    }
	return nRet;
}

String *ReplaceBackReferences( const SearchOptions& rSearchOpt, SwPaM* pPam )
{
    String *pRet = 0;
    if( pPam && pPam->HasMark() &&
        SearchAlgorithms_REGEXP == rSearchOpt.algorithmType )
    {
        const SwCntntNode* pTxtNode = pPam->GetCntntNode( sal_True );
        if( pTxtNode && pTxtNode->IsTxtNode() && pTxtNode == pPam->GetCntntNode( sal_False ) )
        {
            utl::TextSearch aSTxt( rSearchOpt );
            const String& rStr = static_cast<const SwTxtNode*>(pTxtNode)->GetTxt();
			xub_StrLen nStart = pPam->Start()->nContent.GetIndex();
			xub_StrLen nEnd = pPam->End()->nContent.GetIndex();
            SearchResult aResult;
            if( aSTxt.SearchFrwrd( rStr, &nStart, &nEnd, &aResult ) )
            {
                String aReplaceStr( rSearchOpt.replaceString );
                aSTxt.ReplaceBackReferences( aReplaceStr, rStr, aResult );
                pRet = new String( aReplaceStr );
            }
        }
    }
    return pRet;
}