/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: sw_acmplwrd.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2006/10/27 22:21:10 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/


#pragma hdrstop



#ifndef _ACMPLWRD_HXX
#include <acmplwrd.hxx>
#endif

#ifndef _HORIORNT_HXX
#include <horiornt.hxx>
#endif

#ifndef _DOC_HXX
#include <doc.hxx>
#endif

#ifndef _ERRHDL_HXX
#include <errhdl.hxx>
#endif

#ifndef _PAGEDESC_HXX
#include <pagedesc.hxx>
#endif
#ifndef _POOLFMT_HXX
#include <poolfmt.hxx>
#endif
#ifndef _HINTS_HXX
#include <hints.hxx>
#endif
#ifndef _OFF_APP_HXX //autogen
#include <bf_offmgr/app.hxx>
#endif
#ifndef _OFAACCFG_HXX //autogen
#include <bf_offmgr/ofaaccfg.hxx>
#endif
#ifndef _MySVXACORR_HXX
#include <bf_svx/svxacorr.hxx>
#endif

#include <vector>
namespace binfilter {
/* -----------------------------05.08.2002 12:43------------------------------

 ---------------------------------------------------------------------------*/
class SwAutoCompleteClient : public SwClient
{
    SwAutoCompleteWord* pAutoCompleteWord;
    SwDoc*              pDoc;
#ifdef DBG_UTIL
    static ULONG nSwAutoCompleteClientCount;
#endif
public:
    SwAutoCompleteClient(SwAutoCompleteWord& rToTell, SwDoc& rSwDoc);
    SwAutoCompleteClient(const SwAutoCompleteClient& rClient);
    ~SwAutoCompleteClient();

    SwAutoCompleteClient& operator=(const SwAutoCompleteClient& rClient);

    virtual void Modify( SfxPoolItem *pOld, SfxPoolItem *pNew);
    const SwDoc& GetDoc(){return *pDoc;}
#ifdef DBG_UTIL
    static ULONG GetElementCount() {return nSwAutoCompleteClientCount;}
#endif
};
/* -----------------------------05.08.2002 12:48------------------------------

 ---------------------------------------------------------------------------*/
typedef std::vector<SwAutoCompleteClient> SwAutoCompleteClientVector;

class SwAutoCompleteWord_Impl
{
    SwAutoCompleteClientVector  aClientVector;
    SwAutoCompleteWord&         rAutoCompleteWord;
public:
    SwAutoCompleteWord_Impl(SwAutoCompleteWord& rParent) :
        rAutoCompleteWord(rParent){}
    void AddDocument(SwDoc& rDoc);
    void RemoveDocument(const SwDoc& rDoc);
};

/* -----------------------------05.08.2002 14:11------------------------------

 ---------------------------------------------------------------------------*/
typedef const SwDoc* SwDocPtr;
typedef std::vector<SwDocPtr> SwDocPtrVector;
class SwAutoCompleteString : public String
{
#ifdef DBG_UTIL
    static ULONG nSwAutoCompleteStringCount;
#endif
    SwDocPtrVector aSourceDocs;
    public:
        SwAutoCompleteString(const String& rStr, xub_StrLen nPos, xub_StrLen nLen);

        ~SwAutoCompleteString();
        void        AddDocument(const SwDoc& rDoc);
        //returns true if last document reference has been removed
        sal_Bool     RemoveDocument(const SwDoc& rDoc);
#ifdef DBG_UTIL
    static ULONG GetElementCount() {return nSwAutoCompleteStringCount;}
#endif
};
#ifdef DBG_UTIL
    ULONG SwAutoCompleteClient::nSwAutoCompleteClientCount = 0;
    ULONG SwAutoCompleteString::nSwAutoCompleteStringCount = 0;
#endif
/* -----------------------------06.08.2002 08:57------------------------------

 ---------------------------------------------------------------------------*/
/*N*/ SwAutoCompleteClient::SwAutoCompleteClient(SwAutoCompleteWord& rToTell, SwDoc& rSwDoc) :
/*N*/         pAutoCompleteWord(&rToTell),
/*N*/         pDoc(&rSwDoc)
/*N*/ {
/*N*/     pDoc->GetPageDescFromPool(RES_POOLPAGE_STANDARD)->Add(this);
/*N*/ #ifdef DBG_UTIL
/*N*/     ++nSwAutoCompleteClientCount;
/*N*/ #endif
/*N*/ }
/* -----------------------------05.08.2002 14:07------------------------------

 ---------------------------------------------------------------------------*/
/*N*/ SwAutoCompleteClient::SwAutoCompleteClient(const SwAutoCompleteClient& rClient) :
/*N*/     pAutoCompleteWord(rClient.pAutoCompleteWord),
/*N*/     pDoc(rClient.pDoc)
/*N*/ {
/*N*/     pDoc->GetPageDescFromPool(RES_POOLPAGE_STANDARD)->Add(this);
/*N*/ #ifdef DBG_UTIL
/*N*/     ++nSwAutoCompleteClientCount;
/*N*/ #endif
/*N*/ }
/* -----------------------------05.08.2002 14:10------------------------------

 ---------------------------------------------------------------------------*/
/*M*/ SwAutoCompleteClient::~SwAutoCompleteClient()
/*M*/ {
/*M*/ #ifdef DBG_UTIL
/*M*/     --nSwAutoCompleteClientCount;
/*M*/ #endif
/*M*/ }
/* -----------------06.03.2003 15:30-----------------

 --------------------------------------------------*/
/*N*/ SwAutoCompleteClient& SwAutoCompleteClient::operator=(const SwAutoCompleteClient& rClient)
/*N*/ {
/*N*/     pAutoCompleteWord = rClient.pAutoCompleteWord;
/*N*/     pDoc = rClient.pDoc;
/*N*/     if(rClient.GetRegisteredIn())
/*N*/         rClient.pRegisteredIn->Add(this);
/*N*/     else if(GetRegisteredIn())
/*N*/         pRegisteredIn->Remove(this); 
/*N*/     return *this;
/*N*/ }
/* -----------------------------05.08.2002 12:49------------------------------

 ---------------------------------------------------------------------------*/
/*M*/ void SwAutoCompleteClient::Modify(SfxPoolItem *pOld, SfxPoolItem *pNew)
/*M*/ {
/*M*/     switch( pOld ? pOld->Which() : 0 )
/*M*/ 	{
/*M*/ 	case RES_REMOVE_UNO_OBJECT:
/*M*/ 	case RES_OBJECTDYING:
/*M*/         if( (void*)GetRegisteredIn() == ((SwPtrMsgPoolItem *)pOld)->pObject )
/*M*/             ((SwModify*)GetRegisteredIn())->Remove(this);
/*M*/                         pAutoCompleteWord->DocumentDying(*pDoc);
/*M*/ 		break;
/*M*/ 
/*M*/     }
/*M*/ }
/* -----------------------------05.08.2002 13:03------------------------------

 ---------------------------------------------------------------------------*/
/*M*/ void SwAutoCompleteWord_Impl::AddDocument(SwDoc& rDoc)
/*M*/ {
/*M*/     SwAutoCompleteClientVector::iterator aIt;
/*M*/     for(aIt = aClientVector.begin(); aIt != aClientVector.end(); aIt++)
/*M*/     {
/*M*/         if(&aIt->GetDoc() == &rDoc)
/*M*/             return;
/*M*/     }
/*M*/     aClientVector.push_back(SwAutoCompleteClient(rAutoCompleteWord, rDoc));
/*M*/ }
/* -----------------------------05.08.2002 14:33------------------------------

 ---------------------------------------------------------------------------*/
/*M*/ void SwAutoCompleteWord_Impl::RemoveDocument(const SwDoc& rDoc)
/*M*/ {
/*M*/     SwAutoCompleteClientVector::iterator aIt;
/*M*/     for(aIt = aClientVector.begin(); aIt != aClientVector.end(); aIt++)
/*M*/     {
/*M*/         if(&aIt->GetDoc() == &rDoc)
/*M*/         {
/*M*/             aClientVector.erase(aIt);
/*M*/             return;
/*M*/         }
/*M*/     }
/*M*/ }
/* -----------------------------06.08.2002 08:54------------------------------

 ---------------------------------------------------------------------------*/
/*M*/ SwAutoCompleteString::SwAutoCompleteString(const String& rStr, xub_StrLen nPos, xub_StrLen nLen) :
/*M*/             String( rStr, nPos, nLen )
/*M*/ {
/*M*/ #ifdef DBG_UTIL
/*M*/     ++nSwAutoCompleteStringCount;
/*M*/ #endif
/*M*/ }
/* -----------------------------05.08.2002 14:22------------------------------

 ---------------------------------------------------------------------------*/
/*M*/ SwAutoCompleteString::~SwAutoCompleteString()
/*M*/ {
/*M*/ #ifdef DBG_UTIL
/*M*/     --nSwAutoCompleteStringCount;
/*M*/ #endif
/*M*/ }
/* -----------------------------05.08.2002 14:17------------------------------

 ---------------------------------------------------------------------------*/
/*M*/ void SwAutoCompleteString::AddDocument(const SwDoc& rDoc)
/*M*/ {
/*M*/     SwDocPtrVector::iterator aIt;
/*M*/     for(aIt = aSourceDocs.begin(); aIt != aSourceDocs.end(); aIt++)
/*M*/     {
/*M*/         if(*aIt == &rDoc)
/*M*/             return;
/*M*/     }
/*M*/     SwDocPtr pNew = &rDoc;
/*M*/     aSourceDocs.push_back(pNew);
/*M*/ }
/* -----------------------------05.08.2002 14:36------------------------------

 ---------------------------------------------------------------------------*/
/*M*/ sal_Bool SwAutoCompleteString::RemoveDocument(const SwDoc& rDoc)
/*M*/ {
/*M*/     SwDocPtrVector::iterator aIt;
/*M*/     for(aIt = aSourceDocs.begin(); aIt != aSourceDocs.end(); aIt++)
/*M*/     {
/*M*/         if(*aIt == &rDoc)
/*M*/         {
/*M*/             aSourceDocs.erase(aIt);
/*M*/             return !aSourceDocs.size();
/*M*/         }
/*M*/     }
/*M*/     return sal_False;
/*M*/ }
/* ---------------------------------------------------------------------------

 ---------------------------------------------------------------------------*/
/*M*/ SwAutoCompleteWord::SwAutoCompleteWord( USHORT nWords, USHORT nMWrdLen )
/*M*/ 	: aWordLst( 0, 255 ), aLRULst( 0, 255 ),
/*M*/     pImpl(new SwAutoCompleteWord_Impl(*this)),
/*M*/ 	nMaxCount( nWords ),
/*M*/ 	nMinWrdLen( nMWrdLen ),
/*M*/ 	bLockWordLst( FALSE )
/*M*/ {
/*M*/ }

/*M*/ SwAutoCompleteWord::~SwAutoCompleteWord()
/*M*/ {
/*M*/     for(USHORT nPos = aWordLst.Count(); nPos; nPos--)
/*M*/     {
/*M*/         SwAutoCompleteString* pCurrent = (SwAutoCompleteString*)aWordLst[ nPos - 1 ];
/*M*/         aWordLst.Remove( nPos - 1 );
/*M*/         delete pCurrent;
/*M*/     }
/*M*/     delete pImpl;
/*M*/ #ifdef DBG_UTIL
/*M*/     ULONG nStrings = SwAutoCompleteString::GetElementCount();
/*M*/     ULONG nClients = SwAutoCompleteClient::GetElementCount();
/*M*/     DBG_ASSERT(!nStrings && !nClients, "AutoComplete: clients or string count mismatch")
/*M*/ #endif
/*M*/ }

/*M*/ BOOL SwAutoCompleteWord::InsertWord( const String& rWord, SwDoc& rDoc )
/*M*/ {
/*M*/     pImpl->AddDocument(rDoc);
/*M*/     BOOL bRet = FALSE;
/*M*/  	xub_StrLen nWrdLen = rWord.Len();
/*M*/ 	while( nWrdLen && '.' == rWord.GetChar( nWrdLen-1 ))
/*M*/ 		--nWrdLen;
/*M*/ 
/*M*/ 	if( !bLockWordLst && nWrdLen >= nMinWrdLen )
/*M*/ 	{
/*M*/         SwAutoCompleteString* pAutoString;
/*M*/         StringPtr pNew = pAutoString = new SwAutoCompleteString( rWord, 0, nWrdLen );
/*M*/         pAutoString->AddDocument(rDoc);
/*M*/ 		USHORT nInsPos;
/*M*/ 		if( aWordLst.Insert( pNew, nInsPos ) )
/*M*/ 		{
/*M*/ 			bRet = TRUE;
/*M*/ 			if( aLRULst.Count() < nMaxCount )
/*M*/ 				aLRULst.Insert( pNew, 0 );
/*M*/ 			else
/*M*/ 			{
/*M*/ 				// der letzte muss entfernt werden
/*M*/ 				// damit der neue vorne Platz hat
/*M*/ 				String* pDel = (String*)aLRULst[ nMaxCount - 1 ];
/*M*/ 
/*M*/ 				void** ppData = (void**)aLRULst.GetData();
/*M*/ 				memmove( ppData+1, ppData, (nMaxCount - 1) * sizeof( void* ));
/*M*/ 				*ppData = pNew;
/*M*/ 
/*M*/ 				aWordLst.Remove( pDel );
/*M*/                 delete (SwAutoCompleteString*)pDel;
/*M*/ 			}
/*M*/ 		}
/*M*/ 		else
/*M*/ 		{
/*M*/             delete (SwAutoCompleteString*)pNew;
/*M*/ 			// dann aber auf jedenfall nach "oben" moven
/*M*/ 			pNew = aWordLst[ nInsPos ];
/*M*/ 
/*M*/             //add the document to the already inserted string
/*M*/             SwAutoCompleteString* pCurrent = (SwAutoCompleteString*)pNew;
/*M*/             pCurrent->AddDocument(rDoc);
/*M*/ 
/*M*/ 			nInsPos = aLRULst.GetPos( (void*)pNew );
/*M*/ 			ASSERT( USHRT_MAX != nInsPos, "String nicht gefunden" );
/*M*/ 			if( nInsPos )
/*M*/ 			{
/*M*/ 				void** ppData = (void**)aLRULst.GetData();
/*M*/ 				memmove( ppData+1, ppData, nInsPos * sizeof( void* ) );
/*M*/ 				*ppData = pNew;
/*M*/ 			}
/*M*/ 		}
/*M*/ 	}
/*M*/ 	return bRet;
/*M*/ }








/* -----------------------------05.08.2002 12:54------------------------------

 ---------------------------------------------------------------------------*/
/*M*/ void SwAutoCompleteWord::DocumentDying(const SwDoc& rDoc)
/*M*/ {
/*M*/     pImpl->RemoveDocument(rDoc);
/*M*/ 
/*M*/     SvxAutoCorrect* pACorr = OFF_APP()->GetAutoCorrConfig()->GetAutoCorrect();
/*M*/     const sal_Bool bDelete = !pACorr->GetSwFlags().bAutoCmpltKeepList;
/*M*/     for(USHORT nPos = aWordLst.Count(); nPos; nPos--)
/*M*/     {
/*M*/         SwAutoCompleteString* pCurrent = (SwAutoCompleteString*)aWordLst[ nPos - 1 ];
/*M*/         if(pCurrent->RemoveDocument(rDoc) && bDelete)
/*M*/         {
/*M*/             aWordLst.Remove( nPos - 1 );
/*M*/             delete pCurrent;
/*M*/         }
/*M*/     }
/*M*/ }

}
