/*
* Copyright (c) 2002-2007 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*     Phonebook 2 search pane filter. This acts as a wrapper to the FindBox in
*     NameslistView. Info needs to be passed to this filter before the FindBox
*
*/

// INCLUDE FILES
#include "CPbk2PredictiveSearchFilter.h"

// Phonebook 2
#include <Phonebook2PrivateCRKeys.h>
#include <MPbk2ContactNameFormatter.h>
#include <MPbk2ContactNameFormatter2.h>
#include <MVPbkViewContact.h>
#include "MPbk2FilteredViewStack.h"
#include "cpbk2predictiveviewstack.h"
#include "TPbk2FindTextUtil.h"
// Debugging headers
#include <Pbk2Debug.h>

//Avkon System includes
#include <aknsfld.h>
#include <txtetext.h>
#include <eikenv.h>
#include <eikappui.h>
#include <eikcoctl.rsg>
#include <eikedwin.h>
#include <featmgr.h>
#include <AknFepInternalCRKeys.h>
#include <txtglobl.h>

//PS
#include <CPsRequestHandler.h>


/// Unnamed namespace for local definitions
namespace {

_LIT(KQuestionMark, "?");
_LIT(KspaceStr, " ");
const TInt Kspace = ' ';
const TInt Kquestion = '?';
const TInt KDefaultListFormatting =
        MPbk2ContactNameFormatter::EUseSeparator |
        MPbk2ContactNameFormatter::EPreserveLeadingSpaces;

} /// namespace

NONSHARABLE_CLASS( CRunAsynch ): public CActive
    {
    public:
        static CRunAsynch* NewL(CPbk2PredictiveSearchFilter* aParent);
        void ReDraw();
        
        ~CRunAsynch();
    private: 
        CRunAsynch(CPbk2PredictiveSearchFilter* aParent);
        
        void RunL();
        void DoCancel();
        
    private: //Data
        CPbk2PredictiveSearchFilter* iParent;
    };

// --------------------------------------------------------------------------
// CRunAsynch::CRunAsynch
// --------------------------------------------------------------------------
//
CRunAsynch::CRunAsynch(CPbk2PredictiveSearchFilter* aParent) :
    CActive(EPriorityIdle), 
    iParent(aParent) 
    {
    CActiveScheduler::Add(this);
    }

// --------------------------------------------------------------------------
// CRunAsynch::~CRunAsynch
// --------------------------------------------------------------------------
//
inline CRunAsynch::~CRunAsynch()
    {
    Cancel();
    }

// --------------------------------------------------------------------------
// CRunAsynch::NewL
// --------------------------------------------------------------------------
//
CRunAsynch* CRunAsynch::NewL(CPbk2PredictiveSearchFilter* aParent)
    {
    CRunAsynch* self = new ( ELeave ) CRunAsynch(aParent);
    return self;
    }

// --------------------------------------------------------------------------
// CRunAsynch::Redraw
// --------------------------------------------------------------------------
//
void CRunAsynch::ReDraw()
    {
    if(!IsActive())
        {
        TRequestStatus* status=&iStatus;
        User::RequestComplete(status, KErrNone);
        SetActive();
        }
    }

// --------------------------------------------------------------------------
// CRunAsynch::DoCancel
// --------------------------------------------------------------------------
//
void CRunAsynch::DoCancel()
    {
    
    }

// --------------------------------------------------------------------------
// CRunAsynch::RunL
// --------------------------------------------------------------------------
//
void CRunAsynch::RunL()
    {
    iParent->ReDrawL();
    }

// --------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::CPbk2PredictiveSearchFilter
// --------------------------------------------------------------------------
//
inline CPbk2PredictiveSearchFilter::CPbk2PredictiveSearchFilter() :
    iFiltering(EFalse),
    iAppUi( *(iEikonEnv->EikAppUi()) ),
    iPredictiveSearchEnabled(EFalse)
    {
    }

// --------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::~CPbk2PredictiveSearchFilter
// --------------------------------------------------------------------------
//
CPbk2PredictiveSearchFilter::~CPbk2PredictiveSearchFilter()
    {    
    RemoveFromViewStack();    
    iPredictiveTextEntered.Close();    
    delete iSearchText;
    delete iRunAsynch;
    // UnInitialize feature manager
    FeatureManager::UnInitializeLib();
    }

// --------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::NewL
// --------------------------------------------------------------------------
//
CPbk2PredictiveSearchFilter* CPbk2PredictiveSearchFilter::NewL()
    {
    CPbk2PredictiveSearchFilter* self =
        new ( ELeave ) CPbk2PredictiveSearchFilter();
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }

// --------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::ConstructL
// --------------------------------------------------------------------------
//
void CPbk2PredictiveSearchFilter::ConstructL()
    {
    // Initialize feature manager
    FeatureManager::InitializeLibL();

    if(FeatureManager::FeatureSupported(KFeatureIdFfContactsPredictiveSearch))
        {
        //The implementation algorithm suppose that only this class is
        //responsible to change or return PCS input mode therefore we can use this value
        CRepository* repository = CRepository::NewLC(TUid::Uid(KCRUidPhonebook));    
        repository->Get( KPhonebookPredictiveSearchEnablerFlags, iPredictiveSearchEnabled );      
        CleanupStack::PopAndDestroy(); //repository
        
        }
 
    iRunAsynch = CRunAsynch::NewL(this);
    }

// --------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::FilterL
// --------------------------------------------------------------------------
//
void CPbk2PredictiveSearchFilter::FilterL( 
        const TKeyEvent& aKeyEvent, 
        TEventCode aType,
        CAknSearchField* aSearchField )
    {    
    
    if( aType == EEventKeyDown && aKeyEvent.iCode == EKeyNull )
        {        
        if( IsPredictiveActivated() && aSearchField )
            {
            iFiltering = ETrue;
            
            // Before single click it does nothing, but between multitap 
            // clicks it breaks Fep transaction.
            // It removes multitap. 
            RBuf searchText;
            searchText.CreateL( aSearchField->TextLength() );
            CleanupClosePushL( searchText );
            aSearchField->GetSearchText( searchText );       
            aSearchField->SetSearchTextL( searchText );
            aSearchField->SetFocus( ETrue, EDrawNow );
            CleanupStack::PopAndDestroy( &searchText );
            iFiltering = EFalse;  
            }
        }
    }

// --------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::IsFiltering
// --------------------------------------------------------------------------
//
TBool CPbk2PredictiveSearchFilter::IsFiltering()
    {
    return iFiltering;
    }

// --------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::StartFindPaneInlineEditL
// --------------------------------------------------------------------------
//
TBool CPbk2PredictiveSearchFilter::StartFindPaneInlineEditL( TDes& aFindPaneText )
    {
    //Level 1 : Check if virtual keyboard was used
    if( !iVKbUsed && iSearchField && iSearchText->Length() < aFindPaneText.Length() &&
         (iSearchField->Editor().AknEdwinFlags() & EAknEditorFlagTouchInputModeOpened) )
        {
        iVKbUsed = ETrue;
        }
    //Level 2 : Check if predictive serach is activated or not
    //if predictive serach is not activated, avoid performing
    //any operation on the same string in FindPane
    if ( !IsPredictiveActivated() )
        {
        return ETrue;
        }
    TPtr searchPtr (iSearchText->Des()); //Text which holds the FindPane display text    
    TInt findPaneTxtLen = aFindPaneText.Length(); 
        
    //Level 3: If search text filtering is ongoing, avoid performing
    //any operation on the same string in FindPane 
    if (iFiltering )
        {
        return EFalse;
        }    
    
    //Level 4: HandleControlEventL wil be called more than once, avoid performing
    //any operation on the same string in FindPane 
    if (aFindPaneText.Compare(searchPtr) == 0)//HandleControlEventL wil be called more than once, avoid performing
                                          //any operation on the same string in FindPane
        {            
        return EFalse;
        }
    
    //Level 5: If editor is locked, avoid performing
    //any operation on the same string in FindPane 
    if ( iLocked ) 
        { 
        if( aFindPaneText.Length() > 1 && aFindPaneText[aFindPaneText.Length() - 2] == Kquestion )
            {
            TBuf <KSearchFieldLength> findPaneTxtCopy;
            findPaneTxtCopy.SetLength(0);            
            findPaneTxtCopy.Copy(aFindPaneText);
            findPaneTxtCopy.Replace(aFindPaneText.Length() - 1, 1, KspaceStr);            
            SetSearchBoxTextL(findPaneTxtCopy, findPaneTxtCopy.Length() - 1);
            iRemoveSpace = ETrue;
            }
        return EFalse;
        }
    
    TBool isCharRemoved (EFalse); //To know whether its a backspace char or not. If backspace nothing needs to be done
    if ( findPaneTxtLen )
        {    
        TInt len = iPredictiveTextEntered.Length();
        //Append the newly entered char into our predictive search query string
        if ( findPaneTxtLen >= len )
            {
            if ( iLongKeyPress )
                {
                //If it was a long key press
                //Normally during Long Key Press, there are 2 actions that happen
                //first the char is displayed and then followed by that the number
                //eg. the numeric key pad "2" denotes "abc2...", when u long press 2, 
                //first the char 'a' is shown
                //and then followed by that it shows '2'. 
                //We get 2 events one wih 'a' and next with '2'
                //So, we need to send first 'a' to the predictive search
                //and then followed by this '2'.
                //So During this case, the Fep transaction is broken because of us
                //and thus the FEP will send the event with any of the strings
                //' 2' or '*2'(* - denotes the matched char for the 1stquery a)
                //If Long Key Press, we remove the previous char and use the new one
                //for our search, otherwise we might end up sending a search req for 
                //as 'a2' if that would have been a long key press on mumeric keypad 2.
                iPredictiveTextEntered.Delete( len - 1, 1 );
                iLongKeyPress = EFalse;
                }
            if ( findPaneTxtLen == len )
                {
                len = len - 1;
                isCharRemoved = ETrue;
                }
            //Append the newly entered char to our predictive search query. 
            iPredictiveTextEntered.Append( aFindPaneText.Right(findPaneTxtLen - len) );
            }
        else
            {
            //Some chars have been removed so delete the app char from our predictive search query            
            iPredictiveTextEntered.Delete( findPaneTxtLen, iPredictiveTextEntered.Length() - findPaneTxtLen );
            isCharRemoved = ETrue;
            }
        
        TBuf <KSearchFieldLength> findPaneTxtCopy;
        findPaneTxtCopy.SetLength(0);            
        findPaneTxtCopy.Copy(aFindPaneText);
                    
        //Check whether a new text was entered    
        //Ignore if " " has been entered
        if ( !isCharRemoved )
            {
            //New text was entered
            //Now we cannot render this text untill we find the match char from the Predictive search engine
            //Hence remove the newly entered char and diplay the findpane
            //once we get the callback from predictive search with the matched char
            //then we can render that char as the newly entered char
            findPaneTxtCopy.Replace(aFindPaneText.Length()-1, 1, KspaceStr);            
            SetSearchBoxTextL(findPaneTxtCopy, findPaneTxtCopy.Length());
            iLongKeyPress = ETrue;
            }
        
        searchPtr.Copy( findPaneTxtCopy );
        aFindPaneText.Copy( iPredictiveTextEntered );
        }
    else
        {
        ResetL();
        }
       
    return ETrue;
    }   
       
// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::IsPredictiveActivated
// ---------------------------------------------------------------------------
//
TBool CPbk2PredictiveSearchFilter::IsPredictiveActivated() const
    {    
    return iPredictiveSearchEnabled && !iVKbUsed;
    }


// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::HandlePSResults
// ---------------------------------------------------------------------------
//
void CPbk2PredictiveSearchFilter::HandlePSNoMatchL( const TDesC& /*aQueryString*/, const TDesC& aMatchSeq )
    {
    //we have received our Predictive Search Result
    //aMatchSeq contains the string that needs to be displayed on the FindPane
    //now we can render the string on the findPane
    if ( !IsPredictiveActivated() )
        {
        return;
        }
    
    CommitFindPaneTextL( aMatchSeq );
    }

// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::LookupL
// ---------------------------------------------------------------------------
//
void CPbk2PredictiveSearchFilter::LookupL( 
        const MVPbkViewContact& aContact, CPbk2PredictiveViewStack& aView, 
        MPbk2ContactNameFormatter& aNameFormatter, TDes& aMatchSeqChr )
    {
    HBufC* name(NULL);
    if( FeatureManager::FeatureSupported(KFeatureIdFfContactsCompanyNames) )
    {
        MPbk2ContactNameFormatter2* nameformatterExtension =
            reinterpret_cast<MPbk2ContactNameFormatter2*>(aNameFormatter.
                    ContactNameFormatterExtension( MPbk2ContactNameFormatterExtension2Uid ) );
        name = nameformatterExtension->GetContactTitleWithCompanyNameL(aContact.Fields(),
                KDefaultListFormatting);
         }
     else
         {
         // Append name
         name =
         aNameFormatter.GetContactTitleL(aContact.Fields(),
             KDefaultListFormatting);
         }
    CleanupStack::PushL( name );         
              
    TPtr namePtr = name->Des();
    TRAP_IGNORE (
        if ( IsMirroredInputLang() )
            {
            // temporary solution
            // PCS LookupLmethod doesn't work correctly for
            // bidirectional languages
            RArray<TPsMatchLocation> searchMatches; 
            
            aView.GetMatchingPartsL(*name, searchMatches);
            
            TInt matchCount = searchMatches.Count();
            if( matchCount )
                {
                for (TInt index1=0; index1<matchCount; index1++)
                    {
                    TPsMatchLocation& location = searchMatches[index1];                    
                    aMatchSeqChr.Append(namePtr.Mid(location.index, location.length));
                    aMatchSeqChr.Append(Kspace);
                    }
                aMatchSeqChr.LowerCase();
                aMatchSeqChr.Trim();
                }
            searchMatches.Close();
            }
        else
            {
            CPsQuery* lastQuery = const_cast<CPsQuery*> (aView.LastPCSQuery());
            CPSRequestHandler* psHandler = aView.PSHandler();
            if ( psHandler && lastQuery )
                {
                psHandler->LookupMatchL( *lastQuery, *name, aMatchSeqChr );
                }
            }
       );
        
    CleanupStack::PopAndDestroy( name );
    }
            
// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::CommitFindPaneTextL
// ---------------------------------------------------------------------------
//
TInt CPbk2PredictiveSearchFilter::CommitFindPaneTextL( MPbk2FilteredViewStack& aViewStack,
                                MPbk2ContactNameFormatter& aNameFormatter )
    {    
    //aViewStack contains list of the items that is currently shown in
    //the nameslist. 
    //The first item's matched characters must be shown in the Findpane    
    if ( !IsPredictiveActivated() )
        {
        return KErrNotFound;
        }    
    
    RBuf copyPredictiveTextEntered;
    CleanupClosePushL(copyPredictiveTextEntered);
    copyPredictiveTextEntered.CreateL(iPredictiveTextEntered);
    copyPredictiveTextEntered.Trim();
    TBool allCharsAreSpaces = (copyPredictiveTextEntered.Length() == 0) ? ETrue : EFalse;
    CleanupStack::PopAndDestroy(&copyPredictiveTextEntered);
    if( allCharsAreSpaces )
        {
        ReDrawL();
        return KErrNotFound;
        }
    
    TBuf<KSearchFieldLength> matchSeqChr; 
    CPbk2PredictiveViewStack& view = static_cast
                    <CPbk2PredictiveViewStack&>( aViewStack );
    TInt contactCount = aViewStack.ContactCountL();
    TInt matchedItemIndex = KErrNotFound;
    if ( &view && contactCount )
        {
   
        //Proceed, only if there are any contacts visible in the view
        TBool found = EFalse;
        CPsQuery* lastQuery = const_cast<CPsQuery*> (view.LastPCSQuery()); 
        for ( TInt index = 0; index<contactCount && lastQuery && !found; index++ )
            {
            //Iterate untill we find a match to our predictive search query      
            if ( view.IsNonMatchingMarkedContact( index ) )
                {
                //Avoid any mess with the marked contacts that are not part of our
                //search result
                continue;
                }
            
            //Get the item from the view stack
            const MVPbkViewContact& contact = aViewStack.ContactAtL( index );
            LookupL( contact, view, aNameFormatter, matchSeqChr );
            found = matchSeqChr.Length();
            if ( found )
                {
                matchedItemIndex = index;
                }
            }
        }
    
    CommitFindPaneTextL( matchSeqChr );
    return matchedItemIndex;
    }

// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::CommitFindPaneTextL
// ---------------------------------------------------------------------------
//
void CPbk2PredictiveSearchFilter::CommitFindPaneTextL( MPbk2FilteredViewStack& aViewStack,
                                MPbk2ContactNameFormatter& aNameFormatter, const TInt aIndex )
    {
    CPbk2PredictiveViewStack& view = static_cast
                     <CPbk2PredictiveViewStack&>( aViewStack );
    const MVPbkViewContact& contact = aViewStack.ContactAtL( aIndex );
    TBuf<KSearchFieldLength> matchSeqChr; 
    LookupL( contact, view, aNameFormatter, matchSeqChr );
    CommitFindPaneTextL( matchSeqChr );
    }

// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::CommitFindPaneTextL
// ---------------------------------------------------------------------------
//
void CPbk2PredictiveSearchFilter::CommitFindPaneTextL( const TDesC& aMatchSeq )
    {
    if ( !iSearchText )
        {
        return;
        }
    
    TPtr searchPtr (iSearchText->Des()); //Text with which previous search was initiated    
    TInt len = iPredictiveTextEntered.Length();
    TInt matchSeqLen = aMatchSeq.Length();
    TBuf <KSearchFieldLength> searchTextBuffer;    
    searchTextBuffer.Copy( searchPtr.Left( len ) );
    
    //if the last character was not a space  
    if ( len )            
        {
        if (matchSeqLen)
            {
            TInt matchSeqIndex( 0 );
            for ( TInt index = 0; index < len; index++ )
                {
                if ( (matchSeqIndex < matchSeqLen) && (aMatchSeq[matchSeqIndex] == Kspace) )
                    {
                    ++matchSeqIndex;
                    }
                if ( ( iPredictiveTextEntered[index] != Kspace ) 
                                && ( matchSeqIndex < matchSeqLen ) )
                    {
                    searchTextBuffer[index] = aMatchSeq[matchSeqIndex++];
                    }
                }
            
            iLocked = EFalse;          
            }
        else
            {                     
            for (TInt index=0; index<len; index++)
                {
                if ( searchTextBuffer[index] == Kspace )
                    {
                    searchTextBuffer[index] = iPredictiveTextEntered[index];
                    }
                }
            //there is no item to match this predictive serach query
            //hence replace the new character with ? and
            //lock the Findpane filter
            searchTextBuffer.Replace(
                    searchTextBuffer.Length()-1, 
                    KQuestionMark().Length(), 
                    KQuestionMark);
            iLocked = ETrue;    
            }

        SetSearchBoxTextL(searchTextBuffer, searchTextBuffer.Length());
        
        if (iLocked)
            {
            //Push the filter to the Top of the View Stack
            //AddToViewStackL will be run in OfferKeyEventL because it breaks FEP transaction
            iAddToViewStack = ETrue;
            }
        else
            {
            //Remove the filter from the Top of the View Stack
            RemoveFromViewStack();
            }
        iFiltering = EFalse;
        }
    }

// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::IsLocked
// ---------------------------------------------------------------------------
//
TBool CPbk2PredictiveSearchFilter::IsLocked() const
    {
    TBool locked (EFalse);
    if ( IsPredictiveActivated() )
        {
        locked = iLocked;
        }
    return locked;
    }

// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::OfferKeyEventL
// ---------------------------------------------------------------------------
//
TKeyResponse CPbk2PredictiveSearchFilter::OfferKeyEventL
        ( const TKeyEvent& aKeyEvent, TEventCode aType )
    {
    TKeyResponse keyConsume( EKeyWasNotConsumed ); 
    iEditorMode = ENone;
    
    if (IsPredictiveActivated())
        {
        if( iAddToViewStack )
            {
			//Push the filter to the Top of the View Stack
 		    //run delayed AddToViewStackL
            AddToViewStackL();
            iAddToViewStack = EFalse;
            }
        TChar ch(aKeyEvent.iScanCode);
        //If the FindPane filter is locked, discard all
        //other keys here. Since the filter is of high priority
        //than the FEP, FEP will not get the keyevent if consumed
        //by the findpane filter
        if (iLocked && ch.IsAlphaDigit())
            {
            keyConsume = EKeyWasConsumed;
            }
        else
            {
            if ( aType == EEventKeyDown )
                {
                iLongKeyPress = EFalse;
                }
            TInt code=aKeyEvent.iCode;
            const TInt modifiers=aKeyEvent.iModifiers;            
            TBool magnify=modifiers&EModifierCtrl;            
            
            if ( code == EKeyBackspace)
                {
                //Release the findPane lock
                iLocked = EFalse;
                if( iSearchText && iRemoveSpace )
                    {
                    SetSearchBoxTextL(*iSearchText, iSearchText->Length());
                    iRemoveSpace = EFalse;
                    }
                }
            
            //This Checks whether a Paste Operation was performed
            //on the findpane or not
            if (magnify && ( code<100 && code!=' ' ) ) ////!!! magic number
                {        
                TBuf<KSearchFieldLength> buf;        
                iCoeEnv->ReadResourceL(buf,R_EIK_EDWIN_CTRL_HOTKEYS);
                TInt ret=buf.Locate(TChar(code+'a'-1));        
                if ( ret == CEikEdwin::EHotKeyPaste )
                    {
                    iEditorMode = EPaste;
                    }
                }
            }
        }        
    return keyConsume;
    }

// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::ResetL
// ---------------------------------------------------------------------------
//
void CPbk2PredictiveSearchFilter::ResetL()
    {
    iVKbUsed = EFalse;
    RemoveFromViewStack();    
    
    delete iSearchText;
    iSearchText = NULL;    
            
    iSearchText = HBufC::NewL( KSearchFieldLength );
    iFiltering = EFalse;
    iLocked = EFalse;
    iLongKeyPress = EFalse;
    iPredictiveTextEntered.Close();
    iPredictiveTextEntered.CreateL( KSearchFieldLength );
    }
    
// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::FindPaneResetL
// ---------------------------------------------------------------------------
//
void CPbk2PredictiveSearchFilter::FindPaneResetL()
    {
    if ( iSearchField )
        {
        iSearchField->ResetL();
        }
    }

// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::GetSearchTextL
// ---------------------------------------------------------------------------
//
void CPbk2PredictiveSearchFilter::GetSearchTextL( RBuf& aSearchText )
    {
    //Reset
    aSearchText.Close();
    
    if (IsPredictiveActivated())
        {
        aSearchText.CreateL( iPredictiveTextEntered.Length() );
        aSearchText.Copy( iPredictiveTextEntered );        
        }
    else
        {
        aSearchText.CreateL ( iSearchField->TextLength() );
        iSearchField->GetSearchText( aSearchText );        
        }    
    }

// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::SetAknSearchFieldL
// ---------------------------------------------------------------------------
//
void CPbk2PredictiveSearchFilter::SetAknSearchFieldL( CAknSearchField* aSearchField )
    {
    iSearchField = aSearchField;
    iPredictiveTextEntered.CreateL( KSearchFieldLength );
    iSearchText = HBufC::NewL( KSearchFieldLength );
    }

// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::IsPasteMode
// ---------------------------------------------------------------------------
//
TBool CPbk2PredictiveSearchFilter::IsPasteMode()
    {
    return (iEditorMode == EPaste) ? ETrue : EFalse;
    }

// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::AddToViewStackL
// ---------------------------------------------------------------------------
//
void CPbk2PredictiveSearchFilter::AddToViewStackL()
    {
    if ( !iViewStack )
        {
        iViewStack = ETrue;
        iAppUi.AddToStackL(this, ECoeStackPriorityEnvironmentFilter, ECoeStackFlagRefusesFocus|ECoeStackFlagSharable);
        }
    }


// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::RemoveFromViewStack
// ---------------------------------------------------------------------------
//
void CPbk2PredictiveSearchFilter::RemoveFromViewStack()
    {
    if ( iViewStack )
        {
        iViewStack = EFalse;
        iAppUi.RemoveFromStack(this);
        }
    }

// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::HandleForegroundEventL
// ---------------------------------------------------------------------------
//
void CPbk2PredictiveSearchFilter::HandleForegroundEventL(TBool aForeground)
    {
    if ( aForeground && iLocked )
        {
        AddToViewStackL();
        }
    else
        {
        RemoveFromViewStack();
        }
    }

// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::FindPaneTextL
// ---------------------------------------------------------------------------
//
HBufC* CPbk2PredictiveSearchFilter::FindPaneTextL()
    {
    HBufC* findTextBuf( NULL );
    if ( iSearchField )
        {
        TPbk2FindTextUtil::EnsureFindTextBufSizeL( 
                *iSearchField,
                &findTextBuf );
        TPtr bufPtr = findTextBuf->Des();
        iSearchField->GetSearchText(bufPtr);
        if ( iLocked )
            {
            TInt index = bufPtr.LocateReverse( Kquestion );
            if ( ( KErrNotFound != index )  && ( index == bufPtr.Length() - 1 ) )
                {
                bufPtr.Delete( index, 1 );
                }
            }        
        }

    return findTextBuf;
    }


// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::IsMirroredInputLang
// ---------------------------------------------------------------------------
//
TBool CPbk2PredictiveSearchFilter::IsMirroredInputLang()
    {
    // Check if we have mirrored input
    // It is possible to have mixed input in search string. Always ask repository file to get
    // correct input language
    
    TBool mirroredInput( EFalse );
    TInt inputLang( 0 );
    CRepository* centRep( NULL );
    TRAPD(leavecode, centRep = CRepository::NewL( KCRUidAknFep ) );
    if( KErrNone == leavecode )
        {
        centRep->Get( KAknFepInputTxtLang, inputLang );
        }
    delete centRep;
    
    mirroredInput = ( inputLang == ELangArabic ||
                      inputLang == ELangHebrew ||
                      inputLang == ELangFarsi);            
            
    return mirroredInput;
    }

// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::SetSearchBoxTextL
// ---------------------------------------------------------------------------
//
void CPbk2PredictiveSearchFilter::ReDrawL(TBool aAsynchronous)
    {
    if( aAsynchronous )
        {
        iRunAsynch->ReDraw();
        return;
        }
    
    if( iSearchField )
        {
        RBuf searchText;
        searchText.CreateL ( iSearchField->TextLength() );
        CleanupClosePushL( searchText );
        iSearchField->GetSearchText( searchText );
        SetSearchBoxTextL( searchText, iSearchField->TextLength() );
        CleanupStack::PopAndDestroy(&searchText);
        }
    }

// ---------------------------------------------------------------------------
// CPbk2PredictiveSearchFilter::SetSearchBoxTextL
// ---------------------------------------------------------------------------
//
void CPbk2PredictiveSearchFilter::SetSearchBoxTextL( const TDesC& aText, TInt aCursorPos, TBool aDrawNow )
    {
    if( iSearchField )
        {
        iFiltering = ETrue;
        CEikEdwin& editor(iSearchField->Editor());
        if( IsPredictiveActivated() && aText.Length() )
            {
            CGlobalText* globalText = static_cast<CGlobalText*>(editor.Text());
            TCharFormat format;
            TCharFormatMask mask;
            TInt pos = 0;
            TInt length = aText.Length();
            globalText->GetCharFormat(format, mask, pos, length);
            format.iFontPresentation.iUnderline = EUnderlineOn;
            mask.SetAttrib(EAttFontUnderline);
            globalText->ApplyCharFormatL(format, mask, pos, length);
            editor.SetDocumentContentL(*globalText);
            }
        editor.SetTextL(&aText);
        editor.SetCursorPosL(aCursorPos, EFalse);
        if( aDrawNow )
            {
            editor.DrawNow();
            }
        iFiltering = EFalse;
        }
    }

 //End of File
