/*
* Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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 TDdParser.   
*      
*
*/


// INCLUDE FILES

#include "DdParser.h"
#include "CodData.h"
#include "CodError.h"
#include "CodPanic.h"
#include "CodLogger.h"
#include "NwUtil.h"
#include "DdDummyDict.h"
#include "HttpDownloadData.h"
#include <nw_dom_document.h>
#include <utf.h>

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

// Attribute names.
_LIT( KDdName, "name" );                        ///< name.
_LIT( KDdVendor, "vendor" );                    ///< vendor.
_LIT( KDdDescription, "description" );          ///< description.
_LIT( KDdUrl, "objectURI" );                    ///< objectURI.
_LIT( KDdSize, "size" );                        ///< size.
_LIT( KDdType, "type" );                        ///< type.
_LIT( KDdInstallNotify, "installNotifyURI" );   ///< installNotifyURI.
_LIT( KDdNextUrl, "nextURL" );                  ///< nextURL.
_LIT( KDdInfoUrl, "infoURL" );                  ///< infoURL.
_LIT( KDdIcon, "iconURI" );                     ///< iconURI.
_LIT( KDdVersion, "DDVersion" );                ///< DDVersion.
_LIT( KDdMedia, "media" );                      ///< media.
// Attribute names for OMA v2 
_LIT( KDdProduct, "product" );                  ///< media.
_LIT( KDdMediaObject, "mediaObject" );          ///< mediaObject.
_LIT( KDdMeta, "meta" );                        ///< meta.
_LIT( KDdProgressiveDl, "progressiveDownloadFlag" );    ///< progressiveDownloadFlag.
_LIT( KDdLicense, "license" );                  ///< license.
_LIT( KDdOrder, "order" );                      ///< order.
_LIT( KDdSuppressUserConfirmation, "suppressUserConfirmation" ); ///< suppressUserConfirmation.
_LIT( KDdServer, "server" );                    ///< server.
_LIT( KDdText, "text" );						///< text.
_LIT( KDdTrue, "true" );                        ///< true.
_LIT( KDdFalse, "false" );                      ///< false.
_LIT( KDdAlways, "Always" );                    ///< Always.
_LIT( KDdUserConfirmStepOnly, "UserConfirmaStepOnly" );  ///< UserConfirmStepOnly.
_LIT( KDdNever, "Never" );                      ///< Never.
_LIT( KDdPost, "post" );                        ///< post.
_LIT( KDdAny, "any" );                          ///< any.
_LIT( KDdUpdatedDDURI, "updatedDDURI" );//updatedDDURI


#define INDENT_SPACE 2

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

// ---------------------------------------------------------
// TDdParser::ParseL()
// ---------------------------------------------------------
//
void TDdParser::ParseL( const TDesC& aBuf, CCodData& aData, const TBool aIsDd2, TBool& aIsLicenseTag )
    {
    CLOG(( EParse, 2, _L("-> TDdParser::ParseL") ));
    CDUMP(( EParse, 2, _S("Buf:"), _S("    "), \
        (const TUint8*)aBuf.Ptr(), aBuf.Size() ));
    iError = KErrNone;
    iData = &aData;
    // XML Parser expects the buffer contain a BOM and be in
    // network byte order (this is hard-coded into cXmlParser).
    // We already have the buffer converted to UCS-2, native byte order, BOM
    // removed, and this cannot be changed without changing API.
    // So we have to re-add BOM and convert the buffer back to network byte
    // order. This is an annoying a waste, luckily a DD file is small
    // enough not to be significant.
    HBufC* buf = HBufC::NewLC( aBuf.Length() + 1 );
    buf->Des().Append( 0xFFFE );    // Add BOM, little endian as aBuf.
    buf->Des().Append( aBuf );      // Append buffer.
    // Now turn the whole buffer big-endian.
    TUint8* ptr = (TUint8*)buf->Ptr();
    for ( TInt i = 0; i < buf->Size(); i += 2 )
        {
        TUint8 tmp = ptr[i];
        ptr[i] = ptr[i + 1];
        ptr[i + 1] = tmp;
        }
    NW_WBXML_Dictionary_t* dictArray[ 1 ] = 
        { (NW_WBXML_Dictionary_t*)&NW_DdDummy_WBXMLDictionary };
    RNwWbxmlDictionary wbxmlDict;
    User::LeaveIfError( wbxmlDict.Initialize( 1, dictArray ) );
    CleanupClosePushL<RNwWbxmlDictionary>( wbxmlDict );

    NW_TinyDom_Handle_t domHandle;
    NW_Status_t stat;
    CNwDomDocumentNode* docNode = new (ELeave) CNwDomDocumentNode();
    CleanupStack::PushL( docNode );
    docNode->iDocNode = CXML_DOM_DocumentNode_BuildTree
        ( 
        &domHandle, 
        (NW_Byte*)buf->Ptr(), 
        (NW_Int32)buf->Size(), 
        /*encoded=*/NW_FALSE, 
        /*publicID=*/NW_DdDummy_PublicId, 
        /*extTNotStringTable=*/NW_FALSE,
        &stat
        );
    LeaveIfNwErrorL( stat );
    User::LeaveIfNull( docNode->iDocNode ); // Safety code.
    if (!aIsDd2)
	{
	  DocNodeL( docNode->iDocNode );
	}
    else
	{
	  iIsLicenseTag = EFalse;
	  ParseDd2DocNodeL( docNode->iDocNode );
	}
    CleanupStack::PopAndDestroy( 3, buf );  // docNode, close wbxmlDict, buf

#ifdef __TEST_COD_LOG
    TPtrC ptr16;
    TPtrC8 ptr8;
    CLOG(( EParse, 3, _L("TCodParser::ParseL data:") ));
    ptr16.Set( aData.Name() );
    CLOG(( EParse, 3, _L("  Name<%S>"), &ptr16 ));
    ptr16.Set( aData.Vendor() );
    CLOG(( EParse, 3, _L("  Vendor<%S>"), &ptr16 ));
    ptr16.Set( aData.Description() );
    CLOG(( EParse, 3, _L("  Desc<%S>"), &ptr16 ));
    CLOG(( EParse, 3, _L("  Size(%d)"), aData.Size() ));
    ptr8.Set( aData.InstallNotify() );
    CLOG(( EParse, 3, _L8("  InstNotif<%S>"), &ptr8 ));
    ptr8.Set( aData.NextUrl() );
    CLOG(( EParse, 3, _L8("  NextUrl<%S>"), &ptr8 ));
    ptr8.Set( aData.NextUrlAtError() );
    CLOG(( EParse, 3, _L8("  NextUrlAtErr<%S>"), &ptr8 ));
    ptr8.Set( aData.InfoUrl() );
    CLOG(( EParse, 3, _L8("  InfoUrl<%S>"), &ptr8 ));
    ptr16.Set( aData.Price() );
    CLOG(( EParse, 3, _L("  Price<%S>"), &ptr16 ));
    ptr8.Set( aData.Icon() );
    CLOG(( EParse, 3, _L8("  Icon<%S>"), &ptr8 ));

//TODO add logs for OMA 2
#endif /* def __TEST_COD_LOG */
	
	//If there are no media objects present to download, 
    if( !iData->Count() )
    	{
    	User::Leave( KErrCodInvalidDescriptor );	
    	}
    	
    // NULL data for clarity. These are never used later, but don't keep
    // pointers to objects which are out of reach.
    iData = NULL;
    User::LeaveIfError( iError );
    aIsLicenseTag = iIsLicenseTag;
    CLOG(( EParse, 2, _L("<- TDdParser::ParseL") ));
    }

// ---------------------------------------------------------
// TDdParser::DocNodeL()
// ---------------------------------------------------------
//
void TDdParser::DocNodeL( NW_DOM_DocumentNode_t* aDocNode )
    {
    CLOG(( EParse, 2, _L("-> TDdParser::DocNodeL") ));
    __ASSERT_DEBUG( aDocNode, CodPanic( ECodInternal ) );
    // Validity checking of root element (media).
    NW_DOM_ElementNode_t* elmt = 
        NW_DOM_DocumentNode_getDocumentElement( aDocNode );
    if ( !elmt || NW_DOM_Node_getNodeType( elmt ) != NW_DOM_ELEMENT_NODE )
        {
        User::Leave( KErrCodInvalidDescriptor );
        }
    NW_String_t str;
    LeaveIfNwErrorL( NW_DOM_Node_getNodeName( elmt, &str ) );
    CleanupNwStringStoragePushL( &str );
    iEncoding = NW_DOM_DocumentNode_getCharacterEncoding( aDocNode );
    NW_Ucs2* name;
    LeaveIfNwErrorL( NW_String_stringToUCS2Char( &str, iEncoding, &name ) );
    CleanupNwUcs2PushL( name );
    if ( TPtrC( name ).Compare( KDdMedia() ) )
        {
        User::Leave( KErrCodInvalidDescriptor );
        }
    CleanupStack::PopAndDestroy( 2 );   // clean up name, str->storage

    // Process child element nodes.
    NW_DOM_Node_t* node = NW_DOM_Node_getFirstChild( elmt );
    CMediaObjectData *mediaObject = CMediaObjectData::NewL();
    while ( node )
        {
        if ( NW_DOM_Node_getNodeType( node ) == NW_DOM_ELEMENT_NODE )
            {
            ElementNodeL( STATIC_CAST( NW_DOM_ElementNode_t*, node ), mediaObject );
            }
        node = NW_DOM_Node_getNextSibling( node );
        }
	iData->AppendMediaObjectL( mediaObject );        
    CLOG(( EParse, 2, _L("<- TDdParser::DocNodeL") ));
    }

// ---------------------------------------------------------
// TDdParser::ParseDd2DocNodeL()
// ---------------------------------------------------------
//
void TDdParser::ParseDd2DocNodeL( NW_DOM_DocumentNode_t* aDocNode )
{
    CLOG(( EParse, 2, _L("-> TDdParser::ParseDd2DocNodeL") ));
    __ASSERT_DEBUG( aDocNode, CodPanic( ECodInternal ) );
    // Validity checking of root element (media).
    NW_DOM_ElementNode_t* elmt = 
        NW_DOM_DocumentNode_getDocumentElement( aDocNode );
    if ( !elmt || NW_DOM_Node_getNodeType( elmt ) != NW_DOM_ELEMENT_NODE )
        {
        User::Leave( KErrCodInvalidDescriptor );
        }
    NW_String_t str;
    LeaveIfNwErrorL( NW_DOM_Node_getNodeName( elmt, &str ) );
    CleanupNwStringStoragePushL( &str );
    iEncoding = NW_DOM_DocumentNode_getCharacterEncoding( aDocNode );
    NW_Ucs2* name;
    LeaveIfNwErrorL( NW_String_stringToUCS2Char( &str, iEncoding, &name ) );
    CleanupNwUcs2PushL( name );
    if ( TPtrC( name ).Compare( KDdMedia() ) )
        {
        User::Leave( KErrCodInvalidDescriptor );
        }
    CleanupStack::PopAndDestroy( 2 );   // clean up name, str->storage
    ParseMediaElementsL( elmt );
    CLOG(( EParse, 2, _L("<- TDdParser::ParseDd2DocNodeL") ));
}

// ---------------------------------------------------------
// TDdParser::ParseMediaElementsL()
// ---------------------------------------------------------
//
void TDdParser::ParseMediaElementsL( NW_DOM_ElementNode_t* aElement)
{
    CLOG(( EParse, 2, _L("-> TDdParser::ParseMediaElementsL") ));

    // Process child elements for Media Object
    NW_DOM_Node_t* node = NW_DOM_Node_getFirstChild( aElement );
    while ( node )
        {
        if ( NW_DOM_Node_getNodeType( node ) == NW_DOM_ELEMENT_NODE )
            {
            MediaElementNodeL( STATIC_CAST( NW_DOM_ElementNode_t*, node ) );
            }
        node = NW_DOM_Node_getNextSibling( node );
        }

	// Get Attributs for this node
    NW_Status_t stat = NW_STAT_SUCCESS;

    if ( NW_DOM_ElementNode_hasAttributes( aElement ) )
        {

        NW_DOM_AttributeListIterator_t attrIter;
        stat = NW_DOM_ElementNode_getAttributeListIterator
                             ( aElement, &attrIter );

        User::LeaveIfError( NwStatus2Error( stat ) );
        NW_DOM_AttributeHandle_t attrHandle;
        while( NW_DOM_AttributeListIterator_getNextAttribute( &attrIter, &attrHandle ) == NW_STAT_WBXML_ITERATE_MORE )
            {
            ParseNodeAttributesL( &attrHandle );
            }
        }

	CLOG(( EParse, 2, _L("<- TDdParser::ParseMediaElementsL") ));
}

// ---------------------------------------------------------
// TDdParser::ParseProductElementsL()
// ---------------------------------------------------------
//
void TDdParser::ParseProductElementsL( NW_DOM_ElementNode_t* aElement)
{
    CLOG(( EParse, 2, _L("-> TDdParser::ParseProductElementsL") ));
    // Process child elements for Product  Object
    NW_DOM_Node_t* node = NW_DOM_Node_getFirstChild( aElement );
    while ( node )
        {
        if ( NW_DOM_Node_getNodeType( node ) == NW_DOM_ELEMENT_NODE )
            {
            ProductElementNodeL( STATIC_CAST( NW_DOM_ElementNode_t*, node ) );
            }
        node = NW_DOM_Node_getNextSibling( node );
        }
	CLOG(( EParse, 2, _L("<- TDdParser::ParseProductElementsL") ));
}

// ---------------------------------------------------------
// TDdParser::ParseMediaObjectElementsL()
// ---------------------------------------------------------
//
void TDdParser::ParseMediaObjectElementsL( NW_DOM_ElementNode_t* aElement)
{
    CLOG(( EParse, 2, _L("-> TDdParser::ParseMediaObjectElementsL") ));
    //Create a media object and append it to Cod Data array
    CMediaObjectData *mediaObject = CMediaObjectData::NewL();

    // Process child elements for MediaObject
    NW_DOM_Node_t* node = NW_DOM_Node_getFirstChild( aElement );
    while ( node )
        {
        if ( NW_DOM_Node_getNodeType( node ) == NW_DOM_ELEMENT_NODE )
            {
            MediaObjElementNodeL( STATIC_CAST( NW_DOM_ElementNode_t*, node), mediaObject );
            }
        node = NW_DOM_Node_getNextSibling( node );
        }

    if(!mediaObject->Name().Compare(KNullDesC) && mediaObject->Url().Compare(KNullDesC8))
        {
        ParseNameFromUrlL( mediaObject );
        }
    iData->AppendMediaObjectL( mediaObject );              
    
	CLOG(( EParse, 2, _L("<- TDdParser::ParseMediaObjectElementsL") ));
}

// ---------------------------------------------------------
// TDdParser::ParseMetaElementsL()
// ---------------------------------------------------------
//
void TDdParser::ParseMetaElementsL( NW_DOM_ElementNode_t* aElement)
{
	CLOG(( EParse, 2, _L("-> TDdParser::ParseMetaElementsL") ));
    // Process child elements foe Media Object
    NW_DOM_Node_t* node = NW_DOM_Node_getFirstChild( aElement );
    while ( node )
        {
        if ( NW_DOM_Node_getNodeType( node ) == NW_DOM_ELEMENT_NODE )
            {
            MetaElementNodeL( STATIC_CAST( NW_DOM_ElementNode_t*, node ) );
            }
        node = NW_DOM_Node_getNextSibling( node );
        }
	CLOG(( EParse, 2, _L("<- TDdParser::ParseMetaElementsL") ));
}

// ---------------------------------------------------------
// TDdParser::ParseMetaElementsL()
// ---------------------------------------------------------
//
void TDdParser::ParseMetaElementsL( NW_DOM_ElementNode_t* aElement, CMediaObjectData *& aMediaObject )
{
	CLOG(( EParse, 2, _L("-> TDdParser::ParseMetaElementsL") ));
    // Process child elements foe Media Object
    NW_DOM_Node_t* node = NW_DOM_Node_getFirstChild( aElement );
    while ( node )
        {
        if ( NW_DOM_Node_getNodeType( node ) == NW_DOM_ELEMENT_NODE )
            {
            MetaElementNodeL( STATIC_CAST( NW_DOM_ElementNode_t*, node ), aMediaObject );
            }
        node = NW_DOM_Node_getNextSibling( node );
        }
	CLOG(( EParse, 2, _L("<- TDdParser::ParseMetaElementsL") ));
}

// ---------------------------------------------------------
// TDdParser::ParseObjectUriElementsL()
// ---------------------------------------------------------
//
void TDdParser::ParseObjectUriElementsL( NW_DOM_ElementNode_t* aElement, CMediaObjectData *& aMediaObject )
{
	CLOG(( EParse, 2, _L("-> TDdParser::ParseObjectUriElementsL") ));
    // Process child elements for Media Object
    NW_DOM_Node_t* node = NW_DOM_Node_getFirstChild( aElement );
    while ( node )
        {
        if ( NW_DOM_Node_getNodeType( node ) == NW_DOM_ELEMENT_NODE )
            {
            ObjUriElementNodeL( STATIC_CAST( NW_DOM_ElementNode_t*, node ), aMediaObject );
            }
        node = NW_DOM_Node_getNextSibling( node );
        }
	CLOG(( EParse, 2, _L("<- TDdParser::ParseObjectUriElementsL") ));
}

// ---------------------------------------------------------
// TDdParser::MediaElementNodeL()
// ---------------------------------------------------------
//
void TDdParser::MediaElementNodeL( NW_DOM_ElementNode_t* aElmtNode )
    {
    CLOG(( EParse, 2, _L("-> TDdParser::MediaElementNodeL") ));
    __ASSERT_DEBUG( aElmtNode, CodPanic( ECodInternal ) );

    NW_String_t str;
    LeaveIfNwErrorL( NW_DOM_Node_getNodeName( aElmtNode, &str ) );
    CleanupNwStringStoragePushL( &str );
    NW_Ucs2* ucs2;
    LeaveIfNwErrorL( NW_String_stringToUCS2Char( &str, iEncoding, &ucs2 ) );
    CleanupNwUcs2PushL( ucs2 );
    TPtrC attrName( ucs2 );
    TDdAttr attr = MediaAttribute( attrName );
    CLOG(( EParse, 4, _L("  attribute <%S> (%d)"), &attrName, attr ));
    CleanupStack::PopAndDestroy( 2 );   // Clean up ucs2, str->storage
	if ( attr == EDdProduct )
	{	
	    if( iData && !iData->Count() )
	        {
    		ParseProductElementsL(aElmtNode);
	        }
		return;
	}
    if ( attr != EDdUnknownAttr )   // Unknown attribute is ignored.
        {
        ucs2 = PcDataLC( aElmtNode );
        if ( ucs2 )
            {
            SetMediaAttrL( attr, TPtrC( ucs2 ) );
            }
        CleanupStack::PopAndDestroy();  // Clean up ucs2.
        }
    CLOG(( EParse, 2, _L("<- TDdParser::MediaElementNodeL") ));
    }

// ---------------------------------------------------------
// TDdParser::ParseNodeAttributesL()
// ---------------------------------------------------------
//
void TDdParser::ParseNodeAttributesL( NW_DOM_AttributeHandle_t* aAttrHandle )
{
	CLOG(( EParse, 2, _L("-> TDdParser::ParseNodeAttributesL") ));
    NW_Status_t stat = NW_STAT_SUCCESS;
    NW_String_t str;
    // Get the name of the attribute.
    stat = NW_DOM_AttributeHandle_getName( aAttrHandle, &str );
    User::LeaveIfError( NwStatus2Error( stat ) );

    CleanupNwStringStoragePushL( &str );
    NW_Ucs2* ucs2;
    LeaveIfNwErrorL( NW_String_stringToUCS2Char( &str, iEncoding, &ucs2 ) );
    CleanupNwUcs2PushL( ucs2 );

    TPtrC attrName( ucs2 );
    TDdAttr attr = DdVersionAttribute( attrName );
	CleanupStack::PopAndDestroy( 2 );   // Clean up ucs2, str->storage
    if ( attr != EDdUnknownAttr )   // Unknown attribute is ignored.
		{
        LeaveIfNwErrorL(NW_DOM_AttributeHandle_getValue(aAttrHandle, &str) );
        LeaveIfNwErrorL( NW_String_stringToUCS2Char(&str, iEncoding, &ucs2) );
        if ( ucs2 )
            {
			if ( (attr == EDdVersion))
				{
				iData->SetVersionL( TPtrC ( ucs2 ));
				}
            }
        }
    CLOG(( EParse, 2, _L("<- TDdParser::ParseNodeAttributesL") ));
}

// ---------------------------------------------------------
// TDdParser::ObjUriElementNodeL()
// ---------------------------------------------------------
//
void TDdParser::ObjUriElementNodeL( NW_DOM_ElementNode_t* aElmtNode, CMediaObjectData *& aMediaObject )
    {
	CLOG(( EParse, 2, _L("-> TDdParser::ObjUriElementNodeL") ));
    __ASSERT_DEBUG( aElmtNode, CodPanic( ECodInternal ) );
    NW_String_t str;
    LeaveIfNwErrorL( NW_DOM_Node_getNodeName( aElmtNode, &str ) );
    CleanupNwStringStoragePushL( &str );
    NW_Ucs2* ucs2;
    LeaveIfNwErrorL( NW_String_stringToUCS2Char( &str, iEncoding, &ucs2 ) );
    CleanupNwUcs2PushL( ucs2 );

    TPtrC attrName( ucs2 );
    TDdAttr attr = ObjUriAttribute( attrName );
	CleanupStack::PopAndDestroy( 2 );   // Clean up ucs2, str->storage
	TInt ok( EFalse );
    if ( attr != EDdUnknownAttr )   // Unknown attribute is ignored.
		{
        ucs2 = PcDataLC( aElmtNode );
        if ( ucs2 )
            {
			/* composite objects (multiple server elements) are not supported in 3.2
			   So, it takes last ObjectUri
			*/
			if ( (attr == EDdUrl))
				{
				ok = aMediaObject->SetUrlL( TPtrC ( ucs2 ));
				}
            }
        CleanupStack::PopAndDestroy();  // Clean up ucs2.
        }
		if ( !ok )
			{
			Error( KErrCodInvalidDescriptor );
			}
		CLOG(( EParse, 2, _L("<- TDdParser::ObjUriElementNodeL") ));
    }

// ---------------------------------------------------------
// TDdParser::MediaObjElementNodeL()
// ---------------------------------------------------------
//
void TDdParser::MediaObjElementNodeL( NW_DOM_ElementNode_t* aElmtNode, CMediaObjectData *& aMediaObject )
    {
    CLOG(( EParse, 2, _L("-> TDdParser::MediaObjElementNodeL") ));
    __ASSERT_DEBUG( aElmtNode, CodPanic( ECodInternal ) );
    NW_String_t str;
    LeaveIfNwErrorL( NW_DOM_Node_getNodeName( aElmtNode, &str ) );
    CleanupNwStringStoragePushL( &str );
    NW_Ucs2* ucs2;
    LeaveIfNwErrorL( NW_String_stringToUCS2Char( &str, iEncoding, &ucs2 ) );
    CleanupNwUcs2PushL( ucs2 );
    TPtrC attrName( ucs2 );
    TDdAttr attr = MediaObjAttribute( attrName );
    CLOG(( EParse, 4, _L("  attribute <%S> (%d)"), &attrName, attr ));
    CleanupStack::PopAndDestroy( 2 );   // Clean up ucs2, str->storage
	if ( attr == EDdMeta )
	{
		ParseMetaElementsL(aElmtNode, aMediaObject );
		return;
	}
	if ( attr == EDdUrl )
	{
		ParseObjectUriElementsL(aElmtNode, aMediaObject );
		return;
	}
    if ( attr != EDdUnknownAttr )   // Unknown attribute is ignored.
        {
        ucs2 = PcDataLC( aElmtNode );
        if ( ucs2 )
            {
            SetMediaObjAttrL( attr, TPtrC( ucs2 ), aMediaObject );
            }
        CleanupStack::PopAndDestroy();  // Clean up ucs2.
        }
    CLOG(( EParse, 2, _L("<- TDdParser::MediaObjElementNodeL") ));
    }

// ---------------------------------------------------------
// TDdParser::ProductElementNodeL()
// ---------------------------------------------------------
//
void TDdParser::ProductElementNodeL( NW_DOM_ElementNode_t* aElmtNode )
    {
	CLOG(( EParse, 2, _L("-> TDdParser::ProductElementNodeL") ));
	__ASSERT_DEBUG( aElmtNode, CodPanic( ECodInternal ) );
	NW_String_t str;
	LeaveIfNwErrorL( NW_DOM_Node_getNodeName( aElmtNode, &str ) );
	CleanupNwStringStoragePushL( &str );
	NW_Ucs2* ucs2;
	LeaveIfNwErrorL( NW_String_stringToUCS2Char( &str, iEncoding, &ucs2 ) );
	CleanupNwUcs2PushL( ucs2 );
	TPtrC attrName( ucs2 );
	TDdAttr attr = ProductAttribute( attrName );
	CLOG(( EParse, 4, _L("  attribute <%S> (%d)"), &attrName, attr ));
	CleanupStack::PopAndDestroy( 2 );   // Clean up ucs2, str->storage
	if ( attr == EDdMeta )
	{
		ParseMetaElementsL(aElmtNode);
	}
	if ( attr == EDdMediaObject )
	{
		ParseMediaObjectElementsL(aElmtNode);
	}
	CLOG(( EParse, 2, _L("<- TDdParser::ProductElementNodeL") ));
    }

// ---------------------------------------------------------
// TDdParser::MetaElementNodeL()
// ---------------------------------------------------------
//
void TDdParser::MetaElementNodeL( NW_DOM_ElementNode_t* aElmtNode )
    {
    CLOG(( EParse, 2, _L("-> TDdParser::MetaElementNodeL") ));
    __ASSERT_DEBUG( aElmtNode, CodPanic( ECodInternal ) );
    NW_String_t str;
    LeaveIfNwErrorL( NW_DOM_Node_getNodeName( aElmtNode, &str ) );
    CleanupNwStringStoragePushL( &str );
    NW_Ucs2* ucs2;
    LeaveIfNwErrorL( NW_String_stringToUCS2Char( &str, iEncoding, &ucs2 ) );
    CleanupNwUcs2PushL( ucs2 );
    TPtrC attrName( ucs2 );
    TDdAttr attr = MetaAttribute( attrName );
    CLOG(( EParse, 4, _L("  attribute <%S> (%d)"), &attrName, attr ));
    CleanupStack::PopAndDestroy( 2 );   // Clean up ucs2, str->storage
	if ( attr == EDdLicense )
	{
		iIsLicenseTag = ETrue;
		return;
	}
    if ( attr != EDdUnknownAttr )   // Unknown attribute is ignored.
        {
        ucs2 = PcDataLC( aElmtNode );
        if ( ucs2 )
            {
            SetMetaAttrL( attr, TPtrC( ucs2 ) );
            }
        CleanupStack::PopAndDestroy();  // Clean up ucs2.
        }
    CLOG(( EParse, 2, _L("<- TDdParser::MetaElementNodeL") ));
    }

// ---------------------------------------------------------
// TDdParser::MetaElementNodeL()
// ---------------------------------------------------------
//
void TDdParser::MetaElementNodeL( NW_DOM_ElementNode_t* aElmtNode, CMediaObjectData *& aMediaObject )
    {
    CLOG(( EParse, 2, _L("-> TDdParser::MetaElementNodeL") ));
    __ASSERT_DEBUG( aElmtNode, CodPanic( ECodInternal ) );
    NW_String_t str;
    LeaveIfNwErrorL( NW_DOM_Node_getNodeName( aElmtNode, &str ) );
    CleanupNwStringStoragePushL( &str );
    NW_Ucs2* ucs2;
    LeaveIfNwErrorL( NW_String_stringToUCS2Char( &str, iEncoding, &ucs2 ) );
    CleanupNwUcs2PushL( ucs2 );
    TPtrC attrName( ucs2 );
    TDdAttr attr = MetaAttribute( attrName );
    CLOG(( EParse, 4, _L("  attribute <%S> (%d)"), &attrName, attr ));
    CleanupStack::PopAndDestroy( 2 );   // Clean up ucs2, str->storage
	if ( attr == EDdLicense )
	{
		iIsLicenseTag = ETrue;
		return;
	}
    if ( attr != EDdUnknownAttr )   // Unknown attribute is ignored.
        {
        ucs2 = PcDataLC( aElmtNode );
        if ( ucs2 )
            {
            SetMetaAttrL( attr, TPtrC( ucs2 ), aMediaObject );
            }
        CleanupStack::PopAndDestroy();  // Clean up ucs2.
        }
    CLOG(( EParse, 2, _L("<- TDdParser::MetaElementNodeL") ));
    }// ---------------------------------------------------------
// TDdParser::ElementNodeL()
// ---------------------------------------------------------
//
void TDdParser::ElementNodeL( NW_DOM_ElementNode_t* aElmtNode, CMediaObjectData *& aMediaObject )
    {
    CLOG(( EParse, 2, _L("-> TDdParser::ElementNodeL") ));
    __ASSERT_DEBUG( aElmtNode, CodPanic( ECodInternal ) );
    NW_String_t str;
    LeaveIfNwErrorL( NW_DOM_Node_getNodeName( aElmtNode, &str ) );
    CleanupNwStringStoragePushL( &str );
    NW_Ucs2* ucs2;
    LeaveIfNwErrorL( NW_String_stringToUCS2Char( &str, iEncoding, &ucs2 ) );
    CleanupNwUcs2PushL( ucs2 );
    TPtrC attrName( ucs2 );
    TDdAttr attr = Attribute( attrName );
    CLOG(( EParse, 4, _L("  attribute <%S> (%d)"), &attrName, attr ));
    CleanupStack::PopAndDestroy( 2 );   // Clean up ucs2, str->storage
    if ( attr != EDdUnknownAttr )   // Unknown attribute is ignored.
        {
        ucs2 = PcDataLC( aElmtNode );
        if ( ucs2 )
            {
            SetAttrL( attr, TPtrC( ucs2 ), aMediaObject );
            }
        CleanupStack::PopAndDestroy();  // Clean up ucs2.
        }
    CLOG(( EParse, 2, _L("<- TDdParser::ElementNodeL") ));
    }

// ---------------------------------------------------------
// TDdParser::PcDataLC()
// ---------------------------------------------------------
//
NW_Ucs2* TDdParser::PcDataLC( NW_DOM_ElementNode_t* aElmtNode )
    {
    __ASSERT_DEBUG( aElmtNode, CodPanic( ECodInternal ) );
    NW_Ucs2* ucs2 = NULL;
    NW_DOM_TextNode_t* textNode = NW_DOM_Node_getFirstChild( aElmtNode );
    if ( textNode && NW_DOM_Node_getNodeType( textNode ) == NW_DOM_TEXT_NODE )
        {
        NW_String_t str;
        LeaveIfNwErrorL( NW_DOM_TextNode_getData( textNode, &str ) );
        CleanupNwStringStoragePushL( &str );
        LeaveIfNwErrorL
            ( NW_String_stringToUCS2Char( &str, iEncoding, &ucs2 ) );
        CleanupStack::PopAndDestroy();  // Clean up str->storage.
        CleanupNwUcs2PushL( ucs2 );
        }
    if ( !ucs2 )
        {
        // Push the NULL.
        CleanupStack::PushL( ucs2 );
        }
    return ucs2;
    }

// ---------------------------------------------------------
// TDdParser::GetAttrValueLC()
// ---------------------------------------------------------
//
/*
NW_Ucs2* TDdParser::GetAttrValueLC( NW_DOM_ElementNode_t* aElmtNode, NW_DOM_AttributeHandle_t* aAttrHandle )
    {
    __ASSERT_DEBUG( aElmtNode, CodPanic( ECodInternal ) );
    NW_Ucs2* ucs2 = NULL;
    NW_DOM_TextNode_t* textNode = NW_DOM_Node_getFirstChild( aElmtNode );
    if ( textNode && NW_DOM_Node_getNodeType( textNode ) == NW_DOM_TEXT_NODE )
        {
        NW_String_t str;
        LeaveIfNwErrorL( NW_DOM_TextNode_getData( textNode, &str ) );
        CleanupNwStringStoragePushL( &str );
        LeaveIfNwErrorL
            ( NW_String_stringToUCS2Char( &str, iEncoding, &ucs2 ) );
        CleanupStack::PopAndDestroy();  // Clean up str->storage.
        CleanupNwUcs2PushL( ucs2 );
        }
    if ( !ucs2 )
        {
        // Push the NULL.
        CleanupStack::PushL( ucs2 );
        }
    return ucs2;
    }
*/
// ---------------------------------------------------------
// TDdParser::Attribute() // for OMA v1
// ---------------------------------------------------------
//
TDdParser::TDdAttr TDdParser::Attribute( const TDesC& aAttrName ) const
    {
    TDdAttr attr = EDdUnknownAttr;
    if ( !aAttrName.Compare( KDdName ) )
        {
        attr = EDdName;
        }
    else if ( !aAttrName.Compare( KDdVendor ) )
        {
        attr = EDdVendor;
        }
    else if ( !aAttrName.Compare( KDdDescription ) )
        {
        attr = EDdDescription;
        }
    else if ( !aAttrName.Compare( KDdUrl ) )
        {
        attr = EDdUrl;
        }
    else if ( !aAttrName.Compare( KDdSize ) )
        {
        attr = EDdSize;
        }
    else if ( !aAttrName.Compare( KDdType ) )
        {
        attr = EDdType;
        }
    else if ( !aAttrName.Compare( KDdInstallNotify ) )
        {
        attr = EDdInstallNotify;
        }
    else if ( !aAttrName.Compare( KDdNextUrl ) )
        {
        attr = EDdNextUrl;
        }
    else if ( !aAttrName.Compare( KDdInfoUrl ) )
        {
        attr = EDdInfoUrl;
        }
    else if ( !aAttrName.Compare( KDdIcon ) )
        {
        attr = EDdIcon;
        }
    else if ( !aAttrName.Compare( KDdVersion ) )
        {
        attr = EDdVersion;
        }
    return attr;
    }

// ---------------------------------------------------------
// TDdParser::MediaAttribute() // for OMA v2
// ---------------------------------------------------------
//
TDdParser::TDdAttr TDdParser::MediaAttribute( const TDesC& aAttrName ) const
    {
    TDdAttr attr = EDdUnknownAttr;

	if ( !aAttrName.Compare( KDdVersion ) )
        {
        attr = EDdVersion;
        }
    else if ( !aAttrName.Compare( KDdVendor ) )
        {
        attr = EDdVendor;
        }
    else if ( !aAttrName.Compare( KDdName ) )
        {
        attr = EDdName;
        }
    else if ( !aAttrName.Compare( KDdNextUrl ) )
        {
        attr = EDdNextUrl;
        }
    else if ( !aAttrName.Compare( KDdProduct ) )
        {
        attr = EDdProduct;
        }
    else if ( !aAttrName.Compare( KDdUpdatedDDURI ) )
        {
        attr = EDdUpdatedDDURI;
        }        
    return attr;
    }

// ---------------------------------------------------------
// TDdParser::MediaObjAttribute() // for OMA v2
// ---------------------------------------------------------
//
TDdParser::TDdAttr TDdParser::MediaObjAttribute( const TDesC& aAttrName ) const
    {
    TDdAttr attr = EDdUnknownAttr;

	if ( !aAttrName.Compare( KDdUrl ) )
        {
        attr = EDdUrl;
        }
    else if ( !aAttrName.Compare( KDdSize ) )
        {
        attr = EDdSize;
        }
    else if ( !aAttrName.Compare( KDdType ) )
        {
        attr = EDdType;
        }
    else if ( !aAttrName.CompareF( KDdProgressiveDl ) )
        {
        attr = EDdProgressiveDl;
        }
    else if ( !aAttrName.CompareF( KDdSuppressUserConfirmation ) )
        {
        attr = EDdSuppressUserConfirmation;
        }
    else if ( !aAttrName.Compare( KDdMeta ) )
        {
        attr = EDdMeta;
        }

    return attr;
    }

// ---------------------------------------------------------
// TDdParser::ObjUriAttribute() // for OMA v2
// ---------------------------------------------------------
//
TDdParser::TDdAttr TDdParser::ObjUriAttribute( const TDesC& aAttrName ) const
    {
    TDdAttr attr = EDdUnknownAttr;

	if ( !aAttrName.Compare( KDdServer ) )
        {
        attr = EDdUrl;
        }
    return attr;
    }

// ---------------------------------------------------------
// TDdParser::DdVersionAttribute() // for OMA v2
// ---------------------------------------------------------
//
TDdParser::TDdAttr TDdParser::DdVersionAttribute( const TDesC& aAttrName ) const
    {
    TDdAttr attr = EDdUnknownAttr;

	if ( !aAttrName.Compare( KDdVersion ) )
        {
        attr = EDdVersion;
        }
    return attr;
    }

// ---------------------------------------------------------
// TDdParser::MetaAttribute() // for OMA v2
// ---------------------------------------------------------
//
TDdParser::TDdAttr TDdParser::MetaAttribute( const TDesC& aAttrName ) const
    {
    TDdAttr attr = EDdUnknownAttr;
    if ( !aAttrName.Compare( KDdName ) )
        {
        attr = EDdName;
        }
    if ( !aAttrName.Compare( KDdText ) )
        {
        attr = EDdText;
        }
    else if ( !aAttrName.Compare( KDdDescription ) )
        {
        attr = EDdDescription;
        }
    else if ( !aAttrName.Compare( KDdInstallNotify ) )
        {
        attr = EDdInstallNotify;
        }
    else if ( !aAttrName.Compare( KDdLicense ) )
        {
        attr = EDdLicense;
        }
    else if ( !aAttrName.Compare( KDdOrder ) )
        {
        attr = EDdOrder;
        }
    return attr;
    }

// ---------------------------------------------------------
// TDdParser::ProductAttribute() // for OMA v2
// ---------------------------------------------------------
//
TDdParser::TDdAttr TDdParser::ProductAttribute( const TDesC& aAttrName ) const
    {
    TDdAttr attr = EDdUnknownAttr;
    if ( !aAttrName.Compare( KDdMeta ) )
        {
        attr = EDdMeta;
        }
    if ( !aAttrName.Compare( KDdMediaObject ) )
        {
        attr = EDdMediaObject;
        }
    return attr;
    }

// ---------------------------------------------------------
// TDdParser::SetAttrL()  // for OMA v1
// ---------------------------------------------------------
//
void TDdParser::SetAttrL( TDdAttr aAttr, const TDesC& aValue, CMediaObjectData *& aMediaObject )
    {
    TInt ok( ETrue );
    switch( aAttr )
        {
        case EDdName:
            {
            if ( !aMediaObject->Name().Length() )
                {
                ok = aMediaObject->SetNameL( aValue );
                }
            break;
            }

        case EDdDescription:
            {
            if ( !aMediaObject->Description().Length() )
                {
                ok = aMediaObject->SetDescriptionL( aValue );
                }
            break;
            }

        case EDdUrl:
            {
            if ( !aMediaObject->Url().Length() )
                {
                ok = aMediaObject->SetUrlL( aValue );
                }
            break;
            }

        case EDdSize:
            {
            if ( !aMediaObject->Size() )
                {
                // Parse as TUint - negative not allowed.
                TUint size;
                TLex lex( aValue );
                if ( !lex.Val( size ) )
                    {
                    aMediaObject->SetSize( size );
                    }
                else
                    {
                    ok = EFalse;
                    }
                }
            break;
            }

        case EDdType:
            {
            ok = aMediaObject->AddTypeL( aValue );
            break;
            }

        case EDdInstallNotify:
            {
            if ( !aMediaObject->InstallNotify().Length() )
                {
                ok = aMediaObject->SetInstallNotifyL( aValue );
                }
            break;
            }

        case EDdInfoUrl:
            {
            if ( !aMediaObject->InfoUrl().Length() )
                {
                ok = aMediaObject->SetInfoUrlL( aValue );
                }
            break;
            }

        case EDdIcon:
            {
            if ( !aMediaObject->Icon().Length() )
                {
                ok = aMediaObject->SetIconL( aValue );
                }
            break;
            }
            
        case EDdVersion:
            {
            if ( !iData->Version().Length() )
                {
                ok = iData->SetVersionL( aValue );
                }
            break;
            }

        case EDdNextUrl:
            {
            if ( !iData->NextUrl().Length() )
                {
                ok = iData->SetNextUrlL( aValue );
                }
            break;
            }

        case EDdVendor:
            {
            if ( !iData->Vendor().Length() )
                {
                ok = iData->SetVendorL( aValue );
                }
            break;
            }
                        
        default:
            {
            // Unexpected value.
            CodPanic( ECodInternal );
            }
        }
    if ( !ok )
        {
        Error( KErrCodInvalidDescriptor );
        }
    }


// ---------------------------------------------------------
// TDdParser::SetMediaAttrL()
// ---------------------------------------------------------
//
void TDdParser::SetMediaAttrL( TDdAttr aAttr, const TDesC& aValue )
    {
    TInt ok( ETrue );
    switch( aAttr )
        {
        case EDdName:
            {
            if ( !iData->Name().Length() )
                {
                ok = iData->SetNameL( aValue );
                }
            break;
            }
        case EDdVersion:
            {
            if ( !iData->Version().Length() )
                {
                ok = iData->SetVersionL( aValue );
                }
            break;
            }

        case EDdVendor:
            {
            if ( !iData->Vendor().Length() )
                {
                ok = iData->SetVendorL( aValue );
                }
            break;
            }

        case EDdNextUrl:
            {
            if ( !iData->NextUrl().Length() )
                {
                // Unlike COD, DD has no separate URL-s for success and error
                // service flow. Since we have a common data structore for
                // both (which contains separate URLs for those), we fill both
                // URLs with this value.
                ok = iData->SetNextUrlL( aValue ) &&
                     iData->SetNextUrlAtErrorL( aValue );
                }
            break;
            }

        case EDdUpdatedDDURI:
            {
            if(!iData->UpdatedDDUriL().Length())
                {
                iData->SetUpdatedDDURI( aValue );
                }
            
            break;
            }

        default:
            {
            // Unexpected value.
            CodPanic( ECodInternal );
            }
        }
    if ( !ok )
        {
        Error( KErrCodInvalidDescriptor );
        }
    }

// ---------------------------------------------------------
// TDdParser::SetMediaObjAttrL()
// ---------------------------------------------------------
//
void TDdParser::SetMediaObjAttrL( TDdAttr aAttr, const TDesC& aValue, CMediaObjectData *& aMediaObject )
    {
    TInt ok( ETrue );
    switch( aAttr )
        {
        case EDdSize:
            {
            if ( !aMediaObject->Size() )
                {
                // Parse as TUint - negative not allowed.
                TUint size;
                TLex lex( aValue );
                if ( !lex.Val( size ) )
                    {
                    aMediaObject->SetSize( size );
                    }
                else
                    {
                    ok = EFalse;
                    }
                }
            break;
            }

        case EDdType:
            {
            ok = aMediaObject->AddTypeL( aValue );
            break;
            }

        case EDdProgressiveDl:
            {
            TBool pd( EFalse );
            if ( !aValue.CompareF( KDdTrue ) )
                {
                pd = ETrue;
                }
            else if ( aValue.CompareF( KDdFalse ) )
                {
                // Expected 'true' or 'false'
                Error( KErrCodInvalidDescriptor );
                break;
                }
            aMediaObject->SetProgressiveDownload( pd );
            break;
            }

        case EDdSuppressUserConfirmation:
            {
            TInt confirm = CCodData::ENever; 
            if ( !aValue.CompareF(KDdNever) )
                {
                confirm = CCodData::ENever; 
                }
            else if ( aValue.CompareF(KDdUserConfirmStepOnly) )
                {
                confirm = CCodData::EUserConfirmStepOnly; 
                }
            else if ( aValue.CompareF(KDdAlways) )
                {
                confirm = CCodData::EAlways;      
                }
            else 
                {
                Error( KErrCodInvalidDescriptor );
                }
            iData->SetSuppressConfirm( confirm );
            break;
            }
        case EDdUpdatedDDURI:
            {
            if(!iData->UpdatedDDUriL().Length())
                {
                iData->SetUpdatedDDURI( aValue );
                }
            
            break;
            }
        default:
            {
            // Unexpected value.
            CodPanic( ECodInternal );
            }
        }
    if ( !ok )
        {
        Error( KErrCodInvalidDescriptor );
        }
    }


// ---------------------------------------------------------
// TDdParser::SetMetaAttrL()
// ---------------------------------------------------------
//
void TDdParser::SetMetaAttrL( TDdAttr aAttr, const TDesC& aValue )
    {
    TInt ok( ETrue );
    switch( aAttr )
        {
        case EDdName:
            {
            if ( !iData->Name().Length() )
                {
                ok = iData->SetNameL( aValue );
                }
            break;
            }

        case EDdDescription:
            {
            if ( !iData->Description().Length() )
                {
                ok = iData->SetDescriptionL( aValue );
                }
            break;
            }

        case EDdInstallNotify:
            {
            if ( !iData->InstallNotify().Length() )
                {
                ok = iData->SetInstallNotifyL( aValue );
                }
            break;
            }

        case EDdInfoUrl:
            {
            if ( !iData->InfoUrl().Length() )
                {
                ok = iData->SetInfoUrlL( aValue );
                }
            break;
            }

        case EDdIcon:
            {
            if ( !iData->Icon().Length() )
                {
                ok = iData->SetIconL( aValue );
                }
            break;
            }

        case EDdOrder:
            {
            TBool isPostOrder( EFalse );
            if ( !aValue.CompareF( KDdPost ) )
                {
                isPostOrder = ETrue;
                }
            else if ( aValue.CompareF( KDdAny ) )
                {
                // Expected 'post' or 'any'
                Error( KErrCodInvalidDescriptor );
                break;
				}
            iData->SetOrderIsPost( isPostOrder );
            break;
            }

        case EDdText:
            {

            break;
            }
        default:
            {
            // Unexpected value.
            CodPanic( ECodInternal );
            }
        }
    if ( !ok )
        {
        Error( KErrCodInvalidDescriptor );
        }
    }


// ---------------------------------------------------------
// TDdParser::SetMetaAttrL()
// ---------------------------------------------------------
//
void TDdParser::SetMetaAttrL( TDdAttr aAttr, const TDesC& aValue, CMediaObjectData *& aMediaObject )
    {
    TInt ok( ETrue );
    switch( aAttr )
        {
        case EDdName:
            {
            if ( !aMediaObject->Name().Length() )
                {
                ok = aMediaObject->SetNameL( aValue );
                }
            break;
            }

        case EDdDescription:
            {
            if ( !aMediaObject->Description().Length() )
                {
                ok = aMediaObject->SetDescriptionL( aValue );
                }
            break;
            }

        case EDdInstallNotify:
            {
            if ( !aMediaObject->InstallNotify().Length() )
                {
                ok = aMediaObject->SetInstallNotifyL( aValue );
                }
            break;
            }

        case EDdInfoUrl:
            {
            if ( !aMediaObject->InfoUrl().Length() )
                {
                ok = aMediaObject->SetInfoUrlL( aValue );
                }
            break;
            }

        case EDdIcon:
            {
            if ( !aMediaObject->Icon().Length() )
                {
                ok = aMediaObject->SetIconL( aValue );
                }
            break;
            }

        case EDdOrder:
            {
            TBool isPostOrder( EFalse );
            if ( !aValue.CompareF( KDdPost ) )
                {
                isPostOrder = ETrue;
                }
            else if ( aValue.CompareF( KDdAny ) )
                {
                // Expected 'post' or 'any'
                Error( KErrCodInvalidDescriptor );
                break;
				}
            aMediaObject->SetOrderIsPost( isPostOrder );
            break;
            }

        case EDdText:
            {
//TODO for OMA2
/*
            if ( !iData->Text().Length() )
                {
                ok = iData->SetTextL( aValue );
                }
*/
            break;
            }

        default:
            {
            // Unexpected value.
            CodPanic( ECodInternal );
            }
        }
    if ( !ok )
        {
        Error( KErrCodInvalidDescriptor );
        }
    }
    
// ---------------------------------------------------------
// TDdParser::ParseNameFromUrlL()
// ---------------------------------------------------------    
void TDdParser::ParseNameFromUrlL( CMediaObjectData *& aMediaObject )
    {
    TBuf16<COD_URL_MAX_LEN> buf16;
    CnvUtfConverter::ConvertToUnicodeFromUtf8(buf16,aMediaObject->Url());
    TInt lastSlashPos = buf16.LocateReverse('/');
    aMediaObject->SetNameL(buf16.MidTPtr( lastSlashPos + 1));
    }
    
