bool FJsonInternationalizationManifestSerializer::DeserializeInternal( TSharedRef< FJsonObject > InJsonObj, TSharedRef< FInternationalizationManifest > Manifest )
{
	if( InJsonObj->HasField( TAG_FORMATVERSION ) )
	{
		const int32 FormatVersion = static_cast<int32>(InJsonObj->GetNumberField( TAG_FORMATVERSION ));
		Manifest->SetFormatVersion(static_cast<FInternationalizationManifest::EFormatVersion>(FormatVersion));
	}
	else
	{
		Manifest->SetFormatVersion(FInternationalizationManifest::EFormatVersion::Initial);
	}

	return JsonObjToManifest(InJsonObj, TEXT(""), Manifest );
}
bool FInternationalizationManifestJsonSerializer::JsonObjToManifest( TSharedRef< FJsonObject > InJsonObj, FString ParentNamespace, TSharedRef< FInternationalizationManifest > Manifest )
{
	bool bConvertSuccess = true;
	FString AccumulatedNamespace = ParentNamespace;
	if( InJsonObj->HasField( TAG_NAMESPACE) )
	{
		if( !( AccumulatedNamespace.IsEmpty() ) )
		{
			AccumulatedNamespace += NAMESPACE_DELIMITER;
		}
		AccumulatedNamespace += InJsonObj->GetStringField( TAG_NAMESPACE );
	}
	else
	{
		// We found an entry with a missing namespace
		bConvertSuccess = false;
	}

	// Process all the child objects
	if( bConvertSuccess && InJsonObj->HasField( TAG_CHILDREN ) )
	{
		const TArray< TSharedPtr< FJsonValue> > ChildrenArray = InJsonObj->GetArrayField( TAG_CHILDREN );

		for(TArray< TSharedPtr< FJsonValue > >::TConstIterator ChildIter( ChildrenArray.CreateConstIterator() ); ChildIter && bConvertSuccess; ++ChildIter)
		{
			const TSharedPtr< FJsonValue >  ChildEntry = *ChildIter;
			const TSharedPtr< FJsonObject > ChildJSONObject = ChildEntry->AsObject();

			
			FString SourceText;
			TSharedPtr< FLocMetadataObject > SourceMetadata;
			if( ChildJSONObject->HasTypedField< EJson::String>( TAG_DEPRECATED_DEFAULTTEXT) )
			{
				SourceText = ChildJSONObject->GetStringField( TAG_DEPRECATED_DEFAULTTEXT );
			}
			else if( ChildJSONObject->HasTypedField< EJson::Object>( TAG_SOURCE ) )
			{
				const TSharedPtr< FJsonObject > SourceJSONObject = ChildJSONObject->GetObjectField( TAG_SOURCE );
				if( SourceJSONObject->HasTypedField< EJson::String >( TAG_SOURCE_TEXT ) )
				{
					SourceText = SourceJSONObject->GetStringField( TAG_SOURCE_TEXT );

					// Source meta data is mixed in with the source text, we'll process metadata if the source json object has more than one entry
					if( SourceJSONObject->Values.Num() > 1 )
					{
						// We load in the entire source object as metadata and remove the source object
						FInternationalizationMetaDataJsonSerializer::DeserializeMetadata( SourceJSONObject.ToSharedRef(), SourceMetadata );
						if( SourceMetadata.IsValid() )
						{
							SourceMetadata->Values.Remove( TAG_SOURCE_TEXT );
						}
					}
				}
				else
				{
					bConvertSuccess = false;
				}
			}
			else
			{
				bConvertSuccess = false;
			}

			FLocItem Source(SourceText);
			Source.MetadataObj = SourceMetadata;

			if( bConvertSuccess && ChildJSONObject->HasField( TAG_KEYCOLLECTION ) )
			{
				
				const TArray< TSharedPtr<FJsonValue> > ContextArray = ChildJSONObject->GetArrayField( TAG_KEYCOLLECTION);

				for(TArray< TSharedPtr< FJsonValue > >::TConstIterator ContextIter( ContextArray.CreateConstIterator() ); ContextIter && bConvertSuccess; ++ContextIter)
				{
					const TSharedPtr< FJsonValue > ContextEntry = *ContextIter;
					const TSharedPtr< FJsonObject > ContextJSONObject = ContextEntry->AsObject();

					if( ContextJSONObject->HasTypedField< EJson::String >( TAG_KEY ) )
					{
						const FString Key = ContextJSONObject->GetStringField( TAG_KEY );
						const FString SourceLocation = ContextJSONObject->HasField( TAG_PATH ) ? ContextJSONObject->GetStringField( TAG_PATH ) : FString();

						FContext CommandContext;
						CommandContext.Key = Key;
						CommandContext.SourceLocation = SourceLocation;

						if( ContextJSONObject->HasTypedField< EJson::Boolean >( TAG_OPTIONAL ) )
						{
							CommandContext.bIsOptional = ContextJSONObject->GetBoolField( TAG_OPTIONAL );
						}

						if( ContextJSONObject->HasTypedField< EJson::Object >( TAG_METADATA ) )
						{
							const TSharedPtr< FJsonObject > MetaDataJSONObject = ContextJSONObject->GetObjectField( TAG_METADATA );

							if( MetaDataJSONObject->HasTypedField< EJson::Object >( TAG_METADATA_INFO ) )
							{
								const TSharedPtr< FJsonObject > MetaDataInfoJSONObject = MetaDataJSONObject->GetObjectField( TAG_METADATA_INFO );

								TSharedPtr< FLocMetadataObject > MetadataNode;
								FInternationalizationMetaDataJsonSerializer::DeserializeMetadata( MetaDataInfoJSONObject.ToSharedRef(), MetadataNode );
								if( MetadataNode.IsValid() )
								{
									CommandContext.InfoMetadataObj = MetadataNode;
								}
							}

							if( MetaDataJSONObject->HasTypedField< EJson::Object >( TAG_METADATA_KEY ) )
							{
								const TSharedPtr< FJsonObject > MetaDataKeyJSONObject = MetaDataJSONObject->GetObjectField( TAG_METADATA_KEY );

								TSharedPtr< FLocMetadataObject > MetadataNode;
								FInternationalizationMetaDataJsonSerializer::DeserializeMetadata( MetaDataKeyJSONObject.ToSharedRef(), MetadataNode );
								if( MetadataNode.IsValid() )
								{
									CommandContext.KeyMetadataObj = MetadataNode;
								}
							}
						}
						bool bAddSuccessful = Manifest->AddSource( AccumulatedNamespace, Source, CommandContext );
						if(!bAddSuccessful)
						{
							UE_LOG( LogInternationalizationManifestSerializer, Warning,TEXT("Could not add JSON entry to the Internationalization manifest: Namespace:%s SourceText:%s SourceData:%s"), 
								*AccumulatedNamespace, 
								*SourceText, 
								*FInternationalizationMetaDataJsonSerializer::MetadataToString(Source.MetadataObj) );
						}
					}
					else
					{
						//We found a context entry that is missing a identifier/key or a path
						bConvertSuccess = false;
						break;
					}

				}
			}
			else
			{
				// We have an entry that is missing a key/context collection or default text entry.
				bConvertSuccess = false;
				break;
			}

		}
	}

	if( bConvertSuccess && InJsonObj->HasField( TAG_SUBNAMESPACES ) )
	{
		const TArray< TSharedPtr<FJsonValue> > SubnamespaceArray = InJsonObj->GetArrayField( TAG_SUBNAMESPACES );

		for(TArray< TSharedPtr< FJsonValue > >::TConstIterator SubnamespaceIter( SubnamespaceArray.CreateConstIterator() ); SubnamespaceIter; ++SubnamespaceIter )
		{
			const TSharedPtr< FJsonValue >  SubnamespaceEntry = *SubnamespaceIter;
			const TSharedPtr< FJsonObject > SubnamespaceJSONObject = SubnamespaceEntry->AsObject();

			if( !JsonObjToManifest( SubnamespaceJSONObject.ToSharedRef(), AccumulatedNamespace, Manifest ) )
			{
				bConvertSuccess = false;
				break;
			}
		}
	}
	
	return bConvertSuccess;
}
bool FInternationalizationManifestJsonSerializer::DeserializeInternal( TSharedRef< FJsonObject > InJsonObj, TSharedRef< FInternationalizationManifest > Manifest )
{
	return JsonObjToManifest(InJsonObj, TEXT(""), Manifest );
}