uiutils/Findutil/src/FindUtilWestern.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 13 Oct 2010 14:50:15 +0300
branchRCL_3
changeset 72 a5e7a4f63858
parent 59 978afdc0236f
permissions -rw-r--r--
Revision: 201039 Kit: 201041

/*
* Copyright (c) 2002-2005 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:         Western Find Utilities implementation file.
*
*/









#include "FindUtilWestern.h"
#include <collate.h>
#include <PtiIndicDefs.h>
#include "FindUtilKorean.h"
#include <avkon.rsg>
#include <StringLoader.h>
const TInt KLitTab('\t');
const TInt KLitSpace(' ');
const TInt KLitHyphen('-');
const TInt KLitLineFeed(8233);
const TInt KLitStar('*');
const TInt KLitQuestion('?');

const TInt KMatchingBufferLength(256);
const TInt KAknStringBufferSize = 256;

namespace {

// ---------------------------------------------------------------------------
// IsFindWordSeparator
// ---------------------------------------------------------------------------
//
inline TBool IsFindWordSeparator(TChar aCh)
    {
    return aCh == KLitSpace || aCh == KLitHyphen || aCh == KLitTab || aCh == KLitLineFeed;
    }



void ReplaceCharacters(TDes &aDes, const TDesC &aChars, TChar aReplacement)
    //
    // Running time O(aDes.Length() * aChars.Length())
    // Does not change length of the string.
    // 
    {
    TInt src = 0;
    TInt srclength = aDes.Length();
    while(src < srclength)
        {
        TChar c = aDes[src];
        if (aChars.LocateF(c) != KErrNotFound)
            aDes[src] = TUint16(aReplacement);
        ++src;
        }
    }

inline TInt MyFindC(const TDesC &aItemString, const TDesC &aSearchText)
    {
    TBuf<200> searchText;
    TBuf<200> itemString;
    searchText.Append(aSearchText);
    // The replacecharacters are to disable regexp matching provided
    // by MatchC().
	_LIT(KQuestion,"?");
	_LIT(KStar,"*");
    ReplaceCharacters(searchText, KQuestion, TChar('\t'));
    ReplaceCharacters(searchText, KStar, TChar('\r'));
    searchText.Append(KStar);
    if (aItemString.Length() < 200)
        itemString.Append(aItemString);
    else
        itemString.Append(aItemString.Left(200));
    ReplaceCharacters(itemString, KQuestion, TChar('\t'));
    ReplaceCharacters(itemString, KStar, TChar('\r'));


    TInt length = itemString.Length();
    for(int i=0;i<length;i++)
        {
        if (i==0 || IsFindWordSeparator(aItemString[i-1]))
            {
            if (itemString.Mid(i).MatchC(searchText) != KErrNotFound)
                {
                return i;
                }
            }
        }
    return KErrNotFound;
    }
inline TBool IsFindMatchClassic(const TDesC& aItemString, const TDesC& aSearchText, TInt /*aInputLang = 0*/)
    {
    TPtrC itemptr = aItemString;
    TPtrC searchptr = aSearchText;

    TBool match = EFalse;
    
    for(;;) 
        {
        // Loop invariant: itemptr is next character from ' ' or '-'
        // Loop invariant: seachptr is at beginning of searched item
    
        TInt val = MyFindC(itemptr,searchptr);
        if (val == 0)
            {
            match = ETrue;
            break;
            }
        if (val != KErrNotFound && IsFindWordSeparator(itemptr[val-1]))
            {
            match = ETrue;
            break;
            }

        // find the word separator characters from list item
        TInt spacepos = itemptr.LocateF(TChar(' '));
        TInt minuspos = itemptr.LocateF(TChar('-'));
        TInt tabpos = itemptr.LocateF(TChar('\t'));
        if (spacepos != KErrNotFound)
            {
            itemptr.Set(itemptr.Mid(spacepos+1));
            }
        else if (minuspos != KErrNotFound)
            {
            itemptr.Set(itemptr.Mid(minuspos+1));
            }
        else if (tabpos != KErrNotFound)
            {
            itemptr.Set(itemptr.Mid(tabpos+1));
            }
        else
            {
            match = EFalse;
            break;
            }
        if (itemptr.Length() == 0)
            {
            match = EFalse;
            break;
            }

        }
    return match;
    }

// ---------------------------------------------------------------------------
// IsFindMatch
// ---------------------------------------------------------------------------
//
inline TBool IsFindMatch(const TDesC& aItemString, const TDesC& aSearchText, TInt aInputLang = 0)
    {
    TBuf<200> searchText;
    TInt itemStringLength = aItemString.Length();
    
    if ( aSearchText.Length() < 200 )
        {
        searchText.Append( aSearchText );
        }
    else
        {
        searchText.Append( aSearchText.Left(199) );
        }
    
    // To disable the wildchar matching provided by MatchC
    if (aSearchText.Locate( KLitQuestion ) != KErrNotFound)
        {
        return IsFindMatchClassic(aItemString, aSearchText, aInputLang);
        }
    if (aSearchText.Locate( KLitStar ) != KErrNotFound)
        {
        return IsFindMatchClassic(aItemString, aSearchText, aInputLang);
        }

    searchText.Append( KLitStar );
        
    TInt result = KErrNone;
   
    for( TInt i = 0; i < itemStringLength; i++ )
        {
        if ( i==0 || IsFindWordSeparator( aItemString[i-1] ) )
            {
            
            if(aInputLang == ELangHindi
#ifdef RD_MARATHI
                || aInputLang == ELangMarathi
#endif

#ifdef RD_HINDI_PHONETIC_INPUT
                || aInputLang == KLangHindiPhonetic
#endif            
            )
            {
            TUint flag = ( TCollationMethod::EIgnoreNone | TCollationMethod::EFoldCase | TCollationMethod::EIgnoreCombining );
        	TCollationMethod m = *Mem::GetDefaultMatchingTable();
  			m.iFlags |= flag;
        	result = aItemString.Mid(i).MatchC( searchText, &m, 3);
            }
            else
            {
            	result = aItemString.Mid(i).MatchC( searchText );
            }
                        	
            if(result != KErrNotFound)
            	{
            		return ETrue;
            	}
            }
        }
        
    return EFalse;
	}	
}

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CFindUtilWestern::CFindUtilWestern
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CFindUtilWestern::CFindUtilWestern()
    {
    iRepository = NULL;
    iNotifyHandler = NULL;
    }

// Destructor
CFindUtilWestern::~CFindUtilWestern()
    {
    if ( iNotifyHandler )
        {
        iNotifyHandler->StopListening();
        delete iNotifyHandler;
        iNotifyHandler=NULL;
        }
    if(iRepository)
        {
        delete iRepository;
        iRepository = NULL;    
        }    	
    if ( iFindUtilKorean )
        {
    	delete iFindUtilKorean;
    	iFindUtilKorean = NULL;
        }
    if( iDigraphChars )       
        {
        delete iDigraphChars;
        }
    }


void CFindUtilWestern::OpenL()
	{
	CFindUtilBase::OpenL();
    
    if(!iRepository)
    	{
		iRepository = CRepository::NewL(KCRUidAknFep);
		iRepository->Get(KAknFepInputTxtLang, iInputLanguage);
	    }
	if(!iNotifyHandler)
	    {
		iNotifyHandler = CCenRepNotifyHandler::NewL( *this, 
                                              *iRepository,
                                              CCenRepNotifyHandler::EIntKey,
                                              KAknFepInputTxtLang );
		iNotifyHandler->StartListeningL();
	    }	
//TSW: LYEE-7Q2GRV  
	if(!iFindUtilKorean)
	    {
        iFindUtilKorean = CFindUtilKorean::NewL();
	    }
	}
	
void CFindUtilWestern::HandleNotifyInt( TUint32 aId, TInt aNewValue )
	{
	if(aId == KAknFepInputTxtLang)
	    iInputLanguage = aNewValue;
	}
	
// -----------------------------------------------------------------------------
// CFindUtilWestern::Match
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//

TBool CFindUtilWestern::Match(const TDesC& aContactsField, const TDesC& aWord)
    {
    if ( iFindUtilKorean->IsKoreanLanguage( aContactsField ) || iFindUtilKorean->IsKoreanLanguage( aWord ) )
        {
        return iFindUtilKorean->Match( aContactsField, aWord );	
        }
    else
    	{
    TInt numChar = 1;
    	if (!aContactsField.Length())
        	{
                _LIT( KNone, "*" );
    	        if( aWord.CompareC(KNone()) == 0 )
                    {
    	            return ETrue;
                    }
                else
                    {
        	    return EFalse;
                    }
        	}        
    	if((aWord.Length() > 1) && aWord[aWord.Length()-2] == 0x200B)
    		{
    		numChar = 2;
    		}    	
    	if ( IsFindMatch(aContactsField, aWord.Left(aWord.Length()-numChar), iInputLanguage) )
        	{
        	return ETrue;
        	}
  		return EFalse;
   		}
    }


// -----------------------------------------------------------------------------
// CFindUtilWestern::MatchRefineL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CFindUtilWestern::MatchRefineL( const TDesC& aItemString, const TDesC& aSearchText )
    {
    if ( iFindUtilKorean->IsKoreanLanguage( aItemString ) || iFindUtilKorean->IsKoreanLanguage( aSearchText ) )
        {
        return iFindUtilKorean->MatchRefineL( aItemString, aSearchText );	
        }
    else
    {
    if ( aItemString.Length() == 0 )
        {
        return EFalse;
        }

    if ( aSearchText.Length() == 0 )
        {
        return ETrue;
        }
    return IsFindMatch( aItemString, aSearchText, iInputLanguage );
    	}
    }

// -----------------------------------------------------------------------------
// CFindUtilWestern::IsWordValidForMatching
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CFindUtilWestern::IsWordValidForMatching(const TDesC& /*aWord*/)
    {
    return ETrue;
    }


// ========================= FOR ADAPTIVE FIND ================================

// -----------------------------------------------------------------------------
// For Vietnamese AS
// 
// -----------------------------------------------------------------------------
//
inline TChar ReplaceVietnameseChar( const TChar aCh )   
    {
    TChar Char = aCh.GetUpperCase();
    if ( (Char >= 0x00C0 && Char <= 0x00C3) || Char == 0x102  ||
         ((Char >= 0x1EA0 && Char <= 0x1EB6) && Char%2 == 0) )  
        {
        Char = 0x0041; // A
        return Char; 
        }        
    if ( (Char >= 0x00C8 && Char <= 0x00CA) || 
        ((Char >= 0x1EB8 && Char <= 0x1EC6) && Char%2 == 0) )
        {
        Char = 0x0045; // E
        return Char; 
        }               
    if ( Char == 0x00CC || Char == 0x00CD || Char == 0x0128 || 
         Char == 0x1EC8 || Char == 0x1ECA  )
        {
        Char = 0x0049; // I
        return Char; 
        }    
    if ( (Char >= 0x00D2 && Char <= 0x00D5 ) || Char == 0x1ECE || Char == 0x1ECC ||
        ((Char >= 0x1ED0 && Char <= 0x1ED8) && Char%2 == 0)) 
        {
        Char = 0x004F; // O
        return Char; 
        }            
    if ( Char == 0x1EDA || Char == 0x1EDC || Char == 0x1EDE || 
         Char == 0x1EE0 || Char == 0x1EE2  )
        {
        Char = 0x01A0; // O-horn
        return Char; 
        }          
    if ( Char == 0x00DA || Char == 0x00D9 || Char == 0x0168 || 
         Char == 0x1EE4 || Char == 0x1EE6  )
        {
        Char = 0x0055; // U
        return Char; 
        }         
     if ( (Char >= 0x1EE8 && Char <= 0x1EF0) && Char%2 == 0 )
        {
        Char = 0x01AF; // U-horn        
        return Char; 
        }         
     if ( ((Char >= 0x1EF2 && Char <= 0x1EF8) && Char%2 == 0) || Char == 0x00DD ) 
        {
        Char = 0x0059; // Y
        return Char; 
        }              
    return Char;
    } 
    
 /**
 * Checks current character is it special character from Vietnamese language . 
 *
 * @since 5.0
 * @return @c ETrue If it is accent from Vietnamese language, otherwise EFalse. 
 */	
inline TBool IsVietnameseSpecialCharacter( TChar aCh )
    {   
    if ( ( aCh >= 0x0300 && aCh <= 0x0303 ) ||       
        aCh == 0x0306 || aCh == 0x0309 || aCh == 0x0323 || aCh == 0x031B )
        {
        return ETrue;            
        }  
    return EFalse;
    }
       
/**
 * Update next characters if find pane state was changed.
 *
 * @since 5.0
 * @param aNextChars reference to the next characters for the adaptive search grid
 * @param aCh Criteria from the search field.    
 */
inline void UpdateNextCharsL( HBufC*& aNextChars, TChar aCh )
    {
        TChar ch_temp = aCh;          
    
    TLanguage lang = User::Language();  
    if ( lang == ELangVietnamese )
	   {
	   aCh = ReplaceVietnameseChar ( ch_temp );
	   }
    
    if( ( aNextChars->Locate(aCh.GetLowerCase() ) == KErrNotFound ) &&
        ( aNextChars->Locate(aCh.GetUpperCase() ) == KErrNotFound ) )
        {               
        if( aNextChars->Des().Length() == aNextChars->Des().MaxLength() )
            {
            aNextChars = aNextChars->ReAllocL( aNextChars->Des().MaxLength()+10 );
            TInt length1 = aNextChars->Des().Length();
            TInt maxlength1 = aNextChars->Des().MaxLength();
            }       
        aNextChars->Des().Append( aCh );            
        }
    }

// -----------------------------------------------------------------------------
// For Devanagari AS
// Checks if aCh denotes a consonant with nukta. 
// @return ETrue if aCh is a consonant with nukta EFalse otherwise.
// -----------------------------------------------------------------------------
//
inline TBool IsIndicCombinedChar( const TChar aCh )
    {   
    if ( aCh < 0x0900 || aCh > 0x0980 )
        {
        return EFalse;
        }
    else
        {
        return ( aCh == 0x0929 || aCh == 0x0931 || aCh == 0x0934 || 
                (aCh >= 0x0958 && aCh <= 0x095F) );
        }
    }

// -----------------------------------------------------------------------------
// For Devanagari AS
// Returns the correcponding character without nukta
// @param aCh - character to be stripped of nukta
// @return corresponding character with nukta
// -----------------------------------------------------------------------------
//
inline TChar RemoveIndicNukta( const TChar aCh )
    {
    switch (aCh)
        {
        case 0x0929 : return 0x0928; //vocallic 'nna' to 'na'
        case 0x0931 : return 0x0930; //vocallic 'rra' to 'ra'
        case 0x0934 : return 0x0933; //vocallic 'lllla' to 'lla'
        case 0x0958 : return 0x0915; //vocallic 'qa' to 'ka'
        case 0x0959 : return 0x0916; //vocallic 'khha' to 'kha'
        case 0x095A : return 0x0917; //vocallic 'ghha' to 'ga'
        case 0x095B : return 0x091C; //letter 'za' to 'ja'
        case 0x095C : return 0x0921; //vocallic 'dddha' to 'da'
        case 0x095D : return 0x0922; //vocallic 'rha' to 'ddha'
        case 0x095E : return 0x092B; //letter 'fa' to 'pha'
        case 0x095F : return 0x092F; //letter 'yya' to 'ya'        
        default : return aCh;
        }
    }

// -----------------------------------------------------------------------------
// For Devanagari AS
// Checks if the given character is a Indic consonant.
// @param aSearchChar - character to be checked.  
// @return ETrue if this is an independent character EFalse otherwise       
// -----------------------------------------------------------------------------
//  
inline TBool IsIndicConsonant( const TChar aSearchChar )
    {    
	if  (
	    ( aSearchChar >= 0x0915 && aSearchChar <= 0x0939 ) ||
	    ( aSearchChar >= 0x0958 && aSearchChar <= 0x0961 )
	    )
        {
        return ETrue;
        }
    else 
        {
        return EFalse;
        }
    }
    
// -----------------------------------------------------------------------------
// For Devanagari AS
// Checks if the given character is a Indic matra.
// @param aSearchChar - character to be checked.  
// @return ETrue if this is an matra EFalse otherwise  
// -----------------------------------------------------------------------------
//  
inline TBool IsIndicMatra( const TChar aSearchChar )
    {   
    if ( aSearchChar >= 0x093E && aSearchChar <= 0x094C )
        {
        return ETrue;
        }
    else 
        {
        return EFalse;
        }
    }
    
// -----------------------------------------------------------------------------
// For Devanagari AS
// Checks if the given character is a Devanagari independent character.
// @param aSearchChar - character to be checked.  
// @return ETrue if this is an independent character EFalse otherwise  
// -----------------------------------------------------------------------------
//
inline TBool IsIndicIndependentChar( const TChar aSearchChar )
    {    
	if (( aSearchChar >= 0x0905 && aSearchChar <= 0x0939 ) ||
	    ( aSearchChar >= 0x0958 && aSearchChar <= 0x0961 ))
        {
        return ETrue;
        }
    else 
        {
        return EFalse;
        }
    }    
    
// -----------------------------------------------------------------------------
// For Devanagari AS
// Checks if the passed string denotes one of the four special
// Devanagari ligatures - refer UI specs for the description of special ligatures
// @param aCharString - The string containing set of characters to be checked
// @return ETrue if a special ligature is found EFalse otherwise   
// -----------------------------------------------------------------------------
//  
inline TBool IsSpecialIndicLigature( const TDesC& aCharString )
    {
    TBool ret = EFalse;
    if( aCharString.Length() >= 3 )
        {      
        if( (((aCharString[0] == 0x915) && (aCharString[1] == 0x94D)&& (aCharString[2] == 0x937)) ||
             ((aCharString[0] == 0x91C) && (aCharString[1] == 0x94D)&& (aCharString[2] == 0x91E)) ||
             ((aCharString[0] == 0x936) && (aCharString[1] == 0x94D)&& (aCharString[2] == 0x930)) ||
             ((aCharString[0] == 0x924) && (aCharString[1] == 0x94D)&& (aCharString[2] == 0x930))) )
            {
            ret = ETrue;
            }
         }
    return ret;
    }    
   
// -----------------------------------------------------------------------------
// For Devanagari AS
// Counts the number of Indic syllables in the search string
// For the purpose of supporting mixed language entries, we count each
// non-Devanagari charcter as a single syllable. 
// Also replaces the place holder '-' with '*' for searching 
// @param aSearchText - The search string entered so far
// @param aSearchTextLength - Number of characters in string excluding '*'
// @return the number of Devanagari syllables in aCriteria   
// -----------------------------------------------------------------------------
//  
inline TInt IndicSyllableCount( HBufC* aSearchText, TInt& aSearchTextLength )
	{
	TInt syllableCount = 0;
	TPtr ptrSearchText = aSearchText->Des();
	TInt strLength = ptrSearchText.Length();
	for(TInt index=0 ; index < strLength ; index++)
		{
		if( (index) && ptrSearchText[index] == KLitHyphen && 
		        IsIndicIndependentChar(ptrSearchText[index-1]) )
			{
			syllableCount++;
			ptrSearchText[index] = KLitStar;
			--aSearchTextLength;
			}
		else if ( !IsIndicIndependentChar(ptrSearchText[index]) && ptrSearchText[index]!=0x094D )
			{
			//For any other non Indic-independent-character that was entered 
			//through adaptive grid, we consider it as a seperate syllable. 
			++syllableCount;
			}
		}
	return syllableCount;
	}    
	
// -----------------------------------------------------------------------------
// For Devanagari AS
// Checks if aCriteria[aCurrentIndex] is a fallback rendered character.
// @param aCriteria - string in which we need to check.
// @param aCurrentIndex - position in string of character to be checked
// @return ETrue if aCriteria is a rendered character EFalse otherwise.
// -----------------------------------------------------------------------------
//  
inline TBool IsFallbackRenderedCharacter( const TDesC& aCriteria, TInt aCurrentIndex )
    {    
    if ( aCriteria[aCurrentIndex] >= 0x0900 && aCriteria[aCurrentIndex] <= 0x0980)
        {
        // Check for invalid Nuktas:
        if ( aCriteria[aCurrentIndex] == 0x093C )
            {
            // A Nukta is valid only if placed after a consonant 
            if ( !IsIndicConsonant(aCriteria[(aCurrentIndex-1)]) )
                {
                return ETrue;
                }
            }
        // Check for invalid Matras: 
        else if ( IsIndicMatra(aCriteria[aCurrentIndex]) )
            {
            // These can only be placed after a consonant or a valid nukta
            TChar prevChar = aCriteria[(aCurrentIndex-1)];            
            if ( !(IsIndicConsonant(prevChar) || prevChar == 0x093C) )
                {
                return ETrue;
                }
            }
        // Check for invalid Modifiers:
        else if ( aCriteria[aCurrentIndex] >= 0x0901 && aCriteria[aCurrentIndex] <= 0x0903)
            {
            //These are valid only if placed after an independent vowel or a 
            //consonant or a valid nukta or a valid matra.
            TChar prevChar = aCriteria[(aCurrentIndex-1)];
            //if prev character is nukta or matra, it would have been already validated
            if ( !(IsIndicIndependentChar(prevChar) || prevChar == 0x093C 
                    || IsIndicMatra(prevChar) ) )
                {
                return ETrue;
                }
            }
        // Check for invalid Halant/Virama:
        else if ( aCriteria[aCurrentIndex] == 0x094D )
            {
            //This is valid only if placed immediately after a consonant or a valid nukta
            TChar prevChar = aCriteria[(aCurrentIndex-1)];
            //if prev character is nukta, it would have been already validated
            if ( !(IsIndicConsonant(prevChar) || prevChar == 0x093C) )
                {
                return ETrue;
                }
            }
        } //end of "if devanagari character range"    
    return EFalse;
    }
    
// -----------------------------------------------------------------------------
// For Devanagari AS
// Mark the end boundary of syllables in input string
// @param aCriteria - The search/input string entered so far
// @param aStart - The start boundary of syllable to be marked
// @return the end boundary of the syllable  
// -----------------------------------------------------------------------------
//  
inline TInt IndicSyllableEnd( TInt& aStart, const TDesC& aCriteria )
	{
	TInt maxLength = aCriteria.Length();
	TInt endMarker(-1);
	if(aStart >= (maxLength-1))
		{		
		aStart = endMarker = maxLength-1;
		}
	else 
		{			
		TInt nextCharIndex = aStart + 1 ;
		TChar startingChar = aCriteria[aStart];
		if ( IsIndicIndependentChar(startingChar) )
			{
			//Check if syllable contains a special ligature		
			if(  aStart < (maxLength-2) && IsSpecialIndicLigature(aCriteria.Mid(aStart, 3)) ) 
				{
				//Move nextCharIndex till after the 3rd symbol of special ligature.
				nextCharIndex+=2;
				}					
			//check for the next character that is a matra/halant/nukta/modifier
			//Currently this check only for Devanagari characters. If other Indic language support
			//is required, we will need to add to this list.
			while( (nextCharIndex<maxLength) && 
			      ( ( IsIndicMatra(aCriteria[nextCharIndex]) ) //matra
		          ||( aCriteria[nextCharIndex] == 0x094D ) //Devanagari halant
		          ||( aCriteria[nextCharIndex] == 0x093C ) //Devanagari nukta 
			      ||( aCriteria[nextCharIndex] >= 0x0901 && aCriteria[nextCharIndex] <= 0x0903 ))) //Devanagari modifier			      
			    {
				//check if this is a fallback rendered character. Increment index only if it isn't:
				if ( !IsFallbackRenderedCharacter(aCriteria, nextCharIndex) )
				    {
				    ++nextCharIndex;
				    }
				else
				    {
				    break;
				    }
				}
			}		
		//nextCharIndex should now be pointing to either the start of the next syllable
		//or a non-Devanagari-letter. 
		//End marker of current syllable should be placed just before the nextCharIndex
		endMarker = nextCharIndex-1;		
		}		
	return endMarker;			
	}

// -----------------------------------------------------------------------------
// For Devanagari AS
// Parses through each Devanagari-syllable in the input string.
// It will stop when we have gone through aInputSyllableCount number of syllables. 
// @param aCriteria - The search string entered so far
// @param aStart - The start boundary of the last parsed syllable 
// @param aEnd - The end boundary of the last parsed syllable  
// -----------------------------------------------------------------------------
//  
inline void IndicSyllableBoundary( TInt& aStart, TInt& aEnd, TInt aInputSyllableCount, 
    const TDesC &aCriteria )
	{
	TInt boundaryCount = 0;
	TInt tStart = aStart = 0;
	while( boundaryCount != aInputSyllableCount )
		{
		aEnd = IndicSyllableEnd(tStart, aCriteria);	
		boundaryCount++;
		aStart = tStart;
		tStart = aEnd+1;	
		}
	}

// -----------------------------------------------------------------------------
// For Devanagari AS
// Checks if aItemString contains atleast one Indic letter
// @param aItemString - string to be checked
// @return ETrue if aItemString contains Devanagari letter EFalse otherwise.
// -----------------------------------------------------------------------------
//  
inline TBool IsIndicWord( const TDesC& aItemString )
	{
	TInt strLength = aItemString.Length();
	for ( TInt index = 0; index < strLength; ++index )
		{	
		if ( (aItemString[index] >= 0x900) && (aItemString[index] <= 0x980) )
			return ETrue;
		}
	return EFalse;
	}

// -----------------------------------------------------------------------------
// For Devanagari AS
// Checks if the last character from aNextChars can be displayed on 
// the adaptive search grid or not. For now, this filters out the Devanagari 
// vowels and other special symbol which are represented by the placeholder '-'.
// @param aNextChars list of characters to be displayed on adaptive search grid
// @return ETrue last character is valid for AS Grid, else EFalse.  
// -----------------------------------------------------------------------------
//  
inline TBool IsValidNextChars( const TDesC &aNextChars )
	{
	TBool ret = ETrue;
	if(aNextChars.Length()>0)
		{
		TChar ch = aNextChars[aNextChars.Length()-1];
		if( (ch >= 0x0901 && ch <= 0x0903) || (ch >= 0x093C && ch <= 0x094D) )
			{
			ret = EFalse;
			}	   
        }
	return ret;
	}


// -----------------------------------------------------------------------------
// For Devanagari AS
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//  
inline void UpdateNextCharsL( HBufC*& aNextChars, const TDesC& aItemString )
	{
	TChar searchChar = aItemString[0];
    //Check if this is an Indic special ligature
    if ( IsIndicConsonant(searchChar) && aItemString.Length() > 2
            && IsSpecialIndicLigature(aItemString) 
            && KErrNotFound == (*aNextChars).Find(aItemString.Mid(0,3)) )
        {
        //Check if we have enough space for 3 more characters
        if( aNextChars->Des().Length() >= aNextChars->Des().MaxLength()-3 )
            {
            aNextChars = aNextChars->ReAllocL( aNextChars->Des().MaxLength()+10 );
            }       
        aNextChars->Des().Append( aItemString.Mid(0,3) );        
        }
    else
        {
        //check if this is an Indic combined Char
        if ( IsIndicCombinedChar(searchChar) )
            {
            searchChar = RemoveIndicNukta( searchChar );
            }
        //Now update the nextChars string
        TInt strLength = aNextChars->Length();
        for ( TInt i(0); i < strLength ; ++i )
            {
            if ( IsSpecialIndicLigature( (*aNextChars).Mid( i ) ) )
                {
                //As aItemString is not a special ligature (checked above)
                //we can move directly to the 3rd character from here
                i+=2;
                }
            else if ( searchChar.GetUpperCase() == (*aNextChars)[i] ||
                        searchChar.GetLowerCase() == (*aNextChars)[i] )
                {
                //already exists - do nothing
                return;
                }
            //else continue the loop
            }
        //So this character is not yet in the list of nextChars.
        if ( aNextChars->Des().Length() == aNextChars->Des().MaxLength() )
            {
            aNextChars = aNextChars->ReAllocL( aNextChars->Des().MaxLength()+10 );
            }       
        aNextChars->Des().Append( searchChar );   
        }
   	}

/**
 * Update next chars from the list box item text, when search field is empty.
 * This need to be done for update next characters for adaptive grid
 * works faster then calling IsAdaptiveFindMatch().   
 *
 * @since 5.0
 * @param aNextChars reference to the next characters for the adaptive search grid
 * @param aItemString List box item text.
 */
 
inline void UpdateNextCharsFromString( HBufC*& aNextChars, const TDesC& aItemString )
	{   
	 TInt itemStringLength = aItemString.Length();
	 
	 for( TInt i = 0; i < itemStringLength; i++ )
        {
        if ( i == 0 || IsFindWordSeparator( aItemString[i-1] ) )
            {  
            //If this is an Indic letter 
            if ( aItemString[i] >= 0x0900 && aItemString[i] <= 0x0980 )
                {
                TRAP_IGNORE( UpdateNextCharsL( aNextChars, aItemString.Mid(i) ) );
                }
            else  if (!(IsVietnameseSpecialCharacter( aItemString[i])))
                {
                TRAP_IGNORE( UpdateNextCharsL( aNextChars, aItemString[i] ) );
                }
            }
		}
	}
	
inline TBool IsAdaptiveFindMatchClassic( const TDesC& aItemString, const TDesC& aSearchText )
    {
    TPtrC itemptr = aItemString;
    TPtrC searchptr = aSearchText;

    TBool match = EFalse;
    
    for(;;) 
        {
        // Loop invariant: itemptr is next character from ' ' or '-'
        // Loop invariant: seachptr is at beginning of searched item
    
        TInt val = MyFindC(itemptr,searchptr);
        if (val == 0)
            {
            match = ETrue;
            break;
            }
        if (val != KErrNotFound && IsFindWordSeparator(itemptr[val-1]))
            {
            match = ETrue;
            break;
            }

        // find the word separator characters from list item
        TInt spacepos = itemptr.LocateF(TChar(' '));
        TInt minuspos = itemptr.LocateF(TChar('-'));
        TInt tabpos = itemptr.LocateF(TChar('\t'));
        if (spacepos != KErrNotFound)
            {
            itemptr.Set(itemptr.Mid(spacepos+1));
            }
        else if (minuspos != KErrNotFound)
            {
            itemptr.Set(itemptr.Mid(minuspos+1));
            }
        else if (tabpos != KErrNotFound)
            {
            itemptr.Set(itemptr.Mid(tabpos+1));
            }
        else
            {
            match = EFalse;
            break;
            }
        if (itemptr.Length() == 0)
            {
            match = EFalse;
            break;
            }

        }
    return match;
    }	

/**
 * Checks the current character for special character from Thai language . 
 *
 * @since 5.0
 * @return @c ETrue If tone mark or diatric from Thai language otherwise EFalse. 
 */	
inline TBool IsThaiSpecialCharacter( TChar aCh )
    {    
    if( ( aCh > 0xE46 && aCh < 0xE4F ) ||  aCh == 0xE3A )
		{
		return ETrue;
		}       
	return EFalse;
    }

/**
 * Checks if @c aItemText matches @c aSearchText in the sense described in
 * S60.  Calls UpdateNextCharsL() if findutil is not supported.
 *
 * @since 5.0
 * @param aItemText list box item text.
 * @param aSearchText search text.
 * @param aNextChars reference to the next characters for the adaptive search grid
 * @param aDigraphs digraphs and trigraph text.
 * 
 * @return @c ETrue if list box item text matches aSearchText EFalse otherwise.
 */
inline TBool IsAdaptiveFindMatch( const TDesC& aItemString, 
	const TDesC& aSearchText, HBufC*& aNextChars, TInt /*aInputLang*/, const TDesC& aDigraphs )
	{	    	
	HBufC16* searchText = NULL;
	TRAPD( error, searchText = HBufC16::NewL( KMatchingBufferLength ) );
	TBool wildchar = EFalse;
	if ( error == KErrNone )
	    {
	    TInt itemStringLength = aItemString.Length();
        TInt searchTextLength = aSearchText.Length();    
        
        if ( searchTextLength < KMatchingBufferLength )
        	{
        	searchText->Des().Append( aSearchText );
        	}
        else
        	{
        	searchText->Des().Append( aSearchText.Left(KMatchingBufferLength-1) );
        	}  
        	 
         // To disable the wildchar matching provided by MatchC
        if ( aSearchText.Locate( KLitQuestion ) != KErrNotFound || 
             aSearchText.Locate( KLitStar ) != KErrNotFound )
            {            
            wildchar = IsAdaptiveFindMatchClassic( aItemString, aSearchText );
            if ( wildchar == EFalse )
                {
                delete searchText;
                return wildchar;
                }
            else 
                {  
                TInt val;      
                searchText->Des().Append( KLitStar );
                for( TInt i = 0; i < itemStringLength; i++ )
                    {
                    if ( i == 0 || IsFindWordSeparator( aItemString[i-1] ) )
                        {
                        val = MyFindC(  aItemString, aSearchText );                    
                        if( (val == i) && (i < (itemStringLength-searchTextLength))) 
                            {
                            if( !(IsThaiSpecialCharacter(aItemString[i+searchTextLength])) && !(IsVietnameseSpecialCharacter( aItemString[i+searchTextLength]) ))
                                {
                                TRAP_IGNORE( UpdateNextCharsL( aNextChars, aItemString[i+searchTextLength]) );   
                                }                                
                            }
                        }         
              	    } // for
              	delete searchText;
                return wildchar;	 
                }
            }
      	     	
        searchText->Des().Append( KLitStar );
        searchText->Des().UpperCase();

        TBool isCommonChars = EFalse;
        TInt all_result = KErrNotFound;
        
        TLanguage lang = User::Language();
        
        for( TInt i = 0; i < itemStringLength; i++ )
            {
            if ( i == 0 || IsFindWordSeparator( aItemString[i-1] ) )
                {
                TInt result = KErrNotFound;
                //Some vowels of Thai can not be searched with MatchC(). 
                if( aDigraphs.Length() != 0 || lang == ELangThai )
                    {
                    result = aItemString.Mid(i).Match( searchText->Des() );
                    }
                else
                    {
                    result = aItemString.Mid(i).MatchC( searchText->Des() );
                    }
                
                if( result != KErrNotFound ) 
                    {
                    all_result = result;
                    if( i < (itemStringLength-searchTextLength) )                	   	       	   		
                        {
                        if( !(IsThaiSpecialCharacter( aItemString[i+searchTextLength])) && !(IsVietnameseSpecialCharacter( aItemString[i+searchTextLength]) ))
                            {
                            TRAP_IGNORE( UpdateNextCharsL( aNextChars, aItemString[i+searchTextLength]) );

                            if ( aDigraphs.Length() != 0 )
                                {
                                TBuf<2> digraph;
                                digraph.Append( aItemString[i+searchTextLength-1] );
                                digraph.Append( aItemString[i+searchTextLength] );

                                if( searchTextLength == 1 )
                                    {
                                    if( aDigraphs.Find( digraph ) == KErrNotFound )
                                        {
                                        isCommonChars = ETrue;
                                        }
                                    }
                                else
                                    {
                                    TBuf<3> trigraph;
                                    trigraph.Append( aItemString.Mid(i+searchTextLength-2,3) );
                                    if( digraph[0] == KLitSpace 
                                        || ( aDigraphs.Find( digraph ) == KErrNotFound
                                        && aDigraphs.Find( trigraph ) == KErrNotFound ) )
                                        {
                                        isCommonChars = ETrue;
                                        }
                                    }
                                }
                            }            	   
                        }
                    else
                        {
                        isCommonChars = ETrue;
                        }
                    }                                                                  	   	
                } // if (i==0 ..)  
      	    } // for	 
        
        if(aDigraphs.Length() != 0 && !isCommonChars )   
            {
            all_result = KErrNotFound;
            }
	    
  	    if( all_result != KErrNotFound )
            {
            delete searchText;
            return ETrue;
           	}    
        else 
            {
            delete searchText;
            return EFalse;
            }
        	            		
         } // if (error == KErrNone)   
    delete searchText;                 
    return EFalse;
	}

// -----------------------------------------------------------------------------
// For Devanagari AS
// Checks if @c aItemText matches @c aSearchText.
// @param aItemText list box item text.
// @param aSearchText search text.
// @param aNextChars reference to the next characters for the adaptive search grid
// @return @c ETrue if list box item text matches EFalse otherwise.
// -----------------------------------------------------------------------------
//  
inline TBool IsIndicAdaptiveFindMatch( const TDesC& aItemString, 
	const TDesC& aSearchText, HBufC*& aNextChars, TInt /*aInputLang*/ )
	{	    	
	HBufC16* searchText(NULL);
	TRAPD( error, searchText = HBufC16::NewL( KMatchingBufferLength ) );
	if ( error == KErrNone )
	    {
	    TInt itemStringLength = aItemString.Length();
        TInt searchTextLength = aSearchText.Length();    
        
        if ( searchTextLength < KMatchingBufferLength )
        	{
        	searchText->Des().Append( aSearchText );
        	}
        else
        	{
        	searchText->Des().Append( aSearchText.Left(KMatchingBufferLength-1) );
        	}    
    	
    	TInt indicSyllableCount = -1;
        if( aSearchText.Length()>0 )
    		{
    		//This will replace all placeholder '-' symbols with '*'
     		indicSyllableCount = IndicSyllableCount( searchText, searchTextLength );
    		}
    	    	
    	//Append '*' to the end if not already present.
        if ( (*searchText)[searchText->Length() - 1] != KLitStar)
    		{
    		searchText->Des().Append( KLitStar );
    		}   
    	
    	TInt result = KErrNotFound;
        
        //check if the search string is found in the item string
        for( TInt index = 0; index < itemStringLength; index++ )
            {
            if ( index==0 || IsFindWordSeparator( aItemString[index-1] ) )
                {
                TUint flag = ( TCollationMethod::EFoldCase | TCollationMethod::EIgnoreNone | TCollationMethod::EIgnoreCombining);//TCollationMethod::EIgnoreNone |
        		TCollationMethod collationMethod = *Mem::GetDefaultMatchingTable();
        		collationMethod.iFlags |= flag;
            
           		result = aItemString.Mid(index).MatchC( (*searchText), &collationMethod );
                
                if( result != KErrNotFound ) 
                    {
                    if( index <= (itemStringLength-searchTextLength) )
        	   			{
        	   			//search for the last character in the string
        	   			//We use a TBuf instead of TChar since a special ligature is 
        	   			//represented by 3 characters. Last char would be the '*' wildchar.
	        	   		TBuf<4> lastChar;
	        	   		TInt modifiedStrLength = searchText->Length();
	        	   		if( (*searchText)[modifiedStrLength-1] == KLitStar )
	        	   			{
	        	   			//is this a special ligature?
	        	   			if ( modifiedStrLength > 3 &&
	        	   			        IsSpecialIndicLigature( (*searchText).Mid(modifiedStrLength-4) ) )
	        	   			    {
	        	   			    lastChar = (*searchText).Mid(modifiedStrLength-4);
	        	   			    }
	        	   			else
	        	   			    {
	        	   			    lastChar = (*searchText).Mid(modifiedStrLength-2);
	        	   			    }
	        	   			}
	        	   		else
	        	   			{
	        	   			//No wildchar here
	        	   			lastChar = (*searchText).Mid(modifiedStrLength-1);
	        	   			}
	        	   		
	        	   		lastChar.UpperCase(); //For latin characters as adaptive grid is always in upper case
        	   			TInt charPos = result; //aItemString.Mid(index).MatchC( searchText->Des(), &collationMethod );
        	   			//if found position is not within the substring to be searched, return EFalse.
                        if( charPos == KErrNotFound)
                            {
                            delete searchText;
                            return EFalse;
                            }
                        
        	   			TInt tempPos = charPos;
	        	   		
	        	   		TInt startCount = -1 , endCount = -1;
	        	   		
    	   				//TInt tempIndex(0);
    	   				//Get the position of the next syllable to be checked
    	   				IndicSyllableBoundary(startCount, endCount, indicSyllableCount, aItemString.Mid(index));
    	   				tempPos = aItemString.Mid(index+startCount).MatchC( lastChar, &collationMethod ); 
    	   				
    	   				if (
    	   				//if found position is not within the next syllable to be searched, 
    	   				//return EFalse.
    	   				    ( tempPos != 0 )  
    	   				//Also check if character to be searched is a single unicode while
    	   				//the match is at the start of a special ligature
    	   				   	|| ( !IsSpecialIndicLigature( lastChar ) && 
    	   				            IsSpecialIndicLigature( aItemString.Mid(index+startCount) ) )
    	   				    )
    	   				    {
    	   				    delete searchText;
    	   				    return EFalse;
    	   				    }
	        	   		
	        	   		//else, continue - find the next characters to be displayed on the grid	
	        	   		tempPos = index + endCount + 1;
	        	   		
	        	   		do	{
	        	   		    if(charPos!=KErrNotFound && (tempPos) < itemStringLength )
        	   					{
        	   						TRAP_IGNORE( UpdateNextCharsL( aNextChars, aItemString.Mid(tempPos) ) );
        	   					}
        	   				
        	   				//Is the found next character a consonent/independent-vowel/non-Indic character?
        	   				if ( IsValidNextChars( *aNextChars ) )
        	   					{
        	   					//found a valid character for displaying on the grid - return from here
        	   					delete searchText;
            					return ETrue;
        	   					}
        	   				else //we found an invalid valid character - keep searching
        	   					{
        	   					TPtr ptr = aNextChars->Des();
        	   					ptr.Delete(aNextChars->Length()-1,1);
        	   					//Is this a fallback rendered character?
        	   					if ( IsFallbackRenderedCharacter(aItemString, tempPos) )
        	   					    {
        	   					    //Keep the entry but don't show any more characters from this word
        	   					    delete searchText;
        	   					    return ETrue;
        	   					    }
        	   					}
        	   				}
        	   			//keep looping till we find a valid nextChar or we reach the end of the string
        	   			while(tempPos < itemStringLength ); 
        	   			
        	   			}
        	   			
        	   		} // if( result != KErrNotFound )                                                                  	   	
                } // if (index==0 ..)        
      	    } // for loop	 
	    
  	    if( result != KErrNotFound )
            {
            delete searchText;
            return ETrue;
           	}    
        else 
            {
            delete searchText;
            return EFalse;
            }
        	            		
         } // if (error == KErrNone)   
    delete searchText;                 
    return EFalse;
	}
	
// -----------------------------------------------------------------------------
// CFindUtilWestern::MatchAdaptiveRefineL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//  
TBool CFindUtilWestern::MatchAdaptiveRefineL( const TDesC& aItemString, 
	const TDesC& aSearchText, HBufC*& aNextChars )
	{
    if ( aItemString.Length() == 0 )
        {
        return EFalse;
        }
    if ( aSearchText.Length() == 0 )
        {        
        UpdateNextCharsFromString( aNextChars, aItemString );
        return ETrue;
        }
        
    if( iDigraphChars == NULL )
        {
        iDigraphChars = StringLoader::LoadL( R_QTN_ADS_DIGRAPH );
        TPtr digraph = iDigraphChars->Des();
        digraph.UpperCase();

        _LIT( KMissing,"#MISSING" );
        if( digraph.CompareC(KMissing()) == 0 )
            {
            digraph = KNullDesC;
            }
        }
        
    TBuf<KAknStringBufferSize> itemString(aItemString);
    itemString.UpperCase();

    //AS does not show tone marks and diacritics when language is Thai.
    TLanguage lang = User::Language();  
    if ( lang == ELangThai )
        {
        for(TInt i=0; i < itemString.Length(); i++)
            {
            if(IsThaiSpecialCharacter( itemString[i] ))
                {
                itemString.Delete(i,1);
                }
            }
        }

    if ( IsIndicWord(aItemString) )
    	{
    	// itemString contains Devanagari letters
    	return IsIndicAdaptiveFindMatch( itemString, aSearchText, aNextChars, iInputLanguage );		
    	}
    else 
    	{
    	return IsAdaptiveFindMatch( itemString, aSearchText, aNextChars, iInputLanguage, iDigraphChars->Des() );				
    	}    
	}
	
// ---------------------------------------------------------
// Match arithmetic for accurate search, special conversion 
// for aItemString is implemented with MFindStringConverter
// before the final match
// ---------------------------------------------------------
//
TBool CFindUtilWestern::MatchRefineL( const TDesC& /*aItemString*/, const TDesC& /*aSearchText*/, 
                                      TMatchPolicy /*aPolicy*/, MFindStringConverter* /*aConverter*/)
    {
    return EFalse;
    }	

// ========================== OTHER EXPORTED FUNCTIONS =========================

// -----------------------------------------------------------------------------
// FindUtilFactoryFunctionL
// Factory function at first ordinal
// Returns: MFindUtil: It returns MFindUtil I/F.
// -----------------------------------------------------------------------------
//
// Factory function at first ordinal
EXPORT_C MFindUtil* FindUtilFactoryFunctionL()
    {
    return new( ELeave ) CFindUtilWestern();
    }

// end of file