void FManifestInfo::ApplyManifestDependencies()
{
	if( ManifestDependencies.Num() > 0 )
	{
		TSharedRef< FInternationalizationManifest > NewManifest =  MakeShareable( new FInternationalizationManifest );
		// We'll generate a new manifest by only including items that are not in the dependencies
		for( TManifestEntryByContextIdContainer::TConstIterator It( Manifest->GetEntriesByContextIdIterator() ); It; ++It )
		{
			const TSharedRef<FManifestEntry> ManifestEntry = It.Value();

			for(  auto ContextIt = ManifestEntry->Contexts.CreateConstIterator(); ContextIt; ++ContextIt )
			{
				FString DependencyFileName;

				const TSharedPtr<FManifestEntry> DependencyEntry = FindDependencyEntrybyContext( ManifestEntry->Namespace, *ContextIt, DependencyFileName );
				
				if( DependencyEntry.IsValid() )
				{
					if( !(DependencyEntry->Source.IsExactMatch( ManifestEntry->Source )) )
					{
						// There is a dependency manifest entry that has the same namespace and keys as our main manifest entry but the source text differs.
						FString Message = UGatherTextCommandletBase::MungeLogOutput( FString::Printf(TEXT("Found previously entered localized string [%s] %s %s=\"%s\" %s. It was previously \"%s\" %s in dependency manifest %s."),
							*ManifestEntry->Namespace,
							*ContextIt->Key,
							*FInternationalizationMetaDataJsonSerializer::MetadataToString( ContextIt->KeyMetadataObj ),
							*ManifestEntry->Source.Text,
							*FInternationalizationMetaDataJsonSerializer::MetadataToString(ManifestEntry->Source.MetadataObj),
							*DependencyEntry->Source.Text,
							*FInternationalizationMetaDataJsonSerializer::MetadataToString(DependencyEntry->Source.MetadataObj),
							*DependencyFileName));
						UE_LOG(LogGatherTextCommandletBase, Warning, TEXT("%s"), *Message);

						FConflictReportInfo::GetInstance().AddConflict( ManifestEntry->Namespace, ContextIt->Key, ContextIt->KeyMetadataObj, ManifestEntry->Source, *ContextIt->SourceLocation );

						FContext* ConflictingContext = DependencyEntry->FindContext( ContextIt->Key, ContextIt->KeyMetadataObj );
						FString DependencyEntryFullSrcLoc = ( !DependencyFileName.IsEmpty() ) ? DependencyFileName : ConflictingContext->SourceLocation;
						
						FConflictReportInfo::GetInstance().AddConflict( ManifestEntry->Namespace, ContextIt->Key, ContextIt->KeyMetadataObj, DependencyEntry->Source, DependencyEntryFullSrcLoc );

					}
				}
				else
				{
					// Since we did not find any entries in the dependencies list that match, we'll add to the new manifest
					bool bAddSuccessful = NewManifest->AddSource( ManifestEntry->Namespace, ManifestEntry->Source, *ContextIt );
					if(!bAddSuccessful)
					{
						UE_LOG(LogGatherTextCommandletBase, Error, TEXT("Could not process localized string: %s [%s] %s=\"%s\" %s."),
							*ManifestEntry->Namespace,
							*ContextIt->Key,
							*ManifestEntry->Source.Text,
							*FInternationalizationMetaDataJsonSerializer::MetadataToString( ManifestEntry->Source.MetadataObj ));
					}
				}
			}
		}

		Manifest = NewManifest;
	}
}
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 UInternationalizationConditioningCommandlet::ProcessManifest( const FString& PrimaryLangExt, const FString& SourcePath, const FString& DestinationPath )
{
	FString ManifestName = TEXT("Manifest.txt");

	GetConfigString( *SectionName, TEXT("ManifestName"), ManifestName, GatherTextConfigPath );

	// Build info about the primary language
	TArray<FString> PrimaryFilenames;
	TArray<FString> PathPrimaryFilenames;
	FString PrimaryLocDirectory = SourcePath / PrimaryLangExt + TEXT("/");
	FString PrimaryWildcardName = PrimaryLocDirectory + TEXT("*.") + PrimaryLangExt;
	// Grab the list of primary language loc files
	IFileManager::Get().FindFiles(PathPrimaryFilenames, *PrimaryWildcardName, true, false);
	for ( int32 FileIndex = 0; FileIndex < PathPrimaryFilenames.Num(); FileIndex++ )
	{
		FString* CompleteFilename = new(PrimaryFilenames) FString(PrimaryLocDirectory + PathPrimaryFilenames[FileIndex]);
	}

	if ( PrimaryFilenames.Num() == 0 )
	{
		UE_LOG(LogInternationalizationConditioningCommandlet, Warning, TEXT("No primary language(%s) loc files found!"), *PrimaryLangExt);
		return false;
	}

	// Here we cheat a bit and use the primary language as the foreign language, some inefficiency here but it will let us leverage an
	//  existing system to get the entries we are after
	ReadLocFiles(PrimaryFilenames, PrimaryFilenames);

	// Instead of extracting the translated properties, we will pull out the identical properties which will be all the entries
	//  in the localization files since we are comparing the primary language with itself.
	TArray<FLocalizationFileEntry> IdenticalProperties;
	
	for ( int32 i = 0; i < LocPairs.Num(); i++ )
	{
		FLocalizationFilePair& Pair = LocPairs[i];
		Pair.CompareFiles();

		Pair.GetIdenticalProperties( IdenticalProperties );
	}

	// First we want to see if there is an existing manifest.  If so we will load it up and add our entries there
	TSharedRef< FInternationalizationManifest > InternationalizationManifest = MakeShareable( new FInternationalizationManifest );
	FInternationalizationManifestJsonSerializer ManifestSerializer;

	FString ExistingManifestFileName = DestinationPath / ManifestName;

	if( FPaths::FileExists(ExistingManifestFileName) )
	{
		TSharedPtr< FJsonObject > ExistingManifestJsonObject = ReadJSONTextFile( ExistingManifestFileName );
		if( ExistingManifestJsonObject.IsValid() )
		{
			ManifestSerializer.DeserializeManifest( ExistingManifestJsonObject.ToSharedRef(), InternationalizationManifest );
		}
	}

	// Now we add our properties to the manifest. 
	for( int PropIndex = 0; PropIndex < IdenticalProperties.Num(); PropIndex++ )
	{
		FLocalizationFileEntry& Prop = IdenticalProperties[PropIndex];

		// We use the file(package) name and the namespace for the manifest namespace so we avoid potential collisions when multiple ini files have entries where the KEY and namespace are the same but the source text is different
		FString NewNamespace = Prop.Namespace;
		FContext PropContext;
		PropContext.Key = Prop.Key;
		PropContext.SourceLocation = NewNamespace;
		FLocItem Source( Prop.SourceText );
		bool bAddSuccessful = InternationalizationManifest->AddSource( NewNamespace, Source, PropContext );
		if(!bAddSuccessful)
		{
			UE_LOG(LogInternationalizationConditioningCommandlet, Warning, TEXT("Could not add manifest entry %s."), *PropContext.SourceLocation );
		}
	}

	TSharedRef<FJsonObject> FinalManifestJsonObj = MakeShareable( new FJsonObject );
	ManifestSerializer.SerializeManifest( InternationalizationManifest, FinalManifestJsonObj );

	FString DestinationManifestFileName = DestinationPath / ManifestName;
	WriteJSONToTextFile( FinalManifestJsonObj, DestinationManifestFileName, SourceControlInfo );

	LocPairs.Empty();


	return true;
}