bool FInternationalizationArchiveJsonSerializer::SerializeInternal( TSharedRef< const FInternationalizationArchive > InInternationalizationArchive, TSharedRef< FJsonObject > JsonObj )
{
	TSharedPtr< FStructuredArchiveEntry > RootElement = MakeShareable( new FStructuredArchiveEntry( TEXT("") ) );

	// Condition the data so that it exists in a structured hierarchy for easy population of the JSON object.
	GenerateStructuredData( InInternationalizationArchive, RootElement );

	SortStructuredData( RootElement );

	// Clear anything that may be in the JSON object
	JsonObj->Values.Empty();

	// Setup the JSON object using the structured data created
	StructuredDataToJsonObj( RootElement, JsonObj );
	return true;
}
bool FInternationalizationManifestJsonSerializer::SerializeInternal( TSharedRef< const FInternationalizationManifest > InManifest, TSharedRef< FJsonObject > JsonObj )
{
	TSharedPtr< FStructuredEntry > RootElement = MakeShareable( new FStructuredEntry( TEXT("") ) );

	// Condition the data so that it exists in a structured hierarchy for easy population of the JSON object.
	GenerateStructuredData( InManifest, RootElement );

	// Arrange the entries in non-cultural format so that diffs are easier to read.
	SortStructuredData( RootElement );

	//Clear out anything that may be in the JSON object
	JsonObj->Values.Empty();

	// Setup the JSON object using the structured data created
	StructuredDataToJsonObj( RootElement, JsonObj );

	return true;
}
bool FJsonInternationalizationArchiveSerializer::SerializeInternal(TSharedRef<const FInternationalizationArchive> InArchive, TSharedRef<FJsonObject> JsonObj)
{
	TSharedPtr<FStructuredArchiveEntry> RootElement = MakeShareable(new FStructuredArchiveEntry(FString()));

	// Condition the data so that it exists in a structured hierarchy for easy population of the JSON object.
	GenerateStructuredData(InArchive, RootElement);

	SortStructuredData(RootElement);

	// Clear anything that may be in the JSON object
	JsonObj->Values.Empty();

	// Set format version.
	JsonObj->SetNumberField(TAG_FORMATVERSION, static_cast<double>(InArchive->GetFormatVersion()));

	// Setup the JSON object using the structured data created
	StructuredDataToJsonObj(RootElement, JsonObj);
	return true;
}
void FJsonInternationalizationArchiveSerializer::StructuredDataToJsonObj( TSharedPtr< const FStructuredArchiveEntry > InElement, TSharedRef< FJsonObject > OutJsonObj )
{
	OutJsonObj->SetStringField( TAG_NAMESPACE, InElement->Namespace );

	TArray< TSharedPtr< FJsonValue > > NamespaceArray;
	TArray< TSharedPtr< FJsonValue > > EntryArray;

	//Write namespace content entries
	for( TArray< TSharedPtr< FArchiveEntry > >::TConstIterator Iter( InElement->ArchiveEntries ); Iter; ++Iter )
	{
		const TSharedPtr< FArchiveEntry > Entry = *Iter;
		TSharedPtr< FJsonObject > EntryNode = MakeShareable( new FJsonObject );

		FString ProcessedSourceText = Entry->Source.Text;
		FString ProcessedTranslation = Entry->Translation.Text;

		TSharedPtr< FJsonObject > SourceNode;
		if( Entry->Source.MetadataObj.IsValid() )
		{
			FJsonInternationalizationMetaDataSerializer::SerializeMetadata( Entry->Source.MetadataObj.ToSharedRef(), SourceNode );
		}

		if( !SourceNode.IsValid() )
		{
			SourceNode = MakeShareable( new FJsonObject );
		}

		SourceNode->SetStringField( TAG_SOURCE_TEXT, ProcessedSourceText );
		EntryNode->SetObjectField( TAG_SOURCE, SourceNode );
		
		TSharedPtr< FJsonObject > TranslationNode;
		if( Entry->Translation.MetadataObj.IsValid() )
		{
			FJsonInternationalizationMetaDataSerializer::SerializeMetadata( Entry->Translation.MetadataObj.ToSharedRef(), TranslationNode );
		}

		if( !TranslationNode.IsValid() )
		{
			TranslationNode = MakeShareable( new FJsonObject );
		}

		TranslationNode->SetStringField( TAG_TRANSLATION_TEXT, ProcessedTranslation );
		EntryNode->SetObjectField( TAG_TRANSLATION, TranslationNode );

		EntryNode->SetStringField( TAG_KEY, Entry->Key );

		if( Entry->KeyMetadataObj.IsValid() )
		{
			TSharedRef< FJsonObject > MetaDataNode = MakeShareable(new FJsonObject());
			EntryNode->SetObjectField( TAG_METADATA, MetaDataNode );

			TSharedPtr< FJsonObject > KeyMetaDataNode;
			FJsonInternationalizationMetaDataSerializer::SerializeMetadata( Entry->KeyMetadataObj.ToSharedRef(), KeyMetaDataNode );
			if( KeyMetaDataNode.IsValid() )
			{
				MetaDataNode->SetObjectField( TAG_METADATA_KEY, KeyMetaDataNode );
			}
		}

		// We only add the optional field if it is true, it is assumed to be false otherwise.
		if( Entry->bIsOptional == true )
		{
			EntryNode->SetBoolField( TAG_OPTIONAL, Entry->bIsOptional );
		}

		EntryArray.Add( MakeShareable( new FJsonValueObject( EntryNode ) ) );
	}

	//Write the subnamespaces
	for( TArray< TSharedPtr< FStructuredArchiveEntry > >::TConstIterator Iter( InElement->SubNamespaces ); Iter; ++Iter )
	{
		const TSharedPtr<FStructuredArchiveEntry> SubElement = *Iter;
		if( SubElement.IsValid() )
		{
			TSharedRef<FJsonObject> SubObject = MakeShareable( new FJsonObject );
			StructuredDataToJsonObj( SubElement, SubObject );

			NamespaceArray.Add( MakeShareable( new FJsonValueObject( SubObject ) ) );
		}
	}

	if( EntryArray.Num() > 0 )
	{
		OutJsonObj->SetArrayField( TAG_CHILDREN, EntryArray );
	}

	if( NamespaceArray.Num() > 0 )
	{
		OutJsonObj->SetArrayField( TAG_SUBNAMESPACES, NamespaceArray );
	}
}
void FInternationalizationManifestJsonSerializer::StructuredDataToJsonObj( TSharedPtr< const FStructuredEntry > InElement, TSharedRef< FJsonObject > JsonObj )
{

	JsonObj->SetStringField( TAG_NAMESPACE, InElement->Namespace );

	TArray< TSharedPtr< FJsonValue > > NamespaceArray;
	TArray< TSharedPtr< FJsonValue > > EntryArray;

	//Write namespace content entries
	for( TArray< TSharedPtr< FManifestEntry > >::TConstIterator Iter( InElement->ManifestEntries ); Iter; ++Iter )
	{
		const TSharedPtr< FManifestEntry > Entry = *Iter;
		TSharedPtr< FJsonObject > EntryNode = MakeShareable( new FJsonObject );

		TSharedPtr<FJsonObject> SourceNode;

		if( Entry->Source.MetadataObj.IsValid() )
		{
			FInternationalizationMetaDataJsonSerializer::SerializeMetadata( Entry->Source.MetadataObj.ToSharedRef(), SourceNode );
		}
		
		if( !SourceNode.IsValid() )
		{
			SourceNode = MakeShareable( new FJsonObject );
		}

		// Add escapes for special chars - doesn't do backslash
		FString ProcessedText = Entry->Source.Text.ReplaceQuotesWithEscapedQuotes();
		SourceNode->SetStringField( TAG_SOURCE_TEXT, ProcessedText );

		EntryNode->SetObjectField( TAG_SOURCE, SourceNode );

		TArray< TSharedPtr< FJsonValue > > KeyArray;

		for(auto ContextIter = Entry->Contexts.CreateConstIterator(); ContextIter; ++ContextIter)
		{
			const FContext& AContext = *ContextIter;

			FString ProcessedText = AContext.SourceLocation;
			ProcessedText.ReplaceInline( TEXT("\\"), TEXT("/"));
			ProcessedText.ReplaceInline( *FPaths::RootDir(), TEXT("/"));

			TSharedPtr<FJsonObject> KeyNode = MakeShareable( new FJsonObject );
			KeyNode->SetStringField( TAG_KEY, AContext.Key );
			KeyNode->SetStringField( TAG_PATH, ProcessedText );

			// We only add the optional field if it is true, it is assumed to be false otherwise.
			if( AContext.bIsOptional == true )
			{
				KeyNode->SetBoolField( TAG_OPTIONAL, AContext.bIsOptional);
			}

			TSharedPtr< FJsonObject > MetaDataNode = MakeShareable( new FJsonObject );

			if( AContext.InfoMetadataObj.IsValid() )
			{
				TSharedPtr< FJsonObject > InfoDataNode;
				FInternationalizationMetaDataJsonSerializer::SerializeMetadata( AContext.InfoMetadataObj.ToSharedRef(), InfoDataNode );
				if( InfoDataNode.IsValid() )
				{
					MetaDataNode->SetObjectField( TAG_METADATA_INFO, InfoDataNode );
				}
			}

			if( AContext.KeyMetadataObj.IsValid() )
			{
				TSharedPtr< FJsonObject > KeyDataNode;
				FInternationalizationMetaDataJsonSerializer::SerializeMetadata( AContext.KeyMetadataObj.ToSharedRef(), KeyDataNode );
				if( KeyDataNode.IsValid() )
				{
					MetaDataNode->SetObjectField( TAG_METADATA_KEY, KeyDataNode );
				}
			}

			if( MetaDataNode->Values.Num() > 0 )
			{
				KeyNode->SetObjectField( TAG_METADATA, MetaDataNode );
			}
			
			KeyArray.Add( MakeShareable( new FJsonValueObject( KeyNode ) ) );
		}

		EntryNode->SetArrayField( TAG_KEYCOLLECTION, KeyArray);

		EntryArray.Add( MakeShareable( new FJsonValueObject( EntryNode ) ) );
	}

	//Write the subnamespaces
	for( TArray< TSharedPtr< FStructuredEntry > >::TConstIterator Iter( InElement->SubNamespaces.CreateConstIterator() ); Iter; ++Iter )
	{
		const TSharedPtr< FStructuredEntry > SubElement = *Iter;

		if(SubElement.IsValid())
		{
			TSharedRef< FJsonObject > SubObject = MakeShareable( new FJsonObject );
			StructuredDataToJsonObj( SubElement, SubObject );

			NamespaceArray.Add( MakeShareable( new FJsonValueObject( SubObject ) ) );
		}
	}

	if( EntryArray.Num() > 0 )
	{
		JsonObj->SetArrayField( TAG_CHILDREN, EntryArray );
	}

	if( NamespaceArray.Num() > 0 )
	{
		JsonObj->SetArrayField( TAG_SUBNAMESPACES, NamespaceArray );
	}
}