/*
* Copyright (c) 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:  Implementation of class CFsTextParser
*
*/



//<cmail> removed __FS_ALFRED_SUPPORT flag
//#include <fsconfig.h>
//</cmail> removed __FS_ALFRED_SUPPORT flag
// <cmail> SF
#include "emailtrace.h"
#include <alf/alftextstylemanager.h>
// </cmail>
#include <eikenv.h>
#include <icl/imagedata.h>
// <cmail>
#include <AknUtils.h>
// </cmail>
#include <fldinfo.h>

#include "fstextparser.h"
#include "fsrichtexttext.h"
#include "fsrichtextpicture.h"
#include "fsrichtextsmiley.h"
#include "fsrichtextnewline.h"
#include "fsrichtext.h"
#include "fsrichtextfields.h"
#include "fssmileyparser.h"
#include "fstextureloader.h"
#include "fstexture.h"
#include "fstextstylemanager.h"


#include "fbs.h"


CFsTextParser::CFsTextParser(
        CFsRichText& aText,
        CAlfEnv& aEnv,
        CFsTextureLoader* aTextureLoader):
    iText(aText),
    iTextureLoader(aTextureLoader),
    iEnv(aEnv),
    iTextStyleManager(NULL),
    iIsWordTooLong(EFalse),
    iIsSetSizeOfSmiley(EFalse),
    iGetCharsUsed(EFalse),
    iGetCharsUsedOfNextBlock(EFalse),
    iNewLineArrayIndex(0),
    iLastNewLinePositionIndex(0)
    {
    FUNC_LOG;

    }

CFsTextParser* CFsTextParser::NewL(
        CFsRichText& aText,
        CAlfEnv& aEnv,
        CFsTextureLoader* aTextureLoader)
    {
    FUNC_LOG;
    CFsTextParser * self = new(ELeave) CFsTextParser(
            aText,
            aEnv,
            aTextureLoader );
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }

CFsTextParser::~CFsTextParser()
    {
    FUNC_LOG;
    iExpandArray.Close();
    iHotSpotArray.Close();
    iFieldLocation.Close();
    iTextureIndex.Close();
    iNewLineArray.Close();
    iLineDirection.Close();

    delete iSmileyParser;
    }

void CFsTextParser::SetSizeOfSmile(TSize aSizeOfSmiley)
    {
    FUNC_LOG;
    iIsSetSizeOfSmiley = ETrue;
    iSizeOfSmiley = aSizeOfSmiley;
    }

void CFsTextParser::ConstructL()
    {
    FUNC_LOG;
    iEikon = CEikonEnv::Static();
    }

TBool CFsTextParser::SetParsingPosition( TInt aPosition )
    {
    FUNC_LOG;
    TBool retVal = ETrue;

    if( aPosition < 0 || aPosition >= iText.DocumentLength())
        {
        retVal = EFalse;
        }
    else
        {
        iPosition = aPosition;
        }

    return retVal;
    }

void CFsTextParser::MoveBack()
    {
    FUNC_LOG;
    iPosition = iLastPosition;
    }

TInt CFsTextParser::IsWordPartOfExpandArea(
        TInt aStartPosition,
        TInt aEndPosition )
    {
    FUNC_LOG;
    TInt retVal = -1;

    for(TInt i = 0 ; i < iExpandArray.Count() ; ++i)
        {
        if(iExpandArray[i].iStartIndex >= aStartPosition &&
            iExpandArray[i].iStartIndex < aEndPosition)
            {
            if(-1 == retVal)
                {
                retVal = i;
                }
            else
                {
                if ( iExpandArray[i].iStartIndex
                        < iExpandArray[retVal].iStartIndex )
                    {
                    retVal = i;
                    }
                }
            }
        else if ( aStartPosition >= iExpandArray[i].iStartIndex
                && aStartPosition
                  < iExpandArray[i].iStartIndex + iExpandArray[i].iLength )
            {
            if(-1 == retVal)
                {
                retVal = i;
                }
            else
                {
                if ( iExpandArray[i].iStartIndex
                        < iExpandArray[retVal].iStartIndex )
                    {
                    retVal = i;
                    }
                }
            }
        }
    return retVal;
    }


void CFsTextParser::CutWord(TInt aBeginOfWord, TInt aNewLengthOfWord)
    {
    FUNC_LOG;
    iIsWordTooLong = ETrue;
    iPosition = aBeginOfWord;
    iNewLengthOfWord = aNewLengthOfWord;
    }

// ---------------------------------------------------------------------------
// GetTextL
// ---------------------------------------------------------------------------
HBufC* CFsTextParser::GetTextL(TInt aStart, TInt aEnd) const
    {
    FUNC_LOG;
    HBufC* retVal = HBufC::NewL( aEnd - aStart + 1 );
//    TBuf<200> someText01;
    if(aStart < 0 || aEnd > iText.DocumentLength() || aEnd < aStart)
        {
        User::Leave(KErrArgument);
        }

//    someText01.Zero();
    TPtr ptr( retVal->Des() );
    ptr.Append( iText.Read(aStart, aEnd - aStart + 1) );
    while ( ptr.Length() < aEnd - aStart + 1 )
        {
        ptr.Append( iText.Read( aStart + ptr.Length(), aEnd - aStart + 1 - ptr.Length() ) );
        }
//    TPtrC retVal;
//    retVal.Set( someText01.Ptr(), someText01.Length() );
    return retVal;
    }

// ---------------------------------------------------------------------------
// GetTextureL
// ---------------------------------------------------------------------------
CFsTexture& CFsTextParser::GetTextureL(TInt aPos)
    {
    FUNC_LOG;
    if(aPos > iText.DocumentLength())
        {
        User::Leave(KErrArgument);
        }

    const CTextField* field = iText.TextField(aPos);

    CFsTexture* retVal = NULL;

    TInt textureId;
    if(!IsTexturePosition(aPos, textureId))
    	{
		if(KFsRichTextPictureFieldUid == field->Type())
			{
			TPictureHeader header = iText.PictureHeader(aPos);

			CMyPicture* picture =
				static_cast<CMyPicture*>(header.iPicture.AsPtr() );

			CFbsBitmap* bitmap = picture->GetBitmap();
			CFbsBitmap* bitmapMask = picture->GetBitmapMask();

			CFsTexture& texture = (iTextureLoader->AppendBitmapL(bitmap, bitmapMask));

			TTextureIndex newTextureIndex;
			newTextureIndex.iPositionInText = aPos;
			newTextureIndex.iTextureId = texture.Id();

			iTextureIndex.Append(newTextureIndex);

			retVal = &texture;
			}
		else if(KFsRichTextSmileyFieldUid == field->Type())
			{

			TInt smileyIndex = ((CSmileyField*)(field))->GetSmileyIndex();


			TFileName fileName = iSmileyParser->GetSmileyFileName(smileyIndex);


			CFsTexture& texture = iTextureLoader->LoadTextureL( fileName );

			TTextureIndex newTextureIndex;
			newTextureIndex.iPositionInText = aPos;
			newTextureIndex.iTextureId = texture.Id();

			iTextureIndex.Append(newTextureIndex);

			retVal = &texture;
			}
		else
			{
			User::Leave(KErrArgument);
			}
    	}
    else
    	{
    	CFsTexture* texture = iTextureLoader->SearchById(textureId);

    	retVal = texture;
    	}

    return *retVal;
    }

TBool CFsTextParser::IsFieldInrange(TInt aStartPosition, TInt aRange)
    {
    FUNC_LOG;
    TInt siezOfArray = iFieldLocation.Count();

    TBool retVal = EFalse;

    TInt endPosition = aStartPosition + aRange;
    TInt pos;

    for(TInt i = 0 ; i < siezOfArray ; i++)
        {
        pos = iFieldLocation[i];

        if(aStartPosition <= pos && pos <= endPosition)
            {
            retVal = ETrue;
            i = siezOfArray;
            }
        }

    return retVal;
    }

void CFsTextParser::FindBlokOfText()
	{
	if(!iGetCharsUsed)
		{
		iText.GetChars(iGNOSomeText, iGNOCharFormat, iPosition);
		iLastGetCharsPos = iPosition;
		iLastGetCharsLength = iGNOSomeText.Length();
		iGetCharsUsed = ETrue;
		}
	else
		{
		if(iPosition >= iLastGetCharsPos && iPosition < (iLastGetCharsPos + iLastGetCharsLength))
			{
			iGNOSomeText.Set(iText.Read(
									iPosition,
									iLastGetCharsLength - (iPosition - iLastGetCharsPos)));
				
			iLastGetCharsPos = iPosition;
			iLastGetCharsLength = iGNOSomeText.Length();
			}
		else
			{
			if(iPosition == iLastGetCharsPosOfNextBlock)
				{
				iGNOSomeText.Set(iText.Read(iPosition,
							iLastGetCharsLengthOfNextBlock));
				
				iLastGetCharsPos = iPosition;
				iLastGetCharsLength = iGNOSomeText.Length();
				iGNOCharFormat = iGNOCharFormatOfNextBlock;
				}
			else
				{
				iText.GetChars(iGNOSomeText, iGNOCharFormat, iPosition);
				
				iLastGetCharsPos = iPosition;
				iLastGetCharsLength = iGNOSomeText.Length();
				}
			}
		}
	}

void CFsTextParser::FindNextBlokOfText()
	{	
	if(!iGetCharsUsedOfNextBlock)
		{
		iText.GetChars(iGNOSomeTextOfNextBlock, iGNOCharFormatOfNextBlock, iGNONextPosition );		
		iLastGetCharsPosOfNextBlock = iGNONextPosition;
		iLastGetCharsLengthOfNextBlock = iGNOSomeTextOfNextBlock.Length();
		iGetCharsUsedOfNextBlock = ETrue;
		}
	else
		{
		if(iLastGetCharsPosOfNextBlock == iGNONextPosition)
			{
			iGNOSomeTextOfNextBlock.Set(iText.Read(iGNONextPosition,
			iLastGetCharsLengthOfNextBlock));
			}
		else
			{
			iText.GetChars(iGNOSomeTextOfNextBlock, iGNOCharFormatOfNextBlock, iGNONextPosition );
			iLastGetCharsPosOfNextBlock = iGNONextPosition;
			iLastGetCharsLengthOfNextBlock = iGNOSomeTextOfNextBlock.Length();
			}
		}
	}

TInt CFsTextParser::IsNewLinePresent(TInt aPosition, TInt aLength)
	{	
		TInt retVal = -1;
		
		TInt index = 0;
		TInt newLineArrayCount = iNewLineArray.Count();
		
		if(iNewLineArray[iNewLineArrayIndex] < aPosition &&
				iNewLineArray[iNewLineArrayIndex] < (aPosition + aLength))
			{
			for(index = iNewLineArrayIndex ; index < newLineArrayCount - 1 ; ++index)
				{
				TInt alamakota= iNewLineArray[index];
				
				if(iNewLineArray[index] >= aPosition && 
						iNewLineArray[index] < (aPosition + aLength))
					{
					retVal = iNewLineArray[index] - aPosition;
					iNewLineArrayIndex = index;
					index = newLineArrayCount + 1;
					}
				else if(iNewLineArray[index] > aPosition &&
						iNewLineArray[index] > (aPosition + aLength))
					{
					retVal = -1;
					index = newLineArrayCount + 1;
					}
				}
			}
		else
			{
			for(index = iNewLineArrayIndex ; index >= 0  ; --index)
				{
				TInt alamakota= iNewLineArray[index];
							
				if(iNewLineArray[index] >= aPosition && 
						iNewLineArray[index] < (aPosition + aLength))
					{
					retVal = iNewLineArray[index] - aPosition;
					iNewLineArrayIndex = index;
					index = 0;
					}
				else if(iNewLineArray[index] > aPosition &&
						iNewLineArray[index] > (aPosition + aLength))
					{
					retVal = -1;
					index = 0;
					}
				}
			}
		
		return retVal;	
	}


MFsRichTextObject* CFsTextParser::GetNextObjectL()
    {
    MFsRichTextObject* textObject = NULL;
      
    TInt startPos = 0;
    TInt wordLength = 0;
    
    FindBlokOfText();
   
    iGNONextPosition = iPosition + iGNOSomeText.Length(); 
    
    if(iGNONextPosition  < iText.DocumentLength())
    	{
    	FindNextBlokOfText();
    		
    	if(iGNOCharFormat.IsEqual(iGNOCharFormatOfNextBlock))
    		{
    		TBool connect = ETrue;
    		
    		if(iGNOSomeTextOfNextBlock.Length() == 1)
    			{
    			TBuf<1> checkForSpecialChar;
    			_LIT(specialChar, "\xFFFC");
    			
    			iText.Extract(checkForSpecialChar, iGNONextPosition, 1);
    			
    			if(checkForSpecialChar.Right(1).Compare(specialChar) == 0)
    				{
    				connect = EFalse;
    				}
    			}
    		if(iGNOSomeText.Length() == 1)
    			{
    			TBuf<1> checkForSpecialChar;
    			_LIT(specialChar, "\xFFFC");
    			
    			iText.Extract(checkForSpecialChar, iPosition, 1);
    			    			
    			if(checkForSpecialChar.Right(1).Compare(specialChar) == 0)
    				{
    				connect = EFalse;
    				}
    			}
    		
    		if(connect)
    			{
    			TInt l1 = iGNOSomeText.Length();
    			TInt l2 = iGNOSomeTextOfNextBlock.Length();
    		
    			TBuf<121> someCharacter;
    		
    			TInt getTextLength = (l1 + l2) > 120 ? 120 : (l1 + l2);
    		
    			iText.Extract(someCharacter, iPosition, getTextLength);
    		
    			iGNOSomeText.Set(someCharacter.Left(someCharacter.Length()));
    			}
    		}
    	}
    
   	if(iPosition == 0 || iLastPosition != iLastWordPosition || iLastLength < 120)
   		{	
   		iText.GetWordInfo(
            iPosition, 
            startPos, 
            wordLength, 
            EFalse, 
            EFalse);    	
   		iLastLength = wordLength;
   		}
   		
   	if(iGNOSomeText.Length() > 100)
   		{
   		//iGNOSomeText.Set(iText.Read(iPosition,100));
   		iGNOSomeText.Set(iGNOSomeText.Mid(0, 100));
                    
        iLastLength -= 100;
        
        //wordLength = 100;
        //startPos = iPosition;
   		}
   	
   	
   	iLastWordPosition = iPosition;
   	   
   	if ( !wordLength )
   		{
   		wordLength = iNewLengthOfWord != 0 ? iNewLengthOfWord : 0;
   		startPos = iPosition;
   		}
   	   
   	TInt a1 = iGNOSomeText.Length();
   	TInt a2 = startPos + wordLength - iPosition + 1;
   	   
    if(a1 > a2)
        {
        //iGNOSomeText.Set(iText.Read(iPosition,startPos + wordLength - iPosition + 1));
        iGNOSomeText.Set(iGNOSomeText.Mid(0, startPos + wordLength - iPosition + 1));
        }
    
    /*_LIT(endOfFile, "\x2029");
    if(iGNOSomeText.Length() > 0 && iGNOSomeText.Right(1).Compare(endOfFile) == 0)
        {
        iGNOSomeText.Set(iGNOSomeText.Mid(0, iGNOSomeText.Length() - 1));
        }*/
    
    
    if(iIsWordTooLong)
        {
        iIsWordTooLong = EFalse;
        
        if(iGNOSomeText.Length() > iNewLengthOfWord)
            {
            iGNOSomeText.Set(iText.Read(
                    iPosition,
                    iNewLengthOfWord));
            }
        }
    
    //czy text jest elementem expanda
    TInt isWordPartOfExpandArea = IsWordPartOfExpandArea(iPosition, 
                                    iPosition + iGNOSomeText.Length() - 1);
    
    if(-1 != isWordPartOfExpandArea)
        {        
        // Profile
        if(iExpandArray.Count() > isWordPartOfExpandArea && 
            iExpandArray[isWordPartOfExpandArea].iStartIndex > iPosition &&
            iExpandArray[isWordPartOfExpandArea].iStartIndex < 
                            (iPosition + iGNOSomeText.Length() - 1))  
            {
            //w polowie slowa zaczyna sie expand - 
            //nalezy slowo uciac i zajac sie 
            //poczatkowa czescia, ktora nie jest expandem=
            iGNOSomeText.Set( iText.Read(
                iPosition,
                iExpandArray[isWordPartOfExpandArea].iStartIndex 
                  - iPosition ) );
                      
            isWordPartOfExpandArea = -1;
            }
        //wariant 3
        else if(iExpandArray[isWordPartOfExpandArea].iStartIndex + 
            iExpandArray[isWordPartOfExpandArea].iLength >= iPosition 
            && 
            iExpandArray[isWordPartOfExpandArea].iStartIndex + 
            iExpandArray[isWordPartOfExpandArea].iLength < 
            (iPosition + iGNOSomeText.Length() - 1))  
            {
            //poczatek slowa jest expandem 
            //a jego konie nie jest - ten koniec nalezy uciac
            iGNOSomeText.Set(iText.Read(
                        iPosition,
                        iExpandArray[isWordPartOfExpandArea].iStartIndex + 
                        iExpandArray[isWordPartOfExpandArea].iLength - 
                        iPosition));
            }
        }
        
    if(-1 != isWordPartOfExpandArea)
        {
        //Profile
        if(!iExpandArray[isWordPartOfExpandArea].iIsExpand)
            {
            if(iPosition >= 
                    iExpandArray[isWordPartOfExpandArea].iStartIndex + 
                    iExpandArray[isWordPartOfExpandArea].iCaptionLength)
                {              
                iLastPosition = iPosition;
                iPosition = 
                    iExpandArray[isWordPartOfExpandArea].iStartIndex + 
                        iExpandArray[isWordPartOfExpandArea].iLength; 
                
                //jak expand jest do konca textu;
                if(IsNextObject())
                    {
                    return GetNextObjectL();
                    }
                else
                    {
                    textObject = CFsRichTextNewLine::NewL();
                
                    textObject->SetBeginOfObject(iPosition);
                    textObject->SetEndOfObject(iPosition);
                    
                    iLastPosition = iPosition;
                    iPosition += 1;
                    
                    return textObject;
                    }
                }
            
            //expand nie jest rozwiniety dlatego 
            //mozemy przekazac tylko caption
            if(iExpandArray[isWordPartOfExpandArea].iStartIndex + 
                iExpandArray[isWordPartOfExpandArea].iCaptionLength > 
                  iPosition &&
                iExpandArray[isWordPartOfExpandArea].iStartIndex + 
                iExpandArray[isWordPartOfExpandArea].iCaptionLength < 
                iPosition + iGNOSomeText.Length())
                {
                iGNOSomeText.Set(iText.Read(
                        iPosition,
                        iExpandArray[isWordPartOfExpandArea].iStartIndex + 
                        iExpandArray[isWordPartOfExpandArea].iCaptionLength 
                        - iPosition));
                }
            }
//        if ( Profiling2( &iGNOSomeText, &isWordPartOfExpandArea, textObject ) )
//            {
//            return GetNextObjectL();
//            }
        }
    
    TInt isWordPartOfHotSpotArea =
        IsWordPartOfHotSpotArea(
                iPosition, 
                iPosition + iGNOSomeText.Length() - 1);
        
    if(-1 != isWordPartOfHotSpotArea 
            && iHotSpotArray.Count() > isWordPartOfHotSpotArea)
        {
        if(iHotSpotArray[isWordPartOfHotSpotArea].iStartIndex > iPosition &&
            iHotSpotArray[isWordPartOfHotSpotArea].iStartIndex < 
            (iPosition + iGNOSomeText.Length() - 1))  
            {
            //w polowie slowa zaczyna sie expand - 
            //nalezy slowo uciac i zajac sie 
            //poczatkowa czescia, ktora nie jest expandem=
            iGNOSomeText.Set( iText.Read(
                iPosition,
                iHotSpotArray[isWordPartOfHotSpotArea].iStartIndex 
                    - iPosition ) );
                          
            isWordPartOfHotSpotArea = -1;
            }
            //wariant 3
        else if(iHotSpotArray[isWordPartOfHotSpotArea].iStartIndex + 
            iHotSpotArray[isWordPartOfHotSpotArea].iLength >= iPosition && 
            iHotSpotArray[isWordPartOfHotSpotArea].iStartIndex + 
            iHotSpotArray[isWordPartOfHotSpotArea].iLength < 
            (iPosition + iGNOSomeText.Length() - 1))  
            {
            //poczatek slowa jest expandem 
            //a jego konie nie jest - ten koniec nalezy uciac
            iGNOSomeText.Set(iText.Read(
                iPosition,
                iHotSpotArray[isWordPartOfHotSpotArea].iStartIndex + 
                iHotSpotArray[isWordPartOfHotSpotArea].iLength - iPosition));
            } 
        }
    
    TFindFieldInfo info;
    
    TInt dx = iGNOSomeText.Length(); 
    
    if(iPosition + dx > iText.DocumentLength())
        {
        dx = iText.DocumentLength() - iPosition - 1;
        }
    
    //is new line in iGNOSomeText
    
    TInt positionOfNewLine = IsNewLinePresent(iPosition, iGNOSomeText.Length());
    TBool isNewLinePresent = EFalse;

    if( positionOfNewLine > -1 )
    	{
    	if(positionOfNewLine == 0)
    		{
    		isNewLinePresent = ETrue;
    		iGNOSomeText.Set(iGNOSomeText.Mid(0, 1));
    		}
    	else
    		{
    		iGNOSomeText.Set(iGNOSomeText.Mid(0, positionOfNewLine));
    		}
    	}
    
    if(IsFieldInrange(iPosition, dx) && iText.FindFields(info, iPosition, dx))
        {
        if(iPosition != info.iFirstFieldPos)
            {
            iGNOSomeText.Set(iText.Read(
                        iPosition, 
                        info.iFirstFieldPos - iPosition));
            textObject = static_cast<MFsRichTextObject*>
                (CFsRichTextText::NewL(iGNOSomeText, 0));
            CleanupStack::PushL(textObject);
            TInt styleId = iTextStyleManager->GetStyleIDL(iGNOCharFormat);
            ((CFsRichTextText*)textObject)->SetStyleId(styleId);
            
            textObject->SetBeginOfObject(iPosition);
            textObject->SetEndOfObject(iPosition + iGNOSomeText.Length() - 1);    
            
            ((CFsRichTextText*)textObject)->SetTextColor(
                iGNOCharFormat.iFontPresentation.iTextColor );
            
            iLastPosition = iPosition;
            iPosition += iGNOSomeText.Length();
            CleanupStack::Pop(textObject);
            }
        else
            {
            //pobrac fielda
            const CTextField* field = iText.TextField(iPosition);
            
            if(KFsRichTextPictureFieldUid == field->Type())
                {        
                TPictureHeader header = iText.PictureHeader(iPosition);
                
                CMyPicture* picture = 
                    static_cast<CMyPicture*>(header.iPicture.AsPtr() );
                
                textObject = CFsRichTextPicture::NewL();
                
                TSize sizeOfPicture = TSize( 0, 0 );
                picture->GetOriginalSizeInTwips( sizeOfPicture );
                
                static_cast< CFsRichTextPicture* >
                    (textObject)->SetTextureSize(sizeOfPicture);
                
                textObject->SetBeginOfObject(iPosition);
                textObject->SetEndOfObject(iPosition);
                
                iLastPosition = iPosition;
                iPosition += 1;
                }           
            else if(KFsRichTextSmileyFieldUid == field->Type())
                {
                TInt smileyIndex = ((CSmileyField*)(field))->GetSmileyIndex();
                
                iGNOSomeText.Set(iText.Read(
                            iPosition, 
                            iSmileyParser->GetSmileyLength(smileyIndex)));
                                  
                CFsRichTextText* smileyTextObject = 
                    CFsRichTextText::NewL(iGNOSomeText, 0);
                CleanupStack::PushL(smileyTextObject); 
                smileyTextObject->SetTextColor(
                        iGNOCharFormat.iFontPresentation.iTextColor );
                
                TInt styleId = iTextStyleManager->GetStyleIDL(iGNOCharFormat);
                ((CFsRichTextText*)smileyTextObject)->SetStyleId(styleId);
                
                TFileName fileName = 
                    iSmileyParser->GetSmileyFileName(smileyIndex);
                
                TInt textureId = 0;
                TSize texturesize = TSize( 0, 0 );
                if(IsTexturePosition(iPosition, textureId))
                	{
                	CFsTexture* texture = iTextureLoader->SearchById(textureId);
                	texturesize = texture->Texture().Size();
                	}
                else
                	{
                	CFsTexture& texture = iTextureLoader->LoadTextureL( fileName );
                	
                	TTextureIndex newTextureIndex;
                	newTextureIndex.iPositionInText = iPosition;
                	newTextureIndex.iTextureId = texture.Id();
                	
                	iTextureIndex.Append(newTextureIndex);
                	
                	texturesize = texture.Texture().Size();
                	}
                
                CFsRichTextPicture* smileyPictureObject = 
                    CFsRichTextPicture::NewL();
                CleanupStack::PushL(smileyPictureObject);
                if(iIsSetSizeOfSmiley)      
                    {
                    texturesize = iSizeOfSmiley;
                    }
                else if ( texturesize == TSize( 0, 0 ) )
                    {
                    TFrameInfo frameInfo;

                    CFsTextureLoader::GetFrameInfoL( 
                    		fileName,
                            frameInfo );
                    texturesize = frameInfo.iOverallSizeInPixels;
                    TSize texturesize = TSize( 10, 10 ); 
                    }

                static_cast< CFsRichTextPicture* >
                    (smileyPictureObject)->SetTextureSize( texturesize );
                
                textObject = CFsRichTextSmiley::NewL(
                        smileyTextObject, 
                        smileyPictureObject);
                
                CleanupStack::Pop(smileyPictureObject);
                CleanupStack::Pop(smileyTextObject);
                textObject->SetBeginOfObject(iPosition);
                textObject->SetEndOfObject(iPosition + iGNOSomeText.Length() - 1);
                
                iLastPosition = iPosition;
                iPosition += iGNOSomeText.Length();     
                }
            }
        }
    else
        {
        if(isNewLinePresent)
        	{
        	textObject = CFsRichTextNewLine::NewL();
                
            textObject->SetBeginOfObject(iPosition);
            textObject->SetEndOfObject(iPosition);
                
            iLastPosition = iPosition;
            iPosition += 1; 
        	}
        else
        	{
        	textObject = static_cast<MFsRichTextObject*>
                    (CFsRichTextText::NewL(iGNOSomeText, 0));
            CleanupStack::PushL(textObject); 
        	TInt styleId = iTextStyleManager->GetStyleIDL(iGNOCharFormat);
        	((CFsRichTextText*)textObject)->SetStyleId(styleId);
            
        	textObject->SetBeginOfObject(iPosition);
        	textObject->SetEndOfObject(iPosition + iGNOSomeText.Length() - 1);
            
        	((CFsRichTextText*)textObject)->SetTextColor(
            	iGNOCharFormat.iFontPresentation.iTextColor );    
            
        	TBidiText * bidiText = TBidiText::NewL(iGNOSomeText.Length() + 1, 1); 
        
        	TBool found = EFalse;
        
        	TBidiText::TDirectionality direction = bidiText->TextDirectionality(iGNOSomeText, &found );
        
        	// <cmail>
        	if ( !found )
        	    {
        	    direction = AknLayoutUtils::LayoutMirrored() ?
        	    	TBidiText::ERightToLeft : TBidiText::ELeftToRight;
        	    }
        	// </cmail>

        	static_cast<CFsRichTextText*>(textObject)->SetTextDirection(direction);
        
	        delete bidiText;
	        
	        TInt sizeOfSomeText = iGNOSomeText.Length();
	        TBool isWhiteSpace = ETrue;
	        for(TInt k = 0 ; k < sizeOfSomeText ; ++k)
	        	{
	        	if(iGNOSomeText[k] != ' ')
	        		{
	        		isWhiteSpace = EFalse;
	        		k = sizeOfSomeText + 1;
	        		}
	        	}
	            
	        textObject->SetIsWhiteSpace(isWhiteSpace);
	            
	        iLastPosition = iPosition;
	        iPosition += iGNOSomeText.Length();
	        
	        CleanupStack::Pop(textObject);
	        }     
        }
    
    if(-1 != isWordPartOfHotSpotArea)
        {
        textObject->SetHotSpot( ETrue );
        textObject->SetIdOfHotSpot(isWordPartOfHotSpotArea);
        textObject->SetTypeOfHotSpot(
                iHotSpotArray[isWordPartOfHotSpotArea].iId );
        }
    
    if(-1 != isWordPartOfExpandArea)
        {
        textObject->SetEmbeded( ETrue );
        textObject->SetIdOfEmbeded(isWordPartOfExpandArea);
        }
    
    return textObject;
    }

void CFsTextParser::SetTextStylemanager(
        CFsTextStyleManager* aTextStyleManager )
    {
    FUNC_LOG;
    iTextStyleManager = aTextStyleManager;
    }

void CFsTextParser::ConvertBitmapL(CPicture* aPicture, CFbsBitmap*& aBitmap)
    {
    FUNC_LOG;
    TSize size;
    aPicture->GetOriginalSizeInTwips(size);
    aBitmap = new (ELeave)CFbsBitmap;

    size.iWidth = 45;
    size.iWidth = 45;

    User::LeaveIfError(aBitmap->Create(size,EColor256));
    CleanupStack::PushL(aBitmap);

    //create an offscreen device and context
    CGraphicsContext* bitmapContext = NULL;
    CFbsBitmapDevice* bitmapDevice = CFbsBitmapDevice::NewL(aBitmap);
    CleanupStack::PushL(bitmapDevice);
    User::LeaveIfError(bitmapDevice->CreateContext(bitmapContext));
    CleanupStack::PushL(bitmapContext);

    aPicture->Draw(
            *bitmapContext,
            TPoint(0,0),
            TRect( TPoint(0,0),TPoint(45,45) ),
            bitmapDevice);

    CleanupStack::PopAndDestroy(bitmapContext);
    CleanupStack::PopAndDestroy(bitmapDevice);
    CleanupStack::Pop(aBitmap);
    }



TInt CFsTextParser::IsWordPartOfHotSpotArea(
        TInt aStartPosition,
        TInt aEndPosition )
    {
    FUNC_LOG;
    TInt retVal = -1;

    for(TInt i = 0 ; i < iHotSpotArray.Count() ; ++i)
        {
        /*
        TRichTextHotSpotArea test;
        test.iLength = iHotSpotArray[i].iLength;
        test.iStartIndex = iHotSpotArray[i].iStartIndex;
        */

        if(iHotSpotArray[i].iStartIndex >= aStartPosition &&
            iHotSpotArray[i].iStartIndex < aEndPosition)
            {
            if(-1 == retVal)
                {
                retVal = i;
                }
            else
                {
                if ( iHotSpotArray[i].iStartIndex
                        < iHotSpotArray[retVal].iStartIndex )
                    {
                    retVal = i;
                    }
                }
            }
        else if ( aStartPosition >= iHotSpotArray[i].iStartIndex
                && aStartPosition
                   < iHotSpotArray[i].iStartIndex
                      + iHotSpotArray[i].iLength )
            {
            if(-1 == retVal)
                {
                retVal = i;
                }
            else
                {
                if ( iHotSpotArray[i].iStartIndex
                        < iHotSpotArray[retVal].iStartIndex )
                    {
                    retVal = i;
                    }
                }
            }
        }
    return retVal;
    }




TBool CFsTextParser::IsNextObject() const
    {
    FUNC_LOG;

    TInt documentLength = iText.DocumentLength() - 1;
    TBool retVal = EFalse;

    if(documentLength < iPosition)
        {
        retVal = EFalse;
        }
    else
        {
        retVal = ETrue;
        }

    return retVal;
    }

TBool CFsTextParser::MoveParsingPosition( TInt aMoveParsingPositionBy )
    {
    FUNC_LOG;
    TBool retVal = ETrue;

    if( (iPosition + aMoveParsingPositionBy) < 0 ||
        (iPosition + aMoveParsingPositionBy) >= iText.DocumentLength())
        {
        retVal = EFalse;
        }
    else
        {
        iPosition += aMoveParsingPositionBy;
        }

    return retVal;
    }



TBool CFsTextParser::ParseTextL()
    {
    FUNC_LOG;
        TBool retVal = ETrue;

    TInt textLength = iText.DocumentLength();

    TBuf<1> someCharacter;

    _LIT(fourSpaces, "    ");
    _LIT(validNewLine, "\n");


    _LIT(newLine1, "\x2028");
    _LIT(newLine2, "\x2029");
    _LIT(newLine3, "\x85");
    _LIT(newLine4, "\x0D");

    _LIT(tabulator,"\x2007");

    for(TInt i = 0 ; i < iText.GetNumberOfExpandAreas() ; ++i)
        {
        iExpandArray.AppendL(iText.GetExpandAreaL(i));
        }

    for(TInt i = 0 ; i < iText.GetNumberOfHotSpotAreas() ; ++i)
        {
        iHotSpotArray.AppendL(iText.GetHotSpotAreaL(i));
        }

    textLength = iText.DocumentLength();
    for(TInt i = 0 ; i < textLength ; ++i)
        {
        iText.Extract(someCharacter, i, 1);

        if(someCharacter[0] == '\t')
            {
            iText.DeleteL(i,1);
            iText.InsertL(i,fourSpaces);

            textLength = iText.DocumentLength();

            for(TInt j = 0 ; j < iText.GetNumberOfExpandAreas() ; ++j)
                {
                if(iExpandArray[j].iStartIndex > i)
                    {
                    iExpandArray[j].iStartIndex += 3;
                    }
                }

            for(TInt j = 0 ; j < iText.GetNumberOfHotSpotAreas() ; ++j)
                {
                if(iHotSpotArray[j].iStartIndex <= i &&
                   iHotSpotArray[j].iStartIndex + iHotSpotArray[j].iLength > i)
                    {
                    iHotSpotArray[j].iLength += 3;
                    }
                if(iHotSpotArray[j].iStartIndex > i)
                    {
                    iHotSpotArray[j].iStartIndex += 3;
                    }
                }

            ++i;
            }
        else if(someCharacter.Right(1).Compare(tabulator) == 0)
            {
            iText.DeleteL(i,1);
            iText.InsertL(i,fourSpaces);

            textLength = iText.DocumentLength();
            ++i;
            }
        else if(someCharacter.Right(1).Compare(validNewLine) == 0)
        	{
        	TBuf<1> anotherCharacter;
        	if ( iText.DocumentLength() > ( i + 1 ) )
        		{
        		iText.Extract(anotherCharacter, i + 1, 1);

        		if( anotherCharacter.Right(1).Compare(newLine3) == 0 ||
        			anotherCharacter.Right(1).Compare(newLine4) == 0 )
        			{
        			iText.DeleteL( i, 2 );
        			iText.InsertL( i, validNewLine );
        			iText.InsertL( i, _L(" ") );

        			textLength = iText.DocumentLength();
        			}
        		}
        	}
        }

    textLength = iText.DocumentLength();
    TInt lastNewLine = 0;
    TPtrC someText;

    for(TInt i = 0 ; i < textLength ; ++i)
        {
        iText.Extract(someCharacter, i, 1);

        if(someCharacter.Right(1).Compare(validNewLine) == 0 ||
        		someCharacter.Right(1).Compare(newLine1) == 0 || 
        		someCharacter.Right(1).Compare(newLine2) == 0 ||
        		someCharacter.Right(1).Compare(newLine3) == 0 ||
        		someCharacter.Right(1).Compare(newLine4) == 0
                || i == textLength - 1 
                )  
            {
            iNewLineArray.AppendL(i);

            someText.Set(iText.Read(
                    lastNewLine,
                    i - lastNewLine));

            // <cmail>
            TInt partOfHotspotArea = IsWordPartOfHotSpotArea(
                    lastNewLine,
                    i);
            // </cmail>

            lastNewLine = i;

            TBidiText * bidiText = TBidiText::NewL(someText.Length() + 1, 1);

        	TBool found = EFalse;

        	TBidiText::TDirectionality direction = bidiText->TextDirectionality(someText, &found );

	        delete bidiText;

	        // <cmail>
	        if (!found || partOfHotspotArea != -1)
	            {
	            direction = AknLayoutUtils::LayoutMirrored() ? TBidiText::ERightToLeft : TBidiText::ELeftToRight;
	            }
	        // </cmail>

	        iLineDirection.AppendL(direction);
            }
        }


    for(int i = 0 ; i < textLength ; ++i)
        {
            iText.Extract(someCharacter, i, 1);

            if(!iSmileyParser->IsPartOfSmileyL(someCharacter))
                {
                if(iSmileyParser->IsSmiley())
                    {
                    TInt smileysIndex = iSmileyParser->GetSmileyIndex();
                    CTextField* field =
                        (CTextField*)new(ELeave)CSmileyField(smileysIndex);

                    TInt smileysLength =
                        iSmileyParser->GetSmileyLength(smileysIndex);
                    iText.InsertFieldL(
                            i-smileysLength,
                            field,
                            KFsRichTextSmileyFieldUid);

                    iFieldLocation.Append(i-smileysLength);
                    }
                }

            if(someCharacter[0] == CRichText::EPictureCharacter)
                {
                CTextField* field = (CTextField*)
                    new(ELeave)CPictureField(TSize(50,50));
                iText.InsertFieldL(i, field, KFsRichTextPictureFieldUid);

                iFieldLocation.Append(i);
                }
        }

    return retVal;
    }

TBool CFsTextParser::IsPartOfHotSpot(TInt aIndex)
    {
    FUNC_LOG;
    TBool retVal = EFalse;

    for(TInt i = 0 ; i < iHotSpotArray.Count() ; ++i)
        {
        if ( aIndex > iHotSpotArray[i].iStartIndex
            && aIndex <
              iHotSpotArray[i].iStartIndex
              + iHotSpotArray[i].iLength
              - 1 )
            {
            retVal = ETrue;
            break;
            }
        }

    return retVal;
    }

void CFsTextParser::SetSmileyParser(CFsSmileyParser* aSmileyParser)
    {
    FUNC_LOG;
    iSmileyParser = aSmileyParser;
    }

TBool CFsTextParser::SetExpandStatusL(TInt aIdOfExpand, TBool aStatus)
    {
    FUNC_LOG;
    TBool retVal = ETrue;

    if(aIdOfExpand >= iExpandArray.Count())
        {
        User::Leave(KErrArgument);
        }

    iExpandArray[aIdOfExpand].iIsExpand = aStatus;

    return retVal;
    }

TInt CFsTextParser::GetEndIndexOfExpandAreaL(TInt aId)
    {
    FUNC_LOG;
    if(aId >= iExpandArray.Count())
        {
        User::Leave(KErrArgument);
        }

    return iExpandArray[aId].iStartIndex + iExpandArray[aId].iLength - 1;
    }

TInt CFsTextParser::GetStartIndexOfExpandAreaL(TInt aId)
    {
    FUNC_LOG;
    if(aId >= iExpandArray.Count())
        {
        User::Leave(KErrArgument);
        }

    return iExpandArray[aId].iStartIndex;
    }

TInt CFsTextParser::GetBodyIndexOfExpandAreaL(TInt aId)
    {
    FUNC_LOG;
    if(aId >= iExpandArray.Count())
        {
        User::Leave(KErrArgument);
        }

    return
        iExpandArray[aId].iStartIndex
        + iExpandArray[aId].iCaptionLength - 1;
    }

TInt CFsTextParser::GetEndIndexOfHotSpotAreaL(TInt aId, TBool aOriginal)
    {
    FUNC_LOG;
    if(aId >= iHotSpotArray.Count())
        {
        User::Leave(KErrArgument);
        }

    TInt retVal;

    retVal = aOriginal
        ? iHotSpotArray[aId].iOriginalStartIndex + iHotSpotArray[aId].iOriginalLength - 1
        : iHotSpotArray[aId].iStartIndex + iHotSpotArray[aId].iLength - 1;

    return retVal;
    }

TInt CFsTextParser::GetStartIndexOfHotSpotAreaL(TInt aId, TBool aOriginal)
    {
    FUNC_LOG;
    if(aId >= iHotSpotArray.Count())
        {
        User::Leave(KErrArgument);
        }

    TInt retVal = aOriginal
        ? iHotSpotArray[aId].iOriginalStartIndex
        : iHotSpotArray[aId].iStartIndex;

    return retVal;
    }

CFsRichText* CFsTextParser::GetRichTextL(TInt aBeginIndex, TInt aEndIndex)
    {
    FUNC_LOG;
    CFsRichText* fsRichText = CFsRichText::NewL(
            iEikon->SystemParaFormatLayerL(),
            iEikon->SystemCharFormatLayerL());

    TBuf<1> c;

    TCharFormat charFormat;
    TCharFormatMask charMask;

    if(aBeginIndex < 0 || aBeginIndex > iText.DocumentLength() ||
                aEndIndex < 0 || aEndIndex > iText.DocumentLength())
        {
        User::Leave(KErrArgument);
        }

    for(TInt i = aBeginIndex ; i < aEndIndex ; ++i )
        {
        iText.Extract( c, i, 1 );

        TRAPD(err, fsRichText->InsertL(i,c));
        if(err == KErrNone)
            {
            iText.GetSpecificCharFormat(charFormat,charMask,i);
            fsRichText->SetInsertCharFormatL(charFormat,charMask,i);
            }
        }

    return fsRichText;
    }

TBidiText::TDirectionality CFsTextParser::GetParagraphDirection(TInt aPosInText)
	{
    FUNC_LOG;
	/*if(aPosInText > iText.DocumentLength())
        {
        User::Leave(KErrArgument);
        }

    if(iNewLineArray.Count() <= 0 || (iNewLineArray.Count() != iLineDirection.Count()))
    	{
    	User::Leave(KErrArgument);
    	}*/

    // <cmail>
    TBidiText::TDirectionality retVal = AknLayoutUtils::LayoutMirrored() ? TBidiText::ERightToLeft : TBidiText::ELeftToRight;
    // </cmail>

    //TBool found = EFalse;

    TInt newLineArrayCount = iNewLineArray.Count();
    TInt lastNewLinePosition = 0;
    if( aPosInText > iNewLineArray[iLastNewLinePositionIndex] )
    	{		
			return iLineDirection[iLastNewLinePositionIndex + 1];
    	}
    for(TInt i = 0 ; i < newLineArrayCount ; ++i)	
    	{
    	if(lastNewLinePosition <= aPosInText && iNewLineArray[i] >= aPosInText)
    		{
    		retVal = iLineDirection[i];
    		iLastNewLinePositionIndex = i;
			break;
    		}

    		lastNewLinePosition = iNewLineArray[i];
    	}

    /*if(!found)
    	{
    	User::Leave(KErrArgument);
    	}*/

    return retVal;
	}

TBool CFsTextParser::SetTextDirection(TInt aStartPosInText, TInt aEndPosInText,
        				TBidiText::TDirectionality aDirection)
	{
    FUNC_LOG;
	TInt indexOfStart = 0;
	TInt indexOfEnd = 0;

	TInt tableCount = iNewLineArray.Count();

	for(TInt i = 0 ; i < tableCount ; ++i)
		{
		TInt ala = iNewLineArray[i];

		if(iNewLineArray[i] >= aStartPosInText)
			{
			indexOfStart = i;
			i = tableCount + 1;
			}
		}

	for(TInt i = indexOfStart ; i < tableCount ; ++i)
		{
		TInt ala = iNewLineArray[i];

		if(iNewLineArray[i] >= aEndPosInText)
			{
			indexOfEnd = i;
			i = tableCount + 1;
			}
		}

	if(indexOfEnd == indexOfStart)
		{
		iNewLineArray.Insert(aStartPosInText, indexOfStart);
		iNewLineArray.Insert(aEndPosInText, indexOfStart + 1);

		TBidiText::TDirectionality direction = iLineDirection[indexOfEnd];

		iLineDirection.Insert(direction, indexOfStart);
		iLineDirection.Insert(aDirection, indexOfStart + 1);
		}
	else
		{
		iNewLineArray.Insert(aEndPosInText, indexOfEnd);
		iNewLineArray.Insert(aStartPosInText, indexOfStart);

		for(TInt i = indexOfEnd ; i > indexOfStart ; --i)
			{
			iNewLineArray.Remove(i);
			}

		TBidiText::TDirectionality direction = iLineDirection[indexOfStart];

		iLineDirection.Insert(aDirection, indexOfEnd);
		iLineDirection.Insert(direction, indexOfStart);

		for(TInt i = indexOfEnd ; i > indexOfStart ; --i)
			{
			iLineDirection.Remove(i);
			}
		}
	if(0 == aStartPosInText)
		{
		iLineDirection[indexOfStart] = aDirection;
		}
	return ETrue;
	}

TBool CFsTextParser::IsTexturePosition(TInt aPos, TInt &aId)
	{
	TBool retVal = EFalse;

	TInt tableCount = iTextureIndex.Count();

	for(TInt i = 0 ; i < tableCount ; ++i)
		{
		TInt texturePosition = iTextureIndex[i].iPositionInText;

		if(aPos == texturePosition)
			{
			retVal = ETrue;
			aId = iTextureIndex[i].iTextureId;
			i = tableCount + 1;
			}
		}

	return retVal;
	}
