/*
* Copyright (c) 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:  
*       CUniSmilModel, Storage for Smil presentation data.
*
*/



// ========== INCLUDE FILES ================================


#include <e32def.h>
#include <eikenv.h>
#include <eikfutil.h>               // CopyFile

#include <mtclbase.h>   // for CBaseMtm
#include <msvstd.h>     // for TMsvId
#include <msvids.h>     // for KMsvTempIndexEntryId
#include <msvstore.h>
#include <mmsvattachmentmanager.h>
#include <mmsvattachmentmanagersync.h>
#include <cmsvattachment.h>

#include <bautils.h>                // NearestLanguageFile

#include <coemain.h>

#include <MuiuMsvUiServiceUtilities.h>  //Disk space check

// LAF
#include <AknUtils.h>
#include <aknlayoutscalable_avkon.cdl.h>
#include <aknlayoutscalable_apps.cdl.h>
#include <layoutmetadata.cdl.h>

// DOM
#include <gmxmldocument.h>
#include <gmxmlnode.h>
#include <gmxmlelement.h>

// MsgMedia
#include <MsgMedia.hrh>
#include <MsgMediaInfo.h>
#include <MmsConformance.h>
#include <mmsversion.h>
#include <MsgTextInfo.h>
#include <MsgMimeTypes.h>

#include <fileprotectionresolver.h>     //     EFileProtDrm2

// MsgDataUTILS
#include <UniDataModel.rsg>             // Viewer/Editor Mimetype strings
#include "UniModelConst.h"              // Definitions and enums
#include "UniDataUtils.h"
#include "UniSmilSlide.h"
#include "UniSmilModel.h"
#include "UniObjectList.h"
#include "UniObject.h"
#include "UniTextObject.h"
#include "UniMimeInfo.h"
#include "UniSmilUtils.h"
#include "UniSmilParams.h"

// Logging
//#include "//MsgDataUTILSLOGGing.h"


// ========== EXTERNAL DATA STRUCTURES =====================

// ========== EXTERNAL FUNCTION PROTOTYPES =================

// ========== CONSTANTS ====================================

// ========== MACROS =======================================

// ========== LOCAL CONSTANTS AND MACROS ===================

_LIT( KSmilIntFormat, "%d" );
_LIT( KSmilMsecFormat, "%dms" );
const TUint KSlideArrayGranularity( 16 );

// SMIL size estimates
const TInt KSizeMandatorySmilTags = 148;
const TInt KSizeHeadOneRegion = 85;
const TInt KSizeHeadTwoRegions = 170;
const TInt KSizeEmptyPar = 27;
const TInt KSizeNonEmptyPar = 41;
const TInt KSizeAudioTag = 38;
const TInt KSizeImageTag = 52;
const TInt KSizeTextTag = 51;
const TInt KSizeVideoTag = 53;

const TInt KSizeLowResHeight = 208;
const TInt KSizeLowResWidth = 176;

// ========== MODULE DATA STRUCTURES =======================

// ========== LOCAL FUNCTION PROTOTYPES ====================

// ========== LOCAL FUNCTIONS ==============================

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


// ---------------------------------------------------------
// CUniSmilModel::NewL
//
// Factory method.
// ---------------------------------------------------------
//
EXPORT_C CUniSmilModel* CUniSmilModel::NewLC( RFs& aFs,
                                             CBaseMtm& aMtm,
                                             CUniDataUtils& aData,
                                             CUniObjectList& aObjectList )
    {
    CUniSmilModel* self = new ( ELeave )
        CUniSmilModel( aFs, aMtm, aData, aObjectList );

    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }


// ---------------------------------------------------------
// CUniSmilModel::NewL
//
// Factory method.
// ---------------------------------------------------------
//
EXPORT_C CUniSmilModel* CUniSmilModel::NewL( RFs& aFs,
                                            CBaseMtm& aMtm,
                                            CUniDataUtils& aData,
                                            CUniObjectList& aObjectList )
    {
    CUniSmilModel* self = NewLC( aFs, aMtm, aData, aObjectList );
    CleanupStack::Pop( self );
    return self;
    }


// ---------------------------------------------------------
// CUniSmilModel::CUniSmilModel
//
// Constructor.
// ---------------------------------------------------------
//
CUniSmilModel::CUniSmilModel( RFs& aFs,
                             CBaseMtm& aMtm,
                             CUniDataUtils& aData,
                             CUniObjectList& aObjectList ) :
    iFs( aFs ),
    iMtm( aMtm ),
    iData( aData ),
    iObjectList( aObjectList ),
    iSlideLayout( EUniUndefinedLayout ),
    iSmilParams( 0 ),
    iScreenSize( 0, 0 ),
    iSizeEstimateUpToDate( EFalse ),
    iSizeEstimate( 0 )
    {
    }

// ---------------------------------------------------------
// CUniSmilModel::~CUniSmilModel
//
// Destructor.
// ---------------------------------------------------------
//
CUniSmilModel::~CUniSmilModel()
    {   
    if (iSlideArray)
        {
        iSlideArray->ResetAndDestroy();
        }
    delete iSlideArray;
    delete iSmilParams;
    }

// ---------------------------------------------------------
// CUniSmilModel::ParseL
// 
// ---------------------------------------------------------
//
EXPORT_C TInt CUniSmilModel::ParseL( CMDXMLDocument* aDom )
    {
    //MsgDataUTILSLOGGER_ENTERFN( "CUniSmilModel::ParseL()" );

    Reset();

    if ( aDom )
        {
        TRAPD( error, DoPresentationFromDomL( aDom ) );
        if ( error )
            {
            Reset();
            User::Leave( error );
            }
        else
            {
            iParseResult |= EParsedFromSmil;
            }
        }
    else
        {
        //  No SMIL -> Do presentation from object list
        if ( IsMessageSlide() ) 
            {
            // Determine layout. Make slide. 
            DoNoSmilOneSlideL();
            }
        else 
            {
            // Do slide for each media object
            DoNoSmilManySlideL();
            }
        iParseResult |= EParsedFromList;
        }

    return iParseResult;
    }


//**********************************************************
//*
//* SMIL COMPOSING FUNCTIONS
//*
//**********************************************************


// ---------------------------------------------------------
// CUniSmilModel::¨ComposeL
//
// ---------------------------------------------------------
//
EXPORT_C CMDXMLDocument* CUniSmilModel::ComposeL()
    {
    //MsgDataUTILSLOGGER_ENTERFN( "CUniSmilModel::ComposeL()" );

    // Reset region id's
    iTextRegionId.Set( KNullDesC );
    iImageRegionId.Set( KNullDesC );

    // Read default smil parameters
    if( !iSmilParams )
        {
        //MsgDataUTILSLOGGER_WRITE( "CUniSmilModel: Creating smil parameter structures." );
        iSmilParams = CUniSmilParams::NewL( iFs );
        }

    //MsgDataUTILSLOGGER_WRITE( "CUniSmilModel: Creating new DOM." );
    //delete iDom;
    //iDom = 0;
    CMDXMLDocument* dom = CMDXMLDocument::NewLC();

    // Create smil node
    TPtrC name( KSMILWREleSmil );
    CMDXMLElement* root = CMDXMLElement::NewLC( ETrue, dom, name );
    // Append
    dom->DocumentElement()->AppendChild( root ); // Ownership to dom
    CleanupStack::Pop( root );

    // Create Head
    CreateHeadL( dom, root );

    // Create Body
    CreateBodyL( dom, root );

    // TODO: Move to Document and to use smil list
    //iObjectList.CreateSmilAttachmentL( smilAttaId, iDom, iFs );
    CleanupStack::Pop( dom );
    return dom;
    }



// ---------------------------------------------------------
// CUniSmilModel::RemoveEmptySlides
//
//
// ---------------------------------------------------------
//
EXPORT_C void CUniSmilModel::RemoveEmptySlides()
    {
    TInt count = iSlideArray->Count();
    // Must be done from end to beginning because
    // slides might be removed.
    while ( count-- )
        {
        if ( !iSlideArray->At( count )->ObjectCount() )
            {
            RemoveSlide( count );
            }
        }
    }


// ---------------------------------------------------------
// CUniSmilModel::AddSlideL
//
//
// ---------------------------------------------------------
//
EXPORT_C void CUniSmilModel::AddSlideL( TInt aSlideNum )
    {
    DoAddSlideL( aSlideNum );
    }

// ---------------------------------------------------------
// CUniSmilModel::RemoveSlide
//
//
// ---------------------------------------------------------
//
EXPORT_C void CUniSmilModel::RemoveSlide( TInt aSlideNum )
    {
    if ( !IsSlide( aSlideNum ) )
        {
        //__ASSERT_DEBUG( EFalse, DataUtilsPanic( EMmsNotASlide ) );
        return;
        }
    CUniSmilSlide* slide = iSlideArray->At( aSlideNum );
    if ( slide->ObjectCount() )
        {
        //__ASSERT_DEBUG( EFalse, DataUtilsPanic( EMmsSlideNotEmpty ) );
        return;
        }
    
    iSlideArray->Delete( aSlideNum );
    delete slide;
    //MsgDataUTILSLOGGER_WRITE( "CUniSmilModel: Empty slide removed." );
    iSizeEstimateUpToDate = EFalse;
    }

// ---------------------------------------------------------
// CUniSmilModel::MoveSlideL
//
//
// ---------------------------------------------------------
//
EXPORT_C void CUniSmilModel::MoveSlideL( TInt aSlideToMove, TInt aPlaceToMove ) 
    {
    TInt slideCount = iSlideArray->Count();
    if ( !slideCount
        || aSlideToMove < 0
        || aSlideToMove >= slideCount
        || aSlideToMove == aPlaceToMove )
        {
        return;
        }
    TInt place = Min( Max( 0, aPlaceToMove ), slideCount - 1 );
    CUniSmilSlide* slide = iSlideArray->At( aSlideToMove );

    iSlideArray->Delete( aSlideToMove );
    iSlideArray->InsertL( place, slide );
    iSizeEstimateUpToDate = EFalse;
    }

// ---------------------------------------------------------
// SortSlidesL
// 
// Sorts slides accoring to a separate comparison function
// called SortSlidesCompare().
//
// Insertion sort algorithm.
//
// Notice! Intended to be used with SendAs when there
// are multiple slides - each slide containing only 
// one object
// ---------------------------------------------------------
EXPORT_C void CUniSmilModel::SortSlidesL() 
    {
    TInt i = 1; // index 1, i.e. second slide
    TInt count = SlideCount();
    while ( i < count )
        {
        CUniSmilSlide* slide1 = iSlideArray->At( i );
        TInt j = i - 1;
        while ( j >= 0 )
            {
            CUniSmilSlide* slide2 = iSlideArray->At( j );
            if ( SortSlidesCompare( slide1, slide2 ) > 0 )
                {
                break;
                }
            j--;
            }
        j++;
        if ( j < i )
            {
            // slide1 was not in the right place
            iSlideArray->Delete( i );
            iSlideArray->InsertL( j, slide1 );
            }
        i++;
        }
    iSizeEstimateUpToDate = EFalse;
    }


// ---------------------------------------------------------
// SortSlidesCompare
//
// Compares slides according to time. Most recent is greatest.
//
// Empty slides are greater than non-empty slides.
// If aSlide1 "is greater than" aSlide2 returns positive value.
// If aSlide1 "is smaller than" aSlide2 returns negative value.
// If aSlide1 and aSlide2 "are equal" returns zero.
// ---------------------------------------------------------
//
TInt CUniSmilModel::SortSlidesCompare( CUniSmilSlide* aSlide1,
                                      CUniSmilSlide* aSlide2 )
    {
    if ( !aSlide1->ObjectCount() )
        {
        //if both are empty returns 0
        //if slide2 is non-empty -> slide1 "is greater"
        return aSlide2->ObjectCount();
        }
    else if ( !aSlide2->ObjectCount() )
        {
        //empty slide is always "greatest"
        return -1;
        }
    else
        {
        TTime time1;
        TTime time2;
        aSlide1->GetObjectByIndex( 0 )->MediaInfo()->ModificationTime( time1 );
        aSlide2->GetObjectByIndex( 0 )->MediaInfo()->ModificationTime( time2 );
        if ( time1 < time2 )
            {
            return -1;
            }
        else if ( time1 == time2 )
            {
            return 0;
            }
        else
            {
            return 1;
            }
        }
    }

// ---------------------------------------------------------
// CUniSmilModel::IsSlide
//
//
// ---------------------------------------------------------
//
EXPORT_C TBool CUniSmilModel::IsSlide( TInt aSlideNum ) const
    {
    if( aSlideNum >= 0 &&
        aSlideNum < iSlideArray->Count() )
        {
        return ETrue;
        }
    return EFalse;
    }

// ---------------------------------------------------------
// CUniSmilModel::AddTextObjectL
// 
// ---------------------------------------------------------
//
EXPORT_C CUniTextObject* CUniSmilModel::AddTextObjectL(
    TInt aSlideNum, 
    CEikRichTextEditor* aText )
    {
    CUniTextObject* obj = CUniTextObject::NewLC( iFs, iMtm, iData, aText );
    iObjectList.AddObjectL( obj );
    CleanupStack::Pop( obj );
    iSlideArray->At(aSlideNum)->AddObjectL( obj );
    iSizeEstimateUpToDate = EFalse;
    return obj;
    }

// ---------------------------------------------------------
// CUniSmilModel::AddTempObjectL
//
// ---------------------------------------------------------
//
/*
EXPORT_C CUniObject* CUniSmilModel::AddTempObjectL( TInt aSlideNum,
                                            CMsgMediaInfo* aMedia )
    {
    if ( !IsSlide( aSlideNum ) )
        {
        User::Leave( KErrArgument );
        }

    CUniObject* obj = CUniObject::NewLC( iFs, iMtm, iData, aMedia );

    // Update model
    iObjectList.AddObjectL( obj );
    CleanupStack::Pop( obj );
    iSlideArray->At( aSlideNum )->AddObjectL( obj );
    SetLayoutFromObjectTypeL( obj->MediaType() );
    iSizeEstimateUpToDate = EFalse;
    return obj;
    }
*/

// ---------------------------------------------------------
// CUniSmilModel::AddObjectL
//
// ---------------------------------------------------------
//
EXPORT_C CUniObject* CUniSmilModel::AddObjectL( MUniObjectSaveObserver& aObserver,
                                               TInt aSlideNum,
                                               CMsgMediaInfo* aMedia )
    {
    if ( !IsSlide( aSlideNum ) )
        {
        User::Leave( KErrArgument );
        }

    CUniObject* obj = CUniObject::NewLC( iFs, iMtm, iData, aMedia );

    // Update model
    iObjectList.AddObjectL( obj );
    CleanupStack::Pop( obj );
    obj->Save( aObserver, CMsvAttachment::EMsvLinkedFile );
    iSlideArray->At(aSlideNum)->AddObjectL( obj );
    iSizeEstimateUpToDate = EFalse;
    return obj;
    }

// ---------------------------------------------------------
// CUniSmilModel::AddStoredObjectL
//
// ---------------------------------------------------------
//
EXPORT_C CUniObject* CUniSmilModel::AddStoredObjectL( TInt aSlideNum,
                                                     TMsvAttachmentId aAttachmentId,
                                                     CMsgMediaInfo* aMedia )
    {
    if ( !IsSlide( aSlideNum ) )
        {
        User::Leave( KErrArgument );
        }

    CMsvStore* store = iMtm.Entry().EditStoreL();
    CleanupStack::PushL( store );
    MMsvAttachmentManager& manager = store->AttachmentManagerL();
    MMsvAttachmentManagerSync& managerSync = store->AttachmentManagerExtensionsL();
    CMsvAttachment* attachment = manager.GetAttachmentInfoL( aAttachmentId );
    CleanupStack::PushL( attachment );
    
    CUniObject* obj = NULL;
    
    if ( aMedia &&
         aMedia->MediaType() == EMsgMediaText )
        {
        CMsgTextInfo* textInfo = static_cast<CMsgTextInfo*>( aMedia );
        obj = CUniTextObject::NewLC( iFs, iMtm, iData, textInfo, manager, *attachment );
        }
    else
        {
        obj = CUniObject::NewLC( iFs, iMtm, iData, aMedia, manager, *attachment );
        }
    managerSync.ModifyAttachmentInfoL( attachment );
    CleanupStack::Pop( 2, attachment ); //obj, attachment
    CleanupStack::PushL( obj );
    store->CommitL();

    // Update model
    iObjectList.AddObjectL( obj );
    CleanupStack::Pop( obj );
    CleanupStack::PopAndDestroy( store );
    iSlideArray->At(aSlideNum)->AddObjectL( obj );
    iSizeEstimateUpToDate = EFalse;
    return obj;
    }

// ---------------------------------------------------------
// CUniSmilModel::RemoveObjectL
//
//
// ---------------------------------------------------------
//
EXPORT_C void CUniSmilModel::RemoveObjectL( TInt aSlideNum, 
                                            CUniObject* aObject, 
                                            TBool aLeaveToStore/* = EFalse*/ )
    {
    if ( !IsSlide( aSlideNum ) ||
        !iSlideArray->At( aSlideNum )->IsObject( aObject ) )
        {
        return;
        }
    // TODO: Check that object exists on the slide.

    //if ( !IsObject( aSlideNum, aObjectType ) )
    //    {
    //    return;
    //    }
    DoRemoveObjectL( aSlideNum, aObject, aLeaveToStore );
    }

// ---------------------------------------------------------
// CUniSmilModel::RemoveObjectByIndexL
//
//
// ---------------------------------------------------------
//
EXPORT_C void CUniSmilModel::RemoveObjectByIndexL( TInt aSlideNum, TInt aObjectNum )
    {
    if ( !IsSlide( aSlideNum ) )
        {
        return;
        }
    CUniObject* obj = iSlideArray->At( aSlideNum )->GetObjectByIndex( aObjectNum );
    DoRemoveObjectL( aSlideNum, obj );
    }

// ---------------------------------------------------------
// CUniSmilModel::DoRemoveObjectL
//
//
// ---------------------------------------------------------
//
void CUniSmilModel::DoRemoveObjectL( TInt aSlideNum, CUniObject* aObject, TBool aLeaveToStore/* = EFalse*/ )
    {
    //MsgDataUTILSLOGGER_ENTERFN( "CUniSmilModel : DoRemoveObjectL()" );

    TBool removeObj = ( aObject->ReferenceCount() - 1 <= 0 );
    //if last reference was (will be) removed, remove from 
    //attachment list (and msg store)
    if ( removeObj )
        {
        //MsgDataUTILSLOGGER_WRITE( "CUniSmilModel: Removing from atta list and store." );
        iObjectList.RemoveObjectL( aObject, !aLeaveToStore );
        }

    CUniSmilSlide* slide = iSlideArray->At( aSlideNum );
    slide->RemoveObject( aObject );
    iSizeEstimateUpToDate = EFalse;

    if ( removeObj )
        {
        delete aObject;
        }

    //MsgDataUTILSLOGGER_LEAVEFN( "CUniSmilModel : DoRemoveObjectL()" );
    }

// ---------------------------------------------------------
// CUniSmilModel::GetObject
//
//
// ---------------------------------------------------------
//
EXPORT_C CUniObject* CUniSmilModel::GetObjectByIndex( TInt aSlideNum, 
                                                     TInt aObjectNum ) const
    {
    if( !IsSlide( aSlideNum ) )
        {
        return NULL;
        }
    return iSlideArray->At( aSlideNum )->GetObjectByIndex( aObjectNum );
    }

// ---------------------------------------------------------
// CUniSmilModel::GetObject
//
//
// ---------------------------------------------------------
//
EXPORT_C CUniObject* CUniSmilModel::GetObject( TInt aSlideNum, 
                                              TUniRegion aRegion ) const
    {
    if( !IsSlide( aSlideNum ) )
        {
        return NULL;
        }
    return iSlideArray->At( aSlideNum )->GetObject( aRegion );
    }

// ---------------------------------------------------------
// CUniSmilModel::SetLayoutL
//
// Mutator.
// ---------------------------------------------------------
//
EXPORT_C void CUniSmilModel::SetLayoutL( TUniLayout aNewLayout ) 
    {
    iSlideLayout = aNewLayout;
    TUint slideCnt = iSlideArray->Count();
    for (TUint i = 0; i < slideCnt; i++ )
        {
        iSlideArray->At(i)->UpdateLayoutL( iSlideLayout );
        }   
    iSizeEstimateUpToDate = EFalse;
    }

// ---------------------------------------------------------
// CUniSmilModel::SmilComposeSize()
//
// Total size
// ---------------------------------------------------------
//
EXPORT_C TInt CUniSmilModel::SmilComposeSize()
    {
    TInt slideCount = iSlideArray->Count();
    if ( !slideCount )
        {
        return 0;
        }
    if ( !iSizeEstimateUpToDate )
        {
        iSizeEstimate = SmilComposeSize(
            slideCount,
            iSlideArray->At( slideCount - 1 )->ObjectCount() );
        iSizeEstimateUpToDate = ETrue;
        }
    return iSizeEstimate;
    }


// ---------------------------------------------------------
// CUniSmilModel::SmilComposeSize()
//
// Size from beginning
// ---------------------------------------------------------
//
EXPORT_C TInt CUniSmilModel::SmilComposeSize( TInt aToSlideNum, TInt aToObjectNum )
    {
    //__ASSERT_DEBUG(
    //    ( aToSlideNum > 0 && aToSlideNum <= iSlideArray->Count() ),
    //    DataUtilsPanic( EMmsIllegalSlide ) );
    //__ASSERT_DEBUG(
    //    ( aToObjectNum <= iSlideArray->At( aToSlideNum - 1 )->ObjectCount() ),
    //    DataUtilsPanic( EMmsIllegalObject ) );

    TInt size( KSizeMandatorySmilTags );
    TBool imageRegion = EFalse;
    TBool textRegion = EFalse;

    for ( TInt i = 0; i < aToSlideNum; i++ )
        {
        CUniSmilSlide* slide = iSlideArray->At( i );
        TInt toObj = slide->ObjectCount();
        if ( i == aToSlideNum - 1 )
            {
            toObj = aToObjectNum;
            }
        if ( !toObj )
            {
            //No objects on the slide
            size += KSizeEmptyPar;
            }
        else
            {
            //One or more objects
            size += KSizeNonEmptyPar;
            }
        for ( TInt ii = 0; ii < toObj; ii++ )
            {
            CUniObject* obj = slide->GetObjectByIndex( ii );
            switch ( obj->MediaType() )
                {
                case EMsgMediaAudio:
                    size += KSizeAudioTag;
                    break;
                case EMsgMediaImage:
                case EMsgMediaSvg:
                    size += KSizeImageTag;
                    imageRegion = ETrue;
                    break;
                case EMsgMediaText:
                case EMsgMediaXhtml:
                    size += KSizeTextTag;
                    textRegion = ETrue;
                    break;
                case EMsgMediaVideo:
                    size += KSizeVideoTag;
                    imageRegion = ETrue;
                    break;
                default:
                    //Should never come here
                    //Don't increase size
                    break;
                }
            }
        }

    TInt regions = 0;
    if ( imageRegion )
        {
        regions++;
        }
    if ( textRegion )
        {
        regions++;
        }
    switch ( regions )
        {
        case 1:
            size += KSizeHeadOneRegion;
            break;
        case 2:
            size += KSizeHeadTwoRegions;
            break;
        default:
            //Should be zero
            //Don't increase size
            break;
        }
    return size;
    }


// ---------------------------------------------------------
// CUniSmilModel::ObjectCount
//
// Accessor
// ---------------------------------------------------------
//
EXPORT_C TInt CUniSmilModel::ObjectCount() const
    {
    TInt objCnt(0);

    for ( TInt i = iSlideArray->Count(); --i >= 0 ;)
        {
        objCnt += iSlideArray->At(i)->ObjectCount();
        }

    return objCnt;
    }


// ---------------------------------------------------------
// CUniSmilModel::SlideObjectCount
//
// Accessor
// ---------------------------------------------------------
//
EXPORT_C TInt CUniSmilModel::SlideObjectCount(TInt aSlideNum) const
    {
    if ( !IsSlide(aSlideNum) )
        {
        return 0;
        }

    return iSlideArray->At( aSlideNum )->ObjectCount();
    }

//**********************************************************
//*
//* CONTRUCTION FUNCTIONS 
//*
//**********************************************************


// ---------------------------------------------------------
// CUniSmilModel::ConstructL
//
// 2nd phase constructor.
// ---------------------------------------------------------
//
void CUniSmilModel::ConstructL()
    {
    iSlideArray = new ( ELeave ) CSmilSlideArray( KSlideArrayGranularity );
    iTextRegionId.Set( KNullDesC );
    iImageRegionId.Set( KNullDesC );

    // Set default layout to "Text first"
    iSlideLayout = EUniTextFirst;
    
    // Fix for NSIA-6CKFJA. Sets same screen size that SMIL Player is using. MH
    TRect appWindowRect;
    AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EApplicationWindow, appWindowRect );
    
    TAknLayoutRect mainPane;
    mainPane.LayoutRect( appWindowRect, AknLayoutScalable_Avkon::main_pane( 0 ) );   
    
    TAknLayoutRect mainSmilPane;
    mainSmilPane.LayoutRect( mainPane.Rect(), AknLayoutScalable_Apps::main_smil_pane() );
        
    iScreenSize = mainSmilPane.Rect().Size();       
    }

// ---------------------------------------------------------
// CUniSmilModel::Reset
//
// 
// ---------------------------------------------------------
//
void CUniSmilModel::Reset()
    {
    iParseResult = 0;
    iSlideLayout = EUniTextFirst;
    iTextRegionId.Set( KNullDesC );
    iImageRegionId.Set( KNullDesC );
    if ( iSlideArray )
        {
        // Reset slide array
        iSlideArray->ResetAndDestroy();
        }
    TInt objCount = iObjectList.Count();
    while ( objCount-- )
        {
        iObjectList.GetByIndex( objCount )->SetReferenceCount( 0 );
        }
    }

// ---------------------------------------------------------
// CUniSmilModel::DoPresentationFromDomL
//
// When this functios is called DOM should be validated as MMS SMIL.
// ---------------------------------------------------------
//
void CUniSmilModel::DoPresentationFromDomL( CMDXMLDocument* aDom )
    {
    RemoveMetaTagsAndComments( aDom );
    // Resolve layout of the slide
    iSlideLayout = GetMmsSmilLayout( aDom );

    CMDXMLNode* node = GetNode( aDom, KSMILWREleBody );

    if ( node && node->FirstChild() )
        {
        // Only one slide in the message since no <par> tag found
        if ( node->FirstChild()->NodeName().Compare( KSMILWRElePar ) != 0 )
            {
            // Add slide - the one and only
            AddSlideFromDomL( node );
            }

        // Other node types than <par> not possible as this is MMS SMIL.
        else
            {
            // Traverse through every page
            CMDXMLNode* page = node->FirstChild();
            while ( page )
                {
                AddSlideFromDomL( page );
                // Go to next page.
                page = page->NextSibling();
                }
            }
        }
    }

// ---------------------------------------------------------
// CUniSmilModel::AddSlideFromDomL
//
// ---------------------------------------------------------
//
void CUniSmilModel::AddSlideFromDomL( CMDXMLNode* aPage )
    {
    CUniObject* obj = NULL;
    CUniSmilSlide* slide = DoAddSlideL();
    CMDXMLNode* node = aPage->FirstChild();

    // Traverse through every object in page.
    while ( node )
        {
        if ( UniSmilUtils::IsMediaElem( node ) )
            {
            obj = iObjectList.GetByNodeL( node );
            if ( obj )
                {
                if ( slide )
                    {
                    obj->SetMediaTypeBySmilTag( UniSmilUtils::MediaElemType( node ) );
                    AddObjectFromDomL(
                        slide,
                        obj,
                        GetRegionType( node ) );
                    }
                else
                    {
                    iObjectList.RemoveObjectL( obj, ETrue );
                    delete obj;
                    iParseResult |= EObjectRemoved;
                    }
                }
            }
        node = node->NextSibling();
        }
    }


// ---------------------------------------------------------
// CUniSmilModel::AddObjectFromDomL
//
// ---------------------------------------------------------
//
void CUniSmilModel::AddObjectFromDomL( CUniSmilSlide* aSlide,
                                       CUniObject* aObj,
                                       TUniRegion aRegion )
    {            
    if ( !aObj )
        {
        // Smil presentation refers to attachment that's not in the message
        iParseResult |= EMissingObjects;
        // Not actually error that should prevent message viewing.
        return; 
        }

    TMsgMediaType mediaBySmilTag = aObj->MediaTypeBySmilTag();
    TMsgMediaType media = aObj->MediaType();

    if ( media == EMsgMediaSvg )
        {
        // SVG considered an image.
        // (...because "image" tag is used for SVG while composing SMIL.)
        media = EMsgMediaImage;
        }

    if ( media == EMsgMediaXhtml )
        {
        // XHTML is considered as a text.
        // (...because "text" tag is used for xhtml while composing SMIL.)
        media = EMsgMediaText;
        }

    if ( !( media == EMsgMediaText ||
        media == EMsgMediaImage ||
        media == EMsgMediaAudio ||
        media == EMsgMediaVideo ) )
        {
        // Unsupported format
        //MsgDataUTILSLOGGER_WRITE( "CUniSmilModel: Parsing: Message has unsupported objects." );
        iParseResult |= EUnsupportedObjects;
        // Not actually error that should prevent message viewing.
        }
    
    //  NOTE: Smil standard allows <img src="aa.txt"> references, but conformance
    //        Data forbids these. 
    if ( media != EMsgMediaUnknown &&   //Unknown matches anything
         mediaBySmilTag != EMsgMediaRef &&    //<ref> matches anything
         media != mediaBySmilTag )
        {
        // SMIL does not describe content as it should
        //MsgDataUTILSLOGGER_WRITE( "CUniSmilModel: Parsing: Smil object type differs from message object type." );
        iParseResult |= EBadlyReferencedObjects;
        }

    TUniRegion regionBySmilTag = EUniRegionUnresolved;
    switch ( mediaBySmilTag )
        {
        case EMsgMediaAudio:
            {
            regionBySmilTag = EUniRegionAudio;
            break;
            }
        case EMsgMediaImage:
        case EMsgMediaVideo:
            {
            regionBySmilTag = EUniRegionImage;
            break;
            }
        case EMsgMediaText:
            {
            regionBySmilTag = EUniRegionText;
            break;
            }
        default:
            break;
        }

    TUniRegion regionByMediaType = EUniRegionUnresolved;
    switch ( media )
        {
        case EMsgMediaAudio:
            {
            regionByMediaType = EUniRegionAudio;
            break;
            }
        case EMsgMediaImage:
        case EMsgMediaVideo:
            {
            regionByMediaType = EUniRegionImage;
            break;
            }
        case EMsgMediaText:
            {
            regionByMediaType = EUniRegionText;
            break;
            }
        default:
            break;
        }

    // Check that region type matches object media type
    if ( aRegion != EUniRegionUnresolved &&
        regionByMediaType != EUniRegionUnresolved &&
        aRegion != regionByMediaType )
        {
        iParseResult |= ERegionMediaTypeMismatch;
        aRegion = regionByMediaType;
        }
    else if ( regionByMediaType == EUniRegionUnresolved &&  
              aRegion == EUniRegionText )
        {
        // do not put every possible content into text reqion
        iParseResult |= ERegionMediaTypeMismatch;
        aRegion = EUniRegionUnresolved;
        }
    else if ( aRegion == EUniRegionUnresolved )
        {
        // If region couldn't be resolved from the region tag
        // follow the media type. If that's not possible follow
        // the smil media tag name. If everything fails
        // "aRegion" will remain "unresolved".
        aRegion = ( regionByMediaType != EUniRegionUnresolved )
            ? regionByMediaType
            : regionBySmilTag;
        }
   
    CMsgMediaInfo* mediaInfo = aObj->MediaInfo();
    // DRM2 must be put into object view in the viewer
    if ( mediaInfo  &&  
         ( mediaInfo->HandlerApplicationUid().iUid == 0 ||  
           aObj->MediaInfo()->Protection() & EFileProtDrm2 ) )
        {
        aRegion = EUniRegionUnresolved;
        }
    // else - should not occur

    if ( aRegion != EUniRegionUnresolved )
        {
        aSlide->AddObjectL( aObj, aRegion );
        iSizeEstimateUpToDate = EFalse;
        }
    else
        {
        iParseResult |= EBadlyReferencedObjects;
        // -> Something unknown in the SMIL.
        // -> Don't add. Will be handled as an attachment.
        }
    }

// ---------------------------------------------------------
// CUniSmilModel::IsMessageSlide
//
// ---------------------------------------------------------
//
TBool CUniSmilModel::IsMessageSlide()
    {
    TInt imageCnt( 0 );
    TInt audioCnt( 0 );
    TInt textCnt( 0 );
    
    for ( TInt i = iObjectList.Count(); --i >= 0 ; )
        {
        switch( iObjectList.GetByIndex(i)->MediaType() )
            {
            case EMsgMediaSvg:
            case EMsgMediaImage:
                imageCnt++;
                break;

            case EMsgMediaAudio:
                audioCnt++;
                break;

            case EMsgMediaText:
            case EMsgMediaXhtml:
                textCnt++;
                break;

            case EMsgMediaVideo:
                //always consider video as image + audio
                imageCnt++;
                audioCnt++;
                break;

            case EMsgMediaUnknown:
            default:
                //  Unsupported objects will be put into attachment list
                //  in FindAttachmentsL()
                break;
            } // switch
        } // for     

    if ( imageCnt > 1 || audioCnt > 1 || textCnt  > 1 ) 
        {
        return EFalse;
        }

    return ETrue;
    }

// ---------------------------------------------------------
// DoNoSmilOneSlideL
//
// NOTE: Message should be a valid slide at this point.
// ---------------------------------------------------------
//
void CUniSmilModel::DoNoSmilOneSlideL()
    {
    CUniSmilSlide* slide = NULL;
        
    for ( TInt i = 0; i < iObjectList.Count(); i++ )
        {
        CUniObject* obj = iObjectList.GetByIndex(i);
        TMsgMediaType media = obj->MediaType();
        CMsgMediaInfo* mediaInfo = obj->MediaInfo();
        
        // DRM2 must be put into objects view in the viewer
        if ( ( media == EMsgMediaText ||
               media == EMsgMediaXhtml ||  
               media == EMsgMediaImage ||
               media == EMsgMediaSvg ||
               media == EMsgMediaAudio ||
               media == EMsgMediaVideo ) &&
             mediaInfo && 
             mediaInfo->HandlerApplicationUid().iUid &&
             !( obj->MediaInfo()->Protection() & EFileProtDrm2 ) )
            {
            if ( !slide )
                {
                // Add slide
                slide = DoAddSlideL();
                }
            slide->AddObjectL( obj );
            }
        }
    }

// ---------------------------------------------------------
// DoNoSmilManySlideL
//
//  
// ---------------------------------------------------------
//
void CUniSmilModel::DoNoSmilManySlideL()
    {    
    for ( TInt i = 0; i < iObjectList.Count(); i++ )
        {
        CUniObject* obj = iObjectList.GetByIndex(i);
        TMsgMediaType media = obj->MediaType();
        CMsgMediaInfo* mediaInfo = obj->MediaInfo();
        
        // DRM2 must be put into objects view in the viewer
        if ( ( media == EMsgMediaText ||
               media == EMsgMediaXhtml ||  
               media == EMsgMediaImage ||
               media == EMsgMediaSvg ||
               media == EMsgMediaAudio ||
               media == EMsgMediaVideo ) && 
            mediaInfo && 
            mediaInfo->HandlerApplicationUid().iUid &&
             !( obj->MediaInfo()->Protection() & EFileProtDrm2 ) )
            {
            CUniSmilSlide* slide = DoAddSlideL();
            if ( slide )
                {
                slide->AddObjectL( obj );
                }
            else if ( obj )
                {
                iObjectList.RemoveObjectL( obj, ETrue );
                delete obj;
                iParseResult |= EObjectRemoved;
                i--;
                }
            }
        }
    }

// ---------------------------------------------------------
// DoAddSlideL
//
// ---------------------------------------------------------
//
CUniSmilSlide* CUniSmilModel::DoAddSlideL( TInt aSlideNum /*= -1*/ )
    {
    CUniSmilSlide* newSlide = NULL;
    if ( iMaxSlideCount == 0 || 
         iSlideArray->Count() < iMaxSlideCount )
        {
        newSlide = CUniSmilSlide::NewLC( iSlideLayout );
        if ( aSlideNum == -1 || aSlideNum >= iSlideArray->Count() )
            {
            // Add to end of array
            iSlideArray->AppendL( newSlide );
            }
        else
            {
            iSlideArray->InsertL( aSlideNum, newSlide );
            }
        CleanupStack::Pop( newSlide );  // newSlide
        iSizeEstimateUpToDate = EFalse;
        }
    return newSlide;
    }

// ---------------------------------------------------------
// CUniSmilModel::CreateHeadL
// 
// ---------------------------------------------------------
void CUniSmilModel::CreateHeadL( CMDXMLDocument* aDom, CMDXMLElement* aRoot )
    {

    TPtrC name( KSMILWREleHead );
    // Create Head node
    CMDXMLElement* ele = CMDXMLElement::NewLC( ETrue, aDom, name );
    // Append Head in Root node
    aRoot->AppendChild( ele );

    // Create Layout
    CreateLayoutL( aDom, ele );
    CleanupStack::Pop( ele );
    }

// ---------------------------------------------------------
// CUniSmilModel::ChangeLayoutL
// 
// ---------------------------------------------------------
EXPORT_C TBool CUniSmilModel::ChangeLayoutL( CMDXMLDocument* aDom )
    {
    TBool retVal = EFalse;
    if ( aDom )
        {
        CMDXMLElement* layout = (CMDXMLElement*) GetNode( aDom, KSMILWREleLayout );
        if ( !layout )
            {
            // No layout. Nothing to do without composing
            // SMIL from scratch.
            return EFalse;
            }
        CMDXMLElement* head = (CMDXMLElement*) layout->ParentNode();

        // Read default smil parameters
        if( !iSmilParams )
            {
            iSmilParams = CUniSmilParams::NewL( iFs );
            }
        CMDXMLElement* rootLayout = NULL;
        CMDXMLElement* textRegion = NULL;
        CMDXMLElement* imageRegion = NULL;

        GetLayoutElements(
            layout,
            rootLayout,
            textRegion,
            imageRegion );

        if ( rootLayout )
            {
            rootLayout->RemoveAttribute( KSMILWRParaWidth );
            rootLayout->RemoveAttribute( KSMILWRParaHeight );
            }

        if ( textRegion )
            {
            textRegion->RemoveAttribute( KSMILWRParaFit );
            textRegion->RemoveAttribute( KSMILWRParaTop );
            textRegion->RemoveAttribute( KSMILWRParaLeft );
            textRegion->RemoveAttribute( KSMILWRParaBottom );
            textRegion->RemoveAttribute( KSMILWRParaRight );
            textRegion->RemoveAttribute( KSMILWRParaHeight );
            textRegion->RemoveAttribute( KSMILWRParaWidth );
            }
        if ( imageRegion )
            {
            imageRegion->RemoveAttribute( KSMILWRParaFit );
            imageRegion->RemoveAttribute( KSMILWRParaTop );
            imageRegion->RemoveAttribute( KSMILWRParaLeft );
            imageRegion->RemoveAttribute( KSMILWRParaBottom );
            imageRegion->RemoveAttribute( KSMILWRParaRight );
            imageRegion->RemoveAttribute( KSMILWRParaHeight );
            imageRegion->RemoveAttribute( KSMILWRParaWidth );
            }

        CreateLayoutL( aDom, head, rootLayout, layout, textRegion, imageRegion );
        retVal = ETrue;
        }
    return retVal;
    }

// ---------------------------------------------------------
// CUniSmilModel::CorrectTimingL
// 
// ---------------------------------------------------------
EXPORT_C TBool CUniSmilModel::CorrectTimingL( CMDXMLDocument* aDom )
    {
    if ( aDom )
        {
        CMDXMLElement* body = static_cast<CMDXMLElement*>( GetNode( aDom, KSMILWREleBody ) );
        if ( !body )
            {
            // No body. Nothing to do without composing
            // SMIL from scratch.
            return EFalse;
            }
        
        if ( body && body->FirstChild() )
            {
            // Only one slide in the message since no <par> tag found
            if ( body->FirstChild()->NodeName().Compare( KSMILWRElePar ) != 0 &&
                 !body->FirstChild()->NextSibling() )
                {
                // Correct slide timing to the one and only slide
                CorrectSlideTimingL( body );
                }
            // Other node types than <par> not possible as this is MMS SMIL.
            else
                {
                // Traverse through every page
                CMDXMLNode* page = body->FirstChild();
                
                while ( page != NULL )
                    {
                    if ( page->NodeName().Compare( KSMILWRElePar ) == 0 &&
                         page->NodeType() == CMDXMLNode::EElementNode )
                        {
                        CMDXMLElement* pageElement = static_cast<CMDXMLElement*>( page );
                        if ( !TimingSpecified( pageElement ) )
                            {
                            CorrectSlideTimingL( pageElement );
                            }
                        }
                    // Go to next page.
                    page = page->NextSibling();
                    }
                }
            }
        }
        
    return ETrue;
    }

// ---------------------------------------------------------
// CUniSmilModel::IsSupportedMediaType
// 
// ---------------------------------------------------------
EXPORT_C TBool CUniSmilModel::IsSupportedMediaType( TMsgMediaType aMediaType ) const
    {
    if ( aMediaType == EMsgMediaAudio || 
         aMediaType == EMsgMediaImage ||
         aMediaType == EMsgMediaSvg ||
         aMediaType == EMsgMediaXhtml ||
         aMediaType == EMsgMediaVideo ||
         aMediaType == EMsgMediaText )
        {
        return ETrue;
        }
    else
        {
        return EFalse;
        }
    }


// ---------------------------------------------------------
// CUniSmilModel::CreateLayoutL
// 
// ---------------------------------------------------------
void CUniSmilModel::CreateLayoutL( CMDXMLDocument* aDom,
                                  CMDXMLElement* aRoot,
                                  CMDXMLElement* aRootLayout,
                                  CMDXMLElement* aLayout,
                                  CMDXMLElement* aTextRegion,
                                  CMDXMLElement* aImageRegion )
    {

    TPtrC name( KSMILWREleLayout );
    // Create Layout node
    if ( !aLayout )
        {
        aLayout = CMDXMLElement::NewLC( ETrue, aDom, name );
        // Append Layout in Head
        aRoot->InsertBefore( NULL, aLayout );
        CleanupStack::Pop(); // layout
        }

    // Do we have images and text-objects on a slide with other media objects and
    // do we have any video
    TInt hasVideo( 0 );
    TInt hasImage( 0 );
    TInt hasText( 0 );
    
    // Do we have media, which is alone on a slide? Also calculate how medias are alone on a slide.
    // Video overrides any image region, it is not needed
    TInt hasImageOneAndOnly( 0 );
    TInt hasTextOneAndOnly( 0 );

    for( TInt i = 0; i < iSlideArray->Count(); i++ )
        {
        CUniSmilSlide* s = iSlideArray->At( i );
        TBool hasVideoOnThisSlide = EFalse;
        TBool hasImageOnThisSlide = EFalse;
        TBool hasTextOnThisSlide = EFalse;

        CUniObject* imageRegionObj = s->GetObject( EUniRegionImage );
        if ( imageRegionObj )
            {
            if ( imageRegionObj->MediaType() == EMsgMediaVideo )
                {
                hasVideoOnThisSlide = ETrue;
                hasVideo++;
                }
            else
                {
                hasImageOnThisSlide = ETrue;
                hasImage++;
                }
            }
        if ( s->GetObject( EUniRegionText ) )
            {
            hasTextOnThisSlide = ETrue;
            hasText++;
            }
            
        if (    !hasVideoOnThisSlide
            &&  hasImageOnThisSlide 
            &&  !hasTextOnThisSlide )
            {
            hasImageOneAndOnly++;
            }
        if (    !hasVideoOnThisSlide
            &&  !hasImageOnThisSlide 
            &&  hasTextOnThisSlide )
            {
            hasTextOneAndOnly++;
            }
        }
        
    // we know:
    // how many media objects of each type there are totally in the message and
    // whether some regions have alone on a slide
    // we conclude:
    // if a media object has been alone on the slide and there is 
    // only one media object in the whole message
    // or if there are several images without other content or several texts on several slides
    // without other content then the media object is alone on a slide
    // and is only one of its type in the message
    // but: video is exception. It handling is ignored here. Following big if() statement handles it
    // by handling video before exception case resolved 
    if ( hasImageOneAndOnly == hasImage )
        {
        // image does not occur with some other region
        hasImage = 0;
        }
    else
        {
        // image occurs with some other region on some slide
        hasImageOneAndOnly = 0;
        }

    if ( hasTextOneAndOnly ==  hasText )
        {
        // text does not occur with some other region
        hasText = 0;
        }
    else
        {
        // text occurs with some other region on some slide
        hasTextOneAndOnly = 0;
        }
    

    TBool isLandscape( Layout_Meta_Data::IsLandscapeOrientation() );
    
    TBool useSubQCIF( EFalse);
    
    TRect appWin;
    AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EApplicationWindow, appWin );
    TAknLayoutRect mainPane;
    
    if ( isLandscape )
        {
        mainPane.LayoutRect(
            appWin,
            AknLayoutScalable_Apps::main_pane( 4 ).LayoutLine() );
        }
    else
        {
        mainPane.LayoutRect(
            appWin,
            AknLayoutScalable_Apps::main_pane( 6 ).LayoutLine() );
        }
    
    if ( isLandscape &&
         appWin.Height() == KSizeLowResWidth &&
         appWin.Width() == KSizeLowResHeight )
        {
        useSubQCIF = ETrue;
        }
        
    TAknLayoutRect smilLayout;
    smilLayout.LayoutRect(
        mainPane.Rect(),
        AknLayoutScalable_Apps::main_smil2_pane().LayoutLine() );
    
    TAknLayoutRect rootLayout;
    TAknLayoutRect textLayout;
    TAknLayoutRect imageLayout;
    TAknLayoutRect videoLayout;

    // For reader about notation:
    //             x + y == x and y are on the different slide
    //             x,y == x and y are on the same slide
    //             { <item> } item can occur 0 or more times
    if ( hasText && hasImage && !hasVideo ) // text, image - no video
        {
        if ( isLandscape ) // landscape text & image
            {
            if ( iSlideLayout == EUniTextFirst )
                {
                rootLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_root_pane( 4 ).LayoutLine() );
                textLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_text_pane( 4 ).LayoutLine() );
                imageLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_image_pane( 3 ).LayoutLine() );
                }
            else
                {
                rootLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_root_pane( 2 ).LayoutLine() );
                textLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_text_pane( 2 ).LayoutLine() );                    
                imageLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_image_pane( 1 ).LayoutLine() );
                }
            }
        else // portrait text & image
            {
            if ( iSlideLayout == EUniTextFirst )
                {
		        // Option 3 in the layout spec
                rootLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_root_pane( 3 ).LayoutLine() );
                textLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_text_pane( 3 ).LayoutLine() );
                imageLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_image_pane( 2 ).LayoutLine() );
                }
            else
                {
		        // Option 1
                rootLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_root_pane( 1 ).LayoutLine() );
                textLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_text_pane( 1 ).LayoutLine() );                    
                imageLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_image_pane( 0 ).LayoutLine() );
                }
            }
        }
    else if ( hasText && hasVideo ) // text, video or text, image + video
        {
        if ( isLandscape && useSubQCIF ) // landscape subQCIF text & video
            {
            if ( iSlideLayout == EUniTextFirst )
                {
                rootLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_root_pane( 13 ).LayoutLine() );
                textLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_text_pane( 10 ).LayoutLine() );
                videoLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_video_pane( 7 ).LayoutLine() );
                }
            else
                {
                rootLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_root_pane( 12 ).LayoutLine() );
                textLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_text_pane( 9 ).LayoutLine() );
                videoLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_video_pane( 6 ).LayoutLine() );
                }
            }
        else if ( isLandscape && !useSubQCIF ) // landscape QCIF text & video
            {
            if ( iSlideLayout == EUniTextFirst )
                {
                rootLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_root_pane( 10 ).LayoutLine() );
                textLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_text_pane( 8 ).LayoutLine() );
                videoLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_video_pane( 4 ).LayoutLine() );
                }
            else
                {
                rootLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_root_pane( 9 ).LayoutLine() );
                textLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_text_pane( 7 ).LayoutLine() );
                videoLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_video_pane( 3 ).LayoutLine() );
                }
            }
        else // portrait QCIF text & video
            {
            if ( iSlideLayout == EUniTextFirst )
                {
		        // Option 8
                rootLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_root_pane( 8 ).LayoutLine() );
                textLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_text_pane( 6 ).LayoutLine() );
                videoLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_video_pane( 2 ).LayoutLine() );
                }
            else
                {
		        // Option 6
                rootLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_root_pane( 6 ).LayoutLine() );
                textLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_text_pane( 5 ).LayoutLine() );
                videoLayout.LayoutRect(
                    smilLayout.Rect(),
                    AknLayoutScalable_Apps::smil2_video_pane( 0 ).LayoutLine() );
                }
            }
        }
    // cases left:
    // - 1) text {+ text} 
    // - 2) text {+ text} + video
    // - 3) text {+ text} + image { + image }
    // - 4) image {+ image} + video, no text 
    // - 5) image {+ image}
    // - 6) video
    // - no visual media content
    else if ( hasVideo ) 
        {
        // 2) 'text {+ text} + video',  4) 'image {+ image} + video, no text' or 6) 'video'        
        if ( isLandscape )
            {
            rootLayout.LayoutRect(
                smilLayout.Rect(),
                AknLayoutScalable_Apps::smil2_root_pane( 11 ).LayoutLine() );
            videoLayout.LayoutRect(
                smilLayout.Rect(),
                AknLayoutScalable_Apps::smil2_video_pane( 5 ).LayoutLine() );
            }
        else
            {
            // Option 7
            rootLayout.LayoutRect(
                smilLayout.Rect(),
                AknLayoutScalable_Apps::smil2_root_pane( 7 ).LayoutLine() );
            videoLayout.LayoutRect(
                smilLayout.Rect(),
                AknLayoutScalable_Apps::smil2_video_pane( 1 ).LayoutLine() );
            }

        if ( hasTextOneAndOnly ) // + text
            {
            // Option 0
            rootLayout.LayoutRect(
                smilLayout.Rect(),
                AknLayoutScalable_Apps::smil2_root_pane( 0 ).LayoutLine() );
            textLayout.LayoutRect(
                smilLayout.Rect(),
                AknLayoutScalable_Apps::smil2_text_pane( 0 ).LayoutLine() );
            }

        }
    else if (   hasTextOneAndOnly
            ||  hasImageOneAndOnly )
        {
        // 1) text {+ text}, 3) text {+ text} + image { + image ), 5) image {+ image}
        if ( hasTextOneAndOnly ) // text
            {
            // Option 0
            rootLayout.LayoutRect(
                smilLayout.Rect(),
                AknLayoutScalable_Apps::smil2_root_pane( 0 ).LayoutLine() );
            textLayout.LayoutRect(
                smilLayout.Rect(),
                AknLayoutScalable_Apps::smil2_text_pane( 0 ).LayoutLine() );
            }

        // no else - rootLayouts are same
        if ( hasImageOneAndOnly ) // image
            {
            // Option 5
            rootLayout.LayoutRect(
                smilLayout.Rect(),
                AknLayoutScalable_Apps::smil2_root_pane( 5 ).LayoutLine() );
            imageLayout.LayoutRect(
                smilLayout.Rect(),
                AknLayoutScalable_Apps::smil2_image_pane( 4 ).LayoutLine() );
            }
        }
    else    // empty
        {
        rootLayout.LayoutRect(
            smilLayout.Rect(),
            AknLayoutScalable_Apps::smil2_root_pane( 0 ).LayoutLine() );
        textLayout.LayoutRect(
            smilLayout.Rect(),
            AknLayoutScalable_Apps::smil2_text_pane( 0 ).LayoutLine() );        
        }

    iSmilParams->iComposeParams->iDisplayHeight = rootLayout.Rect().Height();
    iSmilParams->iComposeParams->iDisplayWidth = rootLayout.Rect().Width();

    // it does not matter anymore whether object is alone on the slide.
    // Use one variable only in the if() statements
    if ( hasImage || hasImageOneAndOnly )
        {
        hasImage = 1;
        }
    if ( hasText || hasTextOneAndOnly )
        {
        hasText = 1;
        }

    if ( hasText )
        {
        iSmilParams->iTextRegionParams->iSize = textLayout.Rect().Size();
        iSmilParams->iTextRegionParams->iTopLeft = 
            textLayout.Rect().iTl - rootLayout.Rect().iTl;
        }
    if ( hasImage || hasVideo )
        {
        if ( hasVideo )
            {
            iSmilParams->iImageRegionParams->iSize = videoLayout.Rect().Size();
            iSmilParams->iImageRegionParams->iTopLeft = 
                videoLayout.Rect().iTl - rootLayout.Rect().iTl;
            }
        else
            {
            iSmilParams->iImageRegionParams->iSize = imageLayout.Rect().Size();
            iSmilParams->iImageRegionParams->iTopLeft = 
                imageLayout.Rect().iTl - rootLayout.Rect().iTl;
            }
        }

    // Set Region IDs to defaults
    if ( !iImageRegionId.Length() )
        {
        iImageRegionId.Set( KSMILWRRegIDImage );
        }
    if ( !iTextRegionId.Length() )
        {
        iTextRegionId.Set( KSMILWRRegIDText );
        }

    // Create root layout
    name.Set( KSMILWREleRoot_layout );
    TBool rlPop = EFalse;
    if ( !aRootLayout )
        {
        aRootLayout = CMDXMLElement::NewLC( EFalse, aDom, name );
        rlPop = ETrue;
        }
    // Set root layout parameters (attributes)
    TBuf16<20> val;
    val.Zero();
    val.Format( KSmilIntFormat, iSmilParams->iComposeParams->iDisplayWidth );
    aRootLayout->SetAttributeL( KSMILWRParaWidth,val );
    val.Zero();
    val.Format( KSmilIntFormat, iSmilParams->iComposeParams->iDisplayHeight );
    aRootLayout->SetAttributeL( KSMILWRParaHeight, val );
    if ( rlPop )
        {
        // Append root layout in Layout
        aLayout->AppendChild( aRootLayout );
        CleanupStack::Pop( aRootLayout );
        }

    // Create Image region (if needed)
    name.Set( KSMILWREleRegion );
    if ( hasImage || hasVideo )
        {
        TBool imgPop = EFalse;
        if ( !aImageRegion )
            {
            aImageRegion = CMDXMLElement::NewLC( EFalse, aDom, name );
            imgPop = ETrue;
            }
        // Set Image region attributes
        aImageRegion->SetAttributeL( KSMILWRParaId, iImageRegionId );
        val.Zero();
        val.Format( KSmilIntFormat, iSmilParams->iImageRegionParams->Width() );
        aImageRegion->SetAttributeL( KSMILWRParaWidth, val );
        val.Zero();
        val.Format( KSmilIntFormat, iSmilParams->iImageRegionParams->Height() );
        aImageRegion->SetAttributeL( KSMILWRParaHeight, val );
        val.Zero();
        val.Format( KSmilIntFormat, iSmilParams->iImageRegionParams->Top() );
        aImageRegion->SetAttributeL( KSMILWRParaTop, val );
        val.Zero();
        val.Format( KSmilIntFormat, iSmilParams->iImageRegionParams->Left() );
        aImageRegion->SetAttributeL( KSMILWRParaLeft, val );
        aImageRegion->SetAttributeL( KSMILWRParaFit, iSmilParams->iImageRegionParams->iFit->Des() );
        if ( imgPop )
            {
            // Append region in Layout
            aLayout->AppendChild( aImageRegion ); // Ownership to dom
            CleanupStack::Pop( aImageRegion );
            }
        }

    // Create Text region (if needed)
    if ( hasText )
        {
        TBool txtPop = EFalse;
        if ( !aTextRegion )
            {
            aTextRegion = CMDXMLElement::NewLC( EFalse, aDom, name );
            txtPop = ETrue;
            }
        // Set Text region attributes
        aTextRegion->SetAttributeL( KSMILWRParaId, iTextRegionId );
        val.Zero();
        val.Format( KSmilIntFormat, iSmilParams->iTextRegionParams->Width() );
        aTextRegion->SetAttributeL( KSMILWRParaWidth, val );
        val.Zero();
        val.Format( KSmilIntFormat, iSmilParams->iTextRegionParams->Height() );
        aTextRegion->SetAttributeL( KSMILWRParaHeight, val );
        val.Zero();
        val.Format( KSmilIntFormat, iSmilParams->iTextRegionParams->Top() );
        aTextRegion->SetAttributeL( KSMILWRParaTop, val );
        val.Zero();
        val.Format( KSmilIntFormat, iSmilParams->iTextRegionParams->Left() );
        aTextRegion->SetAttributeL( KSMILWRParaLeft, val );
        aTextRegion->SetAttributeL( KSMILWRParaFit, iSmilParams->iTextRegionParams->iFit->Des() );
        if ( txtPop )
            {
            // Append region in Layout
            aLayout->AppendChild( aTextRegion ); // Ownership to dom
            CleanupStack::Pop( aTextRegion );
            }
        }
    }

// ---------------------------------------------------------
// CUniSmilModel::CreateBodyL
// 
// ---------------------------------------------------------
void CUniSmilModel::CreateBodyL( CMDXMLDocument* aDom, CMDXMLElement* aRoot )
    {
    TPtrC name( KSMILWREleBody );
    // Create Body node
    CMDXMLElement* body = CMDXMLElement::NewLC( ETrue, aDom, name );
    // Append
    aRoot->AppendChild( body );
    CleanupStack::Pop( body );

    // For each slide
    for( TInt slide = 0; slide < iSlideArray->Count(); slide++ )
        {
        // Create par
        CreateParL( aDom, body, slide );
        }

    }

// ---------------------------------------------------------
// CUniSmilModel::CreateParL
// 
// ---------------------------------------------------------
void CUniSmilModel::CreateParL( CMDXMLDocument* aDom, CMDXMLElement* aRoot, TInt aSlide )
    {
    TPtrC name( KSMILWRElePar );
    // Create par node
    CMDXMLElement* ele = CMDXMLElement::NewLC( ETrue, aDom, name );
    // Append

    // Get default page duration.
    TInt slideDur = iSmilParams->iComposeParams->iSlideDuration;
    TInt objDur = 0;
    TBool unresolvedDur = EFalse;

    CUniSmilSlide* s = iSlideArray->At( aSlide );

    // For each object in slide
    for ( TInt i = s->ObjectCount(); --i >= 0; )
        {
        // Create Item
        CUniObject* obj = s->GetObjectByIndex( i );
        objDur = CreateItemL( aDom, ele, obj );
        if ( !obj->MediaInfo()->Parsed() &&
            ( obj->MediaType() == EMsgMediaAudio ||
            obj->MediaType() == EMsgMediaVideo ) )
            {
            unresolvedDur = ETrue;
            }
        else 
            {
            slideDur = Max( slideDur, objDur );
            }
        }

    if ( !unresolvedDur )
        {
        TBuf16<20> val;
        val.Zero();
        val.Format( KSmilMsecFormat, slideDur );

        // Set par attributes
        ele->SetAttributeL( KSMILWRParaDur, val );
        }
    aRoot->AppendChild( ele ); // Ownership to dom
    CleanupStack::Pop( ele );
    }

// ---------------------------------------------------------
// CUniSmilModel::CreateItemL
// 
// ---------------------------------------------------------
TInt CUniSmilModel::CreateItemL( CMDXMLDocument* aDom, CMDXMLElement* aRoot, CUniObject* aObj )
    {
    CMDXMLElement* ele = NULL;
    TPtrC name( KNullDesC );

    // Create mediaobject node
    switch ( aObj->Region() )
        {
        case EUniRegionImage:
            {
            if ( aObj->MediaType() == EMsgMediaVideo )
                {
                name.Set( KSMILWREleVideo );
                ele = CMDXMLElement::NewLC( EFalse, aDom, name );
                ele->SetAttributeL( KSMILWRParaRegion, KSMILWRRegIDImage );
                }
            else
                {
                // Considered an image - includes also SVG
                name.Set( KSMILWREleImg );
                ele = CMDXMLElement::NewLC( EFalse, aDom, name );
                ele->SetAttributeL( KSMILWRParaRegion, KSMILWRRegIDImage );
                }
            }
            break;
        case EUniRegionText:
            {
            name.Set( KSMILWREleText );
            ele = CMDXMLElement::NewLC( EFalse, aDom, name );
            ele->SetAttributeL( KSMILWRParaRegion, KSMILWRRegIDText );
            }
            break;
        case EUniRegionAudio:
            {
            name.Set( KSMILWREleAudio );
            ele = CMDXMLElement::NewLC( EFalse, aDom, name );
            }
            break;
        default:
            {
            User::Leave( KErrNotSupported );
            }
        }

    // Set MediaObject node attributes
    ele->SetAttributeL( KSMILWRParaSrc, aObj->MimeInfo()->ContentLocation() );
    
    // Append
    aRoot->AppendChild( ele ); // Ownership to dom
    CleanupStack::Pop( ele );

    return aObj->MediaInfo()->Duration();
    }

// ---------------------------------------------------------
// CUniSmilModel::GetMediaElemRegionIDs
// 
// ---------------------------------------------------------
void CUniSmilModel::GetMediaElemRegionIDs( CMDXMLNode* aPage )
    {
    CMDXMLNode* txtEle = NULL;
    CMDXMLNode* imgEle = NULL;
    CMDXMLNode* obj = aPage->FirstChild();

    // Traverse through every object in page.
    while ( obj )
        {
        if( UniSmilUtils::IsMediaElem( obj ) )
            {
            TMsgMediaType type = UniSmilUtils::MediaElemType( obj );
            switch ( type )
                {
                case EMsgMediaImage:
                case EMsgMediaVideo:
                    imgEle = obj;
                    break;

                case EMsgMediaText:
                case EMsgMediaXhtml:
                    txtEle = obj;
                    break;

                // TODO: REF
                default:
                    break;
                }
            }
        obj = obj->NextSibling();
        }

    // Resolve ID:s
    if ( !iTextRegionId.Length() && txtEle )
        {
        UniSmilUtils::GetRegionId( txtEle, iTextRegionId );
        }
    if ( !iImageRegionId.Length() && imgEle )
        {
        UniSmilUtils::GetRegionId( imgEle, iImageRegionId );
        }
    }

// ---------------------------------------------------------
// CUniSmilModel::GetLayoutElements
// 
// ---------------------------------------------------------
void CUniSmilModel::GetLayoutElements( CMDXMLNode* aLayout,
                                       CMDXMLElement*& aRlEle,
                                       CMDXMLElement*& aTxtEle,
                                       CMDXMLElement*& aImgEle )
    {
    if ( !aLayout )
        {
        return;
        }

    TPtrC value( KNullDesC );
    CMDXMLNode* node = aLayout->FirstChild();
    
    // Search REGIONS & RootLayout
    while ( node )
        {
        // REGION PARAMETERS
        if ( node->NodeName().CompareF( KSMILWREleRegion ) == 0 )
            {
            
            //UniSmilUtils::GetRegionId( node, value );
            if( ((CMDXMLElement*) node)->IsAttributeSpecified( KSMILWRParaId ) )
                {
                ((CMDXMLElement*) node)->GetAttribute( KSMILWRParaId, value );
                }
            else
                {
                value.Set( KNullDesC );
                }
            
            // IMAGE REGION
            if ( value.CompareF( iImageRegionId ) == 0 )
                {
                aImgEle = (CMDXMLElement*) node;
                }
            
            // TEXT REGION
            else if ( value.CompareF( iTextRegionId ) == 0 )
                {
                aTxtEle = (CMDXMLElement*) node;
                }
            
            }
        else if ( node->NodeName().CompareF( KSMILWREleRoot_layout ) == 0 )
            {
            aRlEle = (CMDXMLElement*) node;
            }
        
        node = node->NextSibling();
        
        }
    }

// ---------------------------------------------------------
// CUniSmilModel::GetMmsSmilLayout
// 
// ---------------------------------------------------------
TUniLayout CUniSmilModel::GetMmsSmilLayout( CMDXMLDocument* aDom )
    {
    TUniLayout rval = EUniUndefinedLayout;

    iTextRegionId.Set( KNullDesC );
    iImageRegionId.Set( KNullDesC );

    // --------------------------------------------
    // Resolve region IDs used in media elements
    // --------------------------------------------
    CMDXMLNode* node = GetNode( aDom, KSMILWREleBody );
    if ( !node )
        {
        return rval;
        }

    // Only one slide in the message since no <par> tag found
    // Other node types than <par> not possible as this is MMS SMIL.
    if ( node->FirstChild() )
        {
        if ( node->FirstChild()->NodeName().CompareF( KSMILWRElePar ) != 0 )
            {
            GetMediaElemRegionIDs( node );
            }
        else
            {
            CMDXMLNode* page = node->FirstChild();
            while ( page )
                {
                GetMediaElemRegionIDs( page );

                // Go to next page.
                page = page->NextSibling();
                }
            }
        }

    // -------------------------------------
    // Search layout elements
    // -------------------------------------
    node = GetNode( aDom, KSMILWREleLayout );
    CMDXMLElement* rootLayout = NULL;
    CMDXMLElement* textRegion = NULL;
    CMDXMLElement* imageRegion = NULL;
    GetLayoutElements( node, rootLayout, textRegion, imageRegion );

    // ------------------------------
    // Resolve Root Layout
    // ------------------------------
    TSize rootSize( 0, 0 );
    GetRootLayoutSize( rootLayout, rootSize );

    // ------------------------------------
    // Resolve region parameters
    // ------------------------------------
    TRect imgRect( 0, 0, 0, 0 );
    TRect txtRect( 0, 0, 0, 0 );
    GetRegionRect( imageRegion, rootSize, imgRect );
    GetRegionRect( textRegion, rootSize, txtRect );

    // ------------------------------------
    // Layout decision
    // ------------------------------------
    if ( textRegion && imageRegion )
        {
        if( imgRect.iTl.iY < txtRect.iTl.iY )
            {
            rval =  EUniImageFirst;
            }
        else if ( imgRect.iTl.iY > txtRect.iTl.iY )
            {
            rval = EUniTextFirst;
            }
        else
            {
            if ( imgRect.iTl.iX <= txtRect.iTl.iX )
                {
                rval = EUniImageFirst;
                }
            else
                {
                rval = EUniTextFirst;
                }
            }
        }
    else if ( textRegion )
        {
        rval = EUniTextFirst;
        }
    else // if ( iImgEle ) or none
        {
        rval = EUniImageFirst;
        }

    return rval;

    }

// ---------------------------------------------------------
// CUniSmilModel::GetRootLayoutSize
// 
// ---------------------------------------------------------

void CUniSmilModel::GetRootLayoutSize( CMDXMLElement* aRl, TSize& aSize )
    {
    TPtrC value( KNullDesC );

    if ( aRl )
        {
        if( aRl->IsAttributeSpecified( KSMILWRParaWidth ) )
            {
            aRl->GetAttribute( KSMILWRParaWidth, value );
            aSize.iWidth = UniSmilUtils::StringToIntValue( value, 0 );
            }
        else
            {
            aSize.iWidth = iScreenSize.iWidth;
            }
        
        if( aRl->IsAttributeSpecified( KSMILWRParaHeight ) )
            {
            aRl->GetAttribute( KSMILWRParaHeight, value );
            aSize.iHeight = UniSmilUtils::StringToIntValue( value, 0 );
            }
        else
            {
            aSize.iHeight = iScreenSize.iHeight;
            }
        }
    else
        {
        aSize = iScreenSize;
        }
    }

// ---------------------------------------------------------
// CUniSmilModel::GetRegionRect
// 
// ---------------------------------------------------------

void CUniSmilModel::GetRegionRect( CMDXMLElement* aRegion, TSize aRoot, TRect& aRect )
    {
    TPtrC value;

    TInt width = 0;
    TInt height = 0;

    if ( aRegion )
        {
        if( aRegion->IsAttributeSpecified( KSMILWRParaWidth ) )
            {
            aRegion->GetAttribute( KSMILWRParaWidth, value );
            width = UniSmilUtils::StringToIntValue( value, 0 ) ;
            if ( value.Locate( '%' ) != KErrNotFound )
                {
                width = width * aRoot.iWidth / 100;
                }
            }
        
        if( aRegion->IsAttributeSpecified( KSMILWRParaHeight ) )
            {
            aRegion->GetAttribute( KSMILWRParaHeight, value );
            height = UniSmilUtils::StringToIntValue( value, 0 ) ;
            if ( value.Locate( '%' ) != KErrNotFound )
                {
                height = height * aRoot.iHeight / 100;
                }
            }

        if( aRegion->IsAttributeSpecified( KSMILWRParaTop ) )
            {
            aRegion->GetAttribute( KSMILWRParaTop, value );
            aRect.iTl.iY = UniSmilUtils::StringToIntValue( value, 0 );
            if ( value.Locate( '%' ) != KErrNotFound )
                {
                aRect.iTl.iY = aRect.iTl.iY * aRoot.iHeight / 100;
                }
            }
        else
            {
            aRect.iTl.iY = 0;
            }

        if( aRegion->IsAttributeSpecified( KSMILWRParaLeft ) )
            {
            aRegion->GetAttribute( KSMILWRParaLeft, value );
            aRect.iTl.iX = UniSmilUtils::StringToIntValue( value, 0 );
            if ( value.Locate( '%' ) != KErrNotFound )
                {
                aRect.iTl.iX = aRect.iTl.iX * aRoot.iWidth / 100;
                }
            }
        else
            {
            aRect.iTl.iX = 0;
            }

        aRect.iBr.iY = aRect.iTl.iY + height;
        aRect.iBr.iX = aRect.iTl.iX + width;

        }
    else
        {
        aRect = TRect( 0, 0, 0, 0 );
        }
    }

// ---------------------------------------------------------
// CUniSmilModel::GetRegionType
// ---------------------------------------------------------
//
TUniRegion CUniSmilModel::GetRegionType( CMDXMLNode* aNodePtr ) 
    {
    if ( iImageRegionId.CompareF( iTextRegionId ) == 0 )
        {
        // Image and text regions are the same!
        // Literally taken this is agains MMS SMIL, but
        // we should still tolerate it.
        iParseResult |= ETextAndImageRegionsSame;
        return EUniRegionUnresolved;
        }
    TPtrC regId;
    TInt err = UniSmilUtils::GetRegionId( aNodePtr, regId );
    if ( !err )
        {
        if ( regId.CompareF( iImageRegionId ) == 0 )
            {
            return EUniRegionImage;
            }
        else if ( regId.CompareF( iTextRegionId ) == 0 )
            {
            return EUniRegionText;
            }
        else
            {
            return EUniRegionUnresolved;
            }
        }
    else
        {
        return EUniRegionUnresolved;
        }
    }


// ---------------------------------------------------------
// CUniSmilModel::GetNode
// 
// ---------------------------------------------------------
CMDXMLNode* CUniSmilModel::GetNode( CMDXMLDocument* aDom, const TDesC& aName )
    {
    CMDXMLNode* node = aDom->DocumentElement()->FirstChild();
    while ( node )
        {
        if ( node->NodeName().CompareF( aName ) == 0 )
            {
            break;
            }
        else 
            {
            node = UniSmilUtils::NextNode( node );
            }
        }
    return node;
    }

// ---------------------------------------------------------
// CUniSmilModel::RemoveMetaTagsAndComments
// 
// ---------------------------------------------------------
void CUniSmilModel::RemoveMetaTagsAndComments( CMDXMLDocument* aDom )
    {
    CMDXMLNode* node = aDom->DocumentElement()->FirstChild();
    while ( node )
        {
        if ( node->NodeType() == CMDXMLNode::ECommentNode ||
            node->NodeName().CompareF( KSMILWREleMeta ) == 0 )
            {
            CMDXMLNode* removeNode = node;
            node = removeNode->ParentNode();
            /*TInt ignore =*/ node->RemoveChild( removeNode );
            delete removeNode;
            }
        node = UniSmilUtils::NextNode( node );
        }
    }

// ---------------------------------------------------------
// CUniSmilModel::CorrectSlideTimingL
// 
// ---------------------------------------------------------
void CUniSmilModel::CorrectSlideTimingL( CMDXMLElement* aPage ) 
    {
    CMDXMLNode* node = aPage->FirstChild();
    
    // Traverse through every object in page.
    while ( node != NULL )
        {
        if ( UniSmilUtils::IsMediaElem( node ) )
            {
            CMDXMLElement* nodeElement = static_cast<CMDXMLElement*>( node );
                   
            CUniObject* obj = iObjectList.GetByNodeL( node );
            
            if( !obj ||
                !obj->MediaInfo() ||
                obj->MediaInfo()->Duration() != 0 ||
                TimingSpecified( nodeElement ) )
                {
                // Return as non-static media was found from the page.
                return;
                }
            else if ( nodeElement->IsAttributeSpecified( KSMILWRParaBegin ) )
                {
                // Remove invalid Begin element since no End or Dur attributes is specified.
                nodeElement->RemoveAttribute( KSMILWRParaBegin );
                }
            else if ( nodeElement->IsAttributeSpecified( KSMILWRParaEnd ) )
                {
                // Remove invalid End element since no Begin or Dur attributes is specified.
                nodeElement->RemoveAttribute( KSMILWRParaEnd );
                }
            }
            
        node = node->NextSibling();
        }
    
    // Read default smil parameters
    if ( !iSmilParams )
        {
        iSmilParams = CUniSmilParams::NewL( iFs );
        }
            
    TBuf16<20> defaultVal;
    defaultVal.Zero();
    defaultVal.Format( KSmilMsecFormat, iSmilParams->iComposeParams->iSlideDuration );
   
    aPage->SetAttributeL( KSMILWRParaDur, defaultVal );
    }
    
// ---------------------------------------------------------
// CUniSmilModel::TimingSpecified
// 
// ---------------------------------------------------------
TBool CUniSmilModel::TimingSpecified( CMDXMLElement* aNodePrt )
    {
    TBool result( EFalse );
    
    // Timing is set if dur or begin & end parameters are found
    if ( aNodePrt &&
         ( aNodePrt->IsAttributeSpecified( KSMILWRParaDur ) ||
           ( aNodePrt->IsAttributeSpecified( KSMILWRParaBegin ) &&
             aNodePrt->IsAttributeSpecified( KSMILWRParaEnd ) ) ) )
            {
            result = ETrue;
            }
            
    return result;
    }

// End of file
