// =================================================================================================
// Copyright Adobe
// Copyright 2014 Adobe
// All Rights Reserved
//
// NOTICE:  Adobe permits you to use, modify, and distribute this file in accordance with the terms
// of the Adobe license agreement accompanying it. 
// =================================================================================================

#define IMPLEMENTATION_HEADERS_CAN_BE_INCLUDED 1
	#include "XMPCore/ImplHeaders/RDFDOMSerializerImpl.h"
#undef IMPLEMENTATION_HEADERS_CAN_BE_INCLUDED

#include "XMPCommon/Interfaces/IError_I.h"
#include "XMPCore/XMPCoreErrorCodes.h"

#include "XMPCommon/Utilities/AutoSharedLock.h"

#include "XMPCore/Interfaces/ISimpleNode_I.h"
#include "XMPCore/Interfaces/IArrayNode_I.h"
#include "XMPCore/Interfaces/IMetadata_I.h"
#include "XMPCommon/Interfaces/IUTF8String_I.h"
#include "XMPCore/Interfaces/INameSpacePrefixMap_I.h"
#include "XMPCommon/Utilities/TSmartPointers_I.h"
#include "XMPCommon/Utilities/UTF8String.h"
#include "XMPCore/Interfaces/INodeIterator_I.h"
#include "XMPCore/Interfaces/IMetadataConverterUtils_I.h"

#include "XMPMeta.hpp"


namespace AdobeXMPCore_Int {

	namespace Serializer {
		typedef enum {
			kCPOmitPacketWrapper,
			kCPMarkReadOnlyPacket,
			kCPUseCompactFormat,
			kCPUseCanonicalFormat,
			kCPIncludeThumbnailPadding,
			kCPUseExactPacketLength,
			kCPOmitAllFormatting,
			kCPOmitMetaElement,
			kCPOmitRDFHash,
			kCPUseEncoding,
			kCPUseBigEndian,
			kCPPaddingLength
		} eConfigurableParameters;

		static uint64 kAllowedKeys[] = {
			IConfigurable::ConvertCharBufferToUint64( "oPktWrap" ),
			IConfigurable::ConvertCharBufferToUint64( "mRoPkt  " ),
			IConfigurable::ConvertCharBufferToUint64( "uCompact" ),
			IConfigurable::ConvertCharBufferToUint64( "uCanonic" ),
			IConfigurable::ConvertCharBufferToUint64( "eThmbPad" ),
			IConfigurable::ConvertCharBufferToUint64( "uExctLen" ),
			IConfigurable::ConvertCharBufferToUint64( "oFormat " ),
			IConfigurable::ConvertCharBufferToUint64( "oMetaEl " ),
			IConfigurable::ConvertCharBufferToUint64( "oRDFHash" ),
			IConfigurable::ConvertCharBufferToUint64( "encoding" ),
			IConfigurable::ConvertCharBufferToUint64( "bgEndian"),
			IConfigurable::ConvertCharBufferToUint64( "padLen  " ),
		};

		static ConfigurableImpl::KeyValueTypePair kAllowedKeyValueTypes[] = {
			std::make_pair( kAllowedKeys[ kCPOmitPacketWrapper ], IConfigurable::kDTBool ),
			std::make_pair( kAllowedKeys[ kCPMarkReadOnlyPacket ], IConfigurable::kDTBool ),
			std::make_pair( kAllowedKeys[ kCPUseCompactFormat ], IConfigurable::kDTBool ),
			std::make_pair( kAllowedKeys[ kCPUseCanonicalFormat ], IConfigurable::kDTBool ),
			std::make_pair( kAllowedKeys[ kCPIncludeThumbnailPadding ], IConfigurable::kDTBool ),
			std::make_pair( kAllowedKeys[ kCPUseExactPacketLength ], IConfigurable::kDTBool ),
			std::make_pair( kAllowedKeys[ kCPOmitAllFormatting ], IConfigurable::kDTBool ),
			std::make_pair( kAllowedKeys[ kCPOmitMetaElement ], IConfigurable::kDTBool ),
			std::make_pair( kAllowedKeys[ kCPOmitRDFHash ], IConfigurable::kDTBool ),
			std::make_pair( kAllowedKeys[ kCPUseEncoding ], IConfigurable::kDTUint64 ),
			std::make_pair( kAllowedKeys[ kCPUseBigEndian ], IConfigurable::kDTBool ),
			std::make_pair( kAllowedKeys[ kCPPaddingLength ], IConfigurable::kDTUint64 )
		};
	}

	// static utility functions
//	static spcIUTF8String CreateQualifiedName( const spINode & node, const spcINameSpacePrefixMap_I & userSuppliedMap, spINameSpacePrefixMap_I & generatedMap ) {
//		spIUTF8String qualName = IUTF8String_I::CreateUTF8String( NULL, AdobeXMPCommon::npos );
//		spcIUTF8String nameSpace = node->GetNameSpace();
//		static sizet count( 0 );
//
//		spcIUTF8String prefixStr = userSuppliedMap->GetPrefix( node->GetNameSpace() );
//
//		if ( !prefixStr && !generatedMap ) {
//			generatedMap = MakeUncheckedSharedPointer( INameSpacePrefixMap_I::CreateNameSpacePrefixMap()->GetINameSpacePrefixMap_I(), __FILE__, __LINE__, true );
//			count = 0;
//		}
//		else if (!prefixStr && generatedMap) {
//
//			if (generatedMap->GetPrefix(node->GetNameSpace())) {
//
//				prefixStr = generatedMap->GetPrefix(node->GetNameSpace());
//			}
//		}
//		if ( !prefixStr ) {
//
//			spIUTF8String autoGeneratedPrefix = IUTF8String_I::CreateUTF8String( NULL, AdobeXMPCommon::npos );
//			do {
//				autoGeneratedPrefix->clear();
//				autoGeneratedPrefix->append( "ns", (sizet) 2 );
//				//std::string numStr = std::to_string( ++count );
//                std::ostringstream oss;
//                oss << ++count;
//                std::string numStr = oss.str();
//				autoGeneratedPrefix->append( numStr.c_str(), numStr.size() );
//			} while (generatedMap->IsPrefixPresent ( autoGeneratedPrefix->c_str ( ), autoGeneratedPrefix->size ( ) ));
//			generatedMap->Insert( autoGeneratedPrefix->c_str(), autoGeneratedPrefix->size(), nameSpace->c_str(), nameSpace->size() );
//			prefixStr = autoGeneratedPrefix;
//		}
//
//		qualName->append( prefixStr );
//		qualName->append( ":", 1 );
//		qualName->append( node->GetName() );
//		return qualName;
//	}
//    
//	 static bool FindPrefixFromUserSuppliedMap ( void * voidUserSuppliedMap, XMP_StringPtr nsURI, XMP_StringPtr * namespacePrefix, XMP_StringLen * prefixSize ) {
//		if (voidUserSuppliedMap) {
//			pcINameSpacePrefixMap userSuppliedMap = reinterpret_cast<pcINameSpacePrefixMap>( voidUserSuppliedMap );
//			auto prefix = userSuppliedMap->GetPrefix ( nsURI, AdobeXMPCommon::npos );
//			if (prefix) {
//				*namespacePrefix = prefix->c_str ( );
//				*prefixSize = (XMP_Uns32)prefix->size ( );
//				return true;
//			}
//		}
//		return false;
//	}

//	static XMP_Node * AddChildNode( XMP_Node * xmpParent, const spINode & node, const char * value, const spcINameSpacePrefixMap_I & userSuppliedMap, spINameSpacePrefixMap_I & generatedMap, bool isTopLevel ) {
//		bool isArrayItem = node->IsArrayItem();
//		if ( isTopLevel ) {
//			isArrayItem = false;
//		}
//
//		XMP_OptionBits childOptions = 0;
//
//		spcIUTF8String qualName = CreateQualifiedName( node, userSuppliedMap, generatedMap );
//
//		XMP_StringPtr childName = qualName->c_str();
//		XMP_StringPtr nameSpaceStrPtr = node->GetNameSpace()->c_str();
//
//		if ( isTopLevel ) {
//			// Lookup the schema node, adjust the XMP parent pointer.
//			XMP_Assert( xmpParent->parent == 0 );	// Incoming parent must be the tree root.
//			XMP_Node * schemaNode = FindSchemaNode( xmpParent, nameSpaceStrPtr, kXMP_CreateNodes, NULL, &FindPrefixFromUserSuppliedMap, generatedMap ? generatedMap->GetActualINameSpacePrefixMap() : NULL );
//			if ( schemaNode->options & kXMP_NewImplicitNode ) schemaNode->options ^= kXMP_NewImplicitNode;	// Clear the implicit node bit.
//			// *** Should use "opt &= ~flag" (no conditional), need runtime check for proper 32 bit code.
//			xmpParent = schemaNode;
//
//			// If this is an alias set the isAlias flag in the node and the hasAliases flag in the tree.
//			XMP_StringPtr prefixForAlias( NULL );
//			XMP_StringLen prefixLenForAlias( 0 );
//			if ( sRegisteredNamespaces->GetPrefix( nameSpaceStrPtr, &prefixForAlias, &prefixLenForAlias ) && prefixForAlias && prefixLenForAlias > 0 ) {
//				spIUTF8String childNameForAlias( IUTF8String_I::CreateUTF8String( NULL, npos ) );
//				childNameForAlias->append( prefixForAlias, prefixLenForAlias )->append( node->GetName() );
//				if ( sRegisteredAliasMap->find( childNameForAlias->c_str() ) != sRegisteredAliasMap->end() ) {
//					childOptions |= kXMP_PropIsAlias;
//					schemaNode->parent->options |= kXMP_PropHasAliases;
//				}
//			}
//
//		}
//
//		if ( isArrayItem ) {
//			childName = kXMP_ArrayItemName;
//		}
//
//		// Add the new child to the XMP parent node.
//		XMP_Node * newChild = new XMP_Node( xmpParent, childName, value, childOptions );
//		xmpParent->children.push_back( newChild );
//
//		return newChild;
//	}

//	static XMP_Node * AddQualifierNode( XMP_Node * xmpParent, const spINode & node, const char * value, const spcINameSpacePrefixMap_I & userSuppliedMap, spINameSpacePrefixMap_I & generatedMap ) {
//		spcIUTF8String qualName = CreateQualifiedName( node, userSuppliedMap, generatedMap );
//		XMP_StringPtr childName = qualName->c_str();
//
//		static const char * kLanguageName = "lang";
//		static const char * kTypeName = "type";
//
//		const bool isLang = ( node->GetName()->compare( kLanguageName ) == 0 ) && ( node->GetNameSpace()->compare( kXMP_NS_XML ) == 0 );
//		const bool isType = ( node->GetName()->compare( kTypeName ) == 0 ) && ( node->GetNameSpace()->compare( kXMP_NS_RDF ) == 0 );
//
//		bool isArrayItem = node->IsArrayItem();
//
//		XMP_OptionBits childOptions = 0;
//
//		XMP_StringPtr nameSpaceStrPtr = node->GetNameSpace()->c_str();
//
//		if ( isArrayItem ) {
//			childName = kXMP_ArrayItemName;
//		}
//
//		XMP_Node * newQual = 0;
//
//		newQual = new XMP_Node( xmpParent, childName, value, kXMP_PropIsQualifier );
//
//		if ( !( isLang | isType ) ) {
//			xmpParent->qualifiers.push_back( newQual );
//		} else if ( isLang ) {
//			if ( xmpParent->qualifiers.empty() ) {
//				xmpParent->qualifiers.push_back( newQual );
//			} else {
//				xmpParent->qualifiers.insert( xmpParent->qualifiers.begin(), newQual );
//			}
//			xmpParent->options |= kXMP_PropHasLang;
//		} else {
//			XMP_Assert( isType );
//			if ( xmpParent->qualifiers.empty() ) {
//				xmpParent->qualifiers.push_back( newQual );
//			} else {
//				size_t offset = 0;
//				if ( XMP_PropHasLang( xmpParent->options ) ) offset = 1;
//				xmpParent->qualifiers.insert( xmpParent->qualifiers.begin() + offset, newQual );
//			}
//			xmpParent->options |= kXMP_PropHasType;
//		}
//
//		xmpParent->options |= kXMP_PropHasQualifiers;
//
//		return newQual;
//	}

//	void HandleNode( const spINode & node, XMP_Node * parent, const spcINameSpacePrefixMap_I & userSuppliedMap, spINameSpacePrefixMap_I & generatedMap, bool isTopLevel, bool isQualifierNode );
//   
//    
//    
//	static XMP_Node * HandleSimpleNode( const spISimpleNode & simpleNode, XMP_Node * parent, const spcINameSpacePrefixMap_I & userSuppliedMap, spINameSpacePrefixMap_I & generatedMap, bool isTopLevel, bool isQualifierNode ) {
//		XMP_Node * node = NULL;
//		if ( isQualifierNode ) {
//			node = AddQualifierNode( parent, simpleNode, simpleNode->GetValue()->c_str(), userSuppliedMap, generatedMap );
//		} else {
//			node = AddChildNode( parent, simpleNode, simpleNode->GetValue()->c_str(), userSuppliedMap, generatedMap, isTopLevel );
//		}
//		if ( simpleNode->IsURIType() )
//			node->options |= kXMP_PropValueIsURI;
//		return node;
//	}
//
//    
//    static XMP_Node * HandleStructureNode( const spIStructureNode & structureNode, XMP_Node * parent, const spcINameSpacePrefixMap_I & userSuppliedMap, spINameSpacePrefixMap_I & generatedMap, bool isTopLevel, bool isQualifierNode ) {
//		bool metadataNode = false;
//		if ( isTopLevel ) {
//			// check if it is a XMPMetadata node
//			spIMetadata metadata = structureNode->ConvertToMetadata();
//			if ( metadata ) {
//				metadataNode = true;
//				parent->name = metadata->GetAboutURI()->c_str();
//			}
//		}
//
//		XMP_Node * newComposite = NULL;
//		if ( !metadataNode ) {
//			if ( isQualifierNode ) {
//				newComposite = AddQualifierNode( parent, structureNode, "", userSuppliedMap, generatedMap );
//			} else {
//				newComposite = AddChildNode( parent, structureNode, "", userSuppliedMap, generatedMap, isTopLevel );
//			}
//		} else {
//			newComposite = parent;
//		}
//
//		if ( newComposite == 0 ) return NULL;	// Ignore lower level errors.
//
//		newComposite->options |= kXMP_PropValueIsStruct;
//
//		// iterate over all the children
//		spINodeIterator it = structureNode->Iterator();
//
//		while ( it ) {
//			spINode spNode = it->GetNode();
//			if ( metadataNode )
//				HandleNode( spNode, newComposite, userSuppliedMap, generatedMap, true, false );
//			else
//				HandleNode( spNode, newComposite, userSuppliedMap, generatedMap, false, false );
//			it = it->Next();
//		}
//
//		return newComposite;
//	}
//
//    
//	static XMP_Node * HandleArrayNode( const spIArrayNode & arrayNode, XMP_Node * parent, const spcINameSpacePrefixMap_I & userSuppliedMap, spINameSpacePrefixMap_I & generatedMap, bool isTopLevel, bool isQualifierNode ) {
//		XMP_Node * newComposite = NULL;
//		if ( isQualifierNode ) {
//			newComposite = AddQualifierNode( parent, arrayNode, "", userSuppliedMap, generatedMap );
//		} else {
//			newComposite = AddChildNode( parent, arrayNode, "", userSuppliedMap, generatedMap, isTopLevel );
//		}
//
//		if ( newComposite == 0 ) return NULL;	// Ignore lower level errors.
//
//		newComposite->options |= kXMP_PropValueIsArray;
//
//		IArrayNode::eArrayForm arrayNodeForm = arrayNode->GetArrayForm();
//		if ( arrayNodeForm == IArrayNode::kAFAlternative )
//			newComposite->options |= kXMP_PropValueIsArray | kXMP_PropArrayIsOrdered | kXMP_PropArrayIsAlternate;
//		else if ( arrayNodeForm == IArrayNode::kAFOrdered )
//			newComposite->options |= kXMP_PropValueIsArray | kXMP_PropArrayIsOrdered;
//
//		// iterate over all the children
//		spINodeIterator it = arrayNode->Iterator();
//
//		while ( it ) {
//			spINode spNode = it->GetNode();
//			HandleNode( spNode, newComposite, userSuppliedMap, generatedMap, false, false );
//			it = it->Next();
//		}
//		return newComposite;
//	}
//
//	void HandleNode( const spINode & node, XMP_Node * parent, const spcINameSpacePrefixMap_I & userSuppliedMap, spINameSpacePrefixMap_I & generatedMap, bool isTopLevel, bool isQualifierNode ) {
//		XMP_Node * nodeCreated = NULL;
//		if (!node) return;
//		switch ( node->GetNodeType() ) {
//		case INode::kNTSimple:
//			nodeCreated = HandleSimpleNode( node->ConvertToSimpleNode(), parent, userSuppliedMap, generatedMap, isTopLevel, isQualifierNode );
//			break;
//
//		case INode::kNTStructure:
//			nodeCreated = HandleStructureNode( node->ConvertToStructureNode(), parent, userSuppliedMap, generatedMap, isTopLevel, isQualifierNode );
//			break;
//
//		case INode::kNTArray:
//			nodeCreated = HandleArrayNode( node->ConvertToArrayNode(), parent, userSuppliedMap, generatedMap, isTopLevel, isQualifierNode );
//			break;
//
//		default:
//			break;
//		}
//
//		if ( node->HasQualifiers() && nodeCreated ) {
//			spINodeIterator it = node->QualifiersIterator();
//			while ( it ) {
//				spINode spNode = it->GetNode();
//				HandleNode( spNode, nodeCreated, userSuppliedMap, generatedMap, false, true );
//				it = it->Next();
//			}
//		}
//	}

	DOMSerializerImpl * APICALL RDFDOMSerializerImpl::clone() const {
		return new RDFDOMSerializerImpl();
	}

	static void GetSerializationOptions( pcIConfigurable configurationParameters, XMP_OptionBits & options, uint64 & paddingSize ) {
		options = 0;
		bool flag;
		if ( configurationParameters->GetParameter( Serializer::kAllowedKeys[ Serializer::kCPOmitPacketWrapper ], flag ) && flag )
			options |= kXMP_OmitPacketWrapper;
		if ( configurationParameters->GetParameter( Serializer::kAllowedKeys[ Serializer::kCPMarkReadOnlyPacket ], flag ) && flag )
			options |= kXMP_ReadOnlyPacket;
		if ( configurationParameters->GetParameter( Serializer::kAllowedKeys[ Serializer::kCPUseCompactFormat ], flag ) && flag )
			options |= kXMP_UseCompactFormat;
		if ( configurationParameters->GetParameter( Serializer::kAllowedKeys[ Serializer::kCPUseCanonicalFormat ], flag ) && flag )
			options |= kXMP_UseCanonicalFormat;
		if ( configurationParameters->GetParameter( Serializer::kAllowedKeys[ Serializer::kCPIncludeThumbnailPadding ], flag ) && flag )
			options |= kXMP_IncludeThumbnailPad;
		if ( configurationParameters->GetParameter( Serializer::kAllowedKeys[ Serializer::kCPUseExactPacketLength ], flag ) && flag )
			options |= kXMP_ExactPacketLength;
		if ( configurationParameters->GetParameter( Serializer::kAllowedKeys[ Serializer::kCPOmitAllFormatting ], flag ) && flag )
			options |= kXMP_OmitAllFormatting;
		if ( configurationParameters->GetParameter( Serializer::kAllowedKeys[ Serializer::kCPOmitMetaElement ], flag ) && flag )
			options |= kXMP_OmitXMPMetaElement;
		if ( configurationParameters->GetParameter( Serializer::kAllowedKeys[ Serializer::kCPOmitRDFHash ], flag ) && !flag )
			options |= kXMP_IncludeRDFHash;

		uint64 encoding( 8 );
		if ( !configurationParameters->GetParameter( Serializer::kAllowedKeys[ Serializer::kCPUseBigEndian ], flag ) )
			flag = false;
		if ( !configurationParameters->GetParameter( Serializer::kAllowedKeys[ Serializer::kCPUseEncoding ], encoding ) )
			encoding = 8;

		switch ( encoding ) {
		case 16:
			if ( flag ) options |= kXMP_EncodeUTF16Big; else options |= kXMP_EncodeUTF16Little;
			break;

		case 32:
			if ( flag ) options |= kXMP_EncodeUTF32Big; else options |= kXMP_EncodeUTF32Little;
			break;

		default:
			options |= kXMP_EncodeUTF8;
		}

		if ( !configurationParameters->GetParameter( Serializer::kAllowedKeys[ Serializer::kCPPaddingLength ], paddingSize ) )
			paddingSize = 2048;
	}



	spIUTF8String APICALL RDFDOMSerializerImpl::Serialize( const spINode & node, const spcINameSpacePrefixMap & nameSpacePrefixMap ) {
		XMP_OptionBits options = 0;
//		shared_ptr< XMPMeta > spMeta( new XMPMeta() );
//		spINameSpacePrefixMap_I genereatedMap;
//
//		spcINameSpacePrefixMap mergedMap = INameSpacePrefixMap::GetDefaultNameSpacePrefixMap();
//		if ( nameSpacePrefixMap ) {
//			spINameSpacePrefixMap newMergedMap = mergedMap->Clone();
//			newMergedMap->GetINameSpacePrefixMap_I()->Merge( nameSpacePrefixMap );
//			mergedMap = newMergedMap;
//		}
//		spINameSpacePrefixMap_I userSuppliedMap( MakeUncheckedSharedPointer( const_pointer_cast< INameSpacePrefixMap >( mergedMap )->GetINameSpacePrefixMap_I(), __FILE__, __LINE__, true ) );
//
//		// TODO:meta->SetErrorCallback()
//		HandleNode( node, &spMeta->tree, userSuppliedMap, genereatedMap, true, false );
//
//		NormalizeDCArrays( &( spMeta->tree ) );
//		if ( spMeta->tree.options & kXMP_PropHasAliases ) MoveExplicitAliases( &spMeta->tree, options, spMeta->errorCallback );
//		TouchUpDataModel( spMeta.get(), spMeta->errorCallback );
//
//		// Delete empty schema nodes. Do this last, other cleanup can make empty schema.
//		size_t schemaNum = 0;
//		while ( schemaNum < spMeta->tree.children.size() ) {
//			XMP_Node * currSchema = spMeta->tree.children[ schemaNum ];
//			if ( currSchema->children.size() > 0 ) {
//				++schemaNum;
//			} else {
//				delete spMeta->tree.children[ schemaNum ];	// ! Delete the schema node itself.
//				spMeta->tree.children.erase( spMeta->tree.children.begin() + schemaNum );
//			}
//		}
        
        shared_ptr< XMPMeta > spMeta( (XMPMeta*)(IMetadataConverterUtils_I::convertIMetadatatoXMPMeta(node, options, nameSpacePrefixMap)));
        

		std::string buffer;
		uint64 padding;
		GetSerializationOptions( this, options, padding );
		spMeta->SerializeToBuffer( &buffer, options, (XMP_Uns32)padding, "", "", 0 );
		spIUTF8String serializedOutput = IUTF8String_I::CreateUTF8String( buffer.c_str(), buffer.size() );
		return serializedOutput;
	}

	eConfigurableErrorCode APICALL RDFDOMSerializerImpl::ValidateValue( const uint64 & key, eDataType type, const CombinedDataValue & value ) const {
		if ( key == Serializer::kAllowedKeys[ Serializer::kCPUseEncoding ] ) {
			if ( type == IConfigurable::kDTUint64 && ( value.uint64Value == 8 || value.uint64Value == 16 || value.uint64Value == 32 ) )
				return kCECNone;
			return kCECValueNotSupported;
		}
		return kCECNone;
	}

	void RDFDOMSerializerImpl::InitializeDefaultValues() {
		TreatKeyAsCaseInsensitive( true );
		AllowDifferentValueTypesForExistingEntries( false );

		SetAllowedKeys( &Serializer::kAllowedKeys[ 0 ], 12 );
		SetAllowedValueTypesForKeys( &Serializer::kAllowedKeyValueTypes[ 0 ], 12 );
		SetParameter( Serializer::kAllowedKeys[ Serializer::kCPOmitPacketWrapper ], false );
		SetParameter( Serializer::kAllowedKeys[ Serializer::kCPMarkReadOnlyPacket ], false );
		SetParameter( Serializer::kAllowedKeys[ Serializer::kCPUseCompactFormat ], false );
		SetParameter( Serializer::kAllowedKeys[ Serializer::kCPUseCanonicalFormat ], false );
		SetParameter( Serializer::kAllowedKeys[ Serializer::kCPIncludeThumbnailPadding ], false );
		SetParameter( Serializer::kAllowedKeys[ Serializer::kCPUseExactPacketLength ], false );
		SetParameter( Serializer::kAllowedKeys[ Serializer::kCPOmitAllFormatting ], false );
		SetParameter( Serializer::kAllowedKeys[ Serializer::kCPOmitMetaElement ], false );
		SetParameter( Serializer::kAllowedKeys[ Serializer::kCPOmitRDFHash ], true );
		SetParameter( Serializer::kAllowedKeys[ Serializer::kCPUseEncoding ], ( uint64 ) 8 );
		SetParameter( Serializer::kAllowedKeys[ Serializer::kCPUseBigEndian ], false );
		SetParameter( Serializer::kAllowedKeys[ Serializer::kCPPaddingLength ], ( uint64 ) 2048 );

	}

	spIUTF8String APICALL RDFDOMSerializerImpl::SerializeInternal(const spINode & node, XMP_OptionBits options, sizet padding, const char * newline, const char * indent, sizet baseIndent, const spcINameSpacePrefixMap & nameSpacePrefixMap) const {

//		shared_ptr< XMPMeta > spMeta(new XMPMeta());
//		spINameSpacePrefixMap_I genereatedMap;
//
//		spcINameSpacePrefixMap mergedMap = INameSpacePrefixMap::GetDefaultNameSpacePrefixMap();
//		if (nameSpacePrefixMap) {
//			spINameSpacePrefixMap newMergedMap = mergedMap->Clone();
//			newMergedMap->GetINameSpacePrefixMap_I()->Merge(nameSpacePrefixMap);
//			mergedMap = newMergedMap;
//		}
//		spINameSpacePrefixMap_I userSuppliedMap(MakeUncheckedSharedPointer(const_pointer_cast<INameSpacePrefixMap>(mergedMap)->GetINameSpacePrefixMap_I(), __FILE__, __LINE__, true));
//
//		// TODO:meta->SetErrorCallback()
//		HandleNode(node, &spMeta->tree, userSuppliedMap, genereatedMap, true, false);
//
//		NormalizeDCArrays(&(spMeta->tree));
//		if (spMeta->tree.options & kXMP_PropHasAliases) MoveExplicitAliases(&spMeta->tree, options, spMeta->errorCallback);
//		TouchUpDataModel(spMeta.get(), spMeta->errorCallback);
//
//		// Delete empty schema nodes. Do this last, other cleanup can make empty schema.
//		size_t schemaNum = 0;
//		while (schemaNum < spMeta->tree.children.size()) {
//			XMP_Node * currSchema = spMeta->tree.children[schemaNum];
//			if (currSchema->children.size() > 0) {
//				++schemaNum;
//			}
//			else {
//				delete spMeta->tree.children[schemaNum];	// ! Delete the schema node itself.
//				spMeta->tree.children.erase(spMeta->tree.children.begin() + schemaNum);
//			}
//		}
        
        shared_ptr< XMPMeta > spMeta( (XMPMeta*)(IMetadataConverterUtils_I::convertIMetadatatoXMPMeta(node, options, nameSpacePrefixMap)));
		std::string buffer;
		spMeta->SerializeToBuffer(&buffer, options, (XMP_Uns32)padding, newline, indent, (XMP_Index)baseIndent);
		spIUTF8String serializedOutput = IUTF8String_I::CreateUTF8String(buffer.c_str(), buffer.size());
		return serializedOutput;

	}

}
