bool FFeaturePackContentSource::LoadPakFileToBuffer(FPakPlatformFile& PakPlatformFile, FString Path, TArray<uint8>& Buffer)
{
	bool bResult = false;
	TSharedPtr<IFileHandle> FileHandle(PakPlatformFile.OpenRead(*Path));
	if( FileHandle.IsValid())
	{
		Buffer.AddUninitialized(FileHandle->Size());
		bResult = FileHandle->Read(Buffer.GetData(), FileHandle->Size());
	}
	return bResult;
}
FFeaturePackContentSource::FFeaturePackContentSource(FString InFeaturePackPath)
{
	FeaturePackPath = InFeaturePackPath;
	bPackValid = false;
	// Create a pak platform file and mount the feature pack file.
	FPakPlatformFile PakPlatformFile;
	FString CommandLine;
	PakPlatformFile.Initialize(&FPlatformFileManager::Get().GetPlatformFile(), TEXT(""));
	FString MountPoint = "root:/";
	PakPlatformFile.Mount(*InFeaturePackPath, 0, *MountPoint);
	
	// Gets the manifest file as a JSon string
	TArray<uint8> ManifestBuffer;
	if( LoadPakFileToBuffer(PakPlatformFile, FPaths::Combine(*MountPoint, TEXT("manifest.json")), ManifestBuffer) == false )
	{
		UE_LOG(LogFeaturePack, Warning, TEXT("Error in Feature pack %s. Cannot find manifest."), *InFeaturePackPath);
		Category = EContentSourceCategory::Unknown;
		return;
	}
	FString ManifestString;
	FFileHelper::BufferToString(ManifestString, ManifestBuffer.GetData(), ManifestBuffer.Num());

	// Populate text fields from the manifest.
	TSharedPtr<FJsonObject> ManifestObject;
	TSharedRef<TJsonReader<>> ManifestReader = TJsonReaderFactory<>::Create(ManifestString);
	FJsonSerializer::Deserialize(ManifestReader, ManifestObject);
	for (TSharedPtr<FJsonValue> NameValue : ManifestObject->GetArrayField("Name"))
	{
		TSharedPtr<FJsonObject> LocalizedNameObject = NameValue->AsObject();
		LocalizedNames.Add(FLocalizedText(
			LocalizedNameObject->GetStringField("Language"),
			FText::FromString(LocalizedNameObject->GetStringField("Text"))));
	}

	for (TSharedPtr<FJsonValue> DescriptionValue : ManifestObject->GetArrayField("Description"))
	{
		TSharedPtr<FJsonObject> LocalizedDescriptionObject = DescriptionValue->AsObject();
		LocalizedDescriptions.Add(FLocalizedText(
			LocalizedDescriptionObject->GetStringField("Language"),
			FText::FromString(LocalizedDescriptionObject->GetStringField("Text"))));
	}

	// Parse asset types field
	for (TSharedPtr<FJsonValue> AssetTypesValue : ManifestObject->GetArrayField("AssetTypes"))
	{
		TSharedPtr<FJsonObject> LocalizedAssetTypesObject = AssetTypesValue->AsObject();
		LocalizedAssetTypesList.Add(FLocalizedText(
			LocalizedAssetTypesObject->GetStringField("Language"),
			FText::FromString(LocalizedAssetTypesObject->GetStringField("Text"))));
	}
	
	// Parse class types field
	ClassTypes = ManifestObject->GetStringField("ClassTypes");
	
	// Parse initial focus asset
	FocusAssetIdent = ManifestObject->GetStringField("FocusAsset");

	FString CategoryString = ManifestObject->GetStringField("Category");	
	if (CategoryString == "CodeFeature")
	{
		Category = EContentSourceCategory::CodeFeature;
	}
	else if (CategoryString == "BlueprintFeature")
	{
		Category = EContentSourceCategory::BlueprintFeature;
	}
	else if (CategoryString == "Content")
	{
		Category = EContentSourceCategory::Content;
	}
	else
	{
		Category = EContentSourceCategory::Unknown;
	}

	// Load image data
	FString IconFilename = ManifestObject->GetStringField("Thumbnail");
	TSharedPtr<TArray<uint8>> IconImageData = MakeShareable(new TArray<uint8>());
	FString ThumbnailFile = FPaths::Combine(*MountPoint, TEXT("Media"), *IconFilename);
	if( LoadPakFileToBuffer(PakPlatformFile, ThumbnailFile, *IconImageData) == true)
	{
		IconData = MakeShareable(new FImageData(IconFilename, IconImageData));
	}
	else
	{
		UE_LOG(LogFeaturePack, Warning, TEXT("Error in Feature pack %s. Cannot find thumbnail %s."), *InFeaturePackPath, *ThumbnailFile );
	}

	const TArray<TSharedPtr<FJsonValue>> ScreenshotFilenameArray = ManifestObject->GetArrayField("Screenshots");
	for (const TSharedPtr<FJsonValue> ScreenshotFilename : ScreenshotFilenameArray)
	{
		TSharedPtr<TArray<uint8>> SingleScreenshotData = MakeShareable(new TArray<uint8>);
		LoadPakFileToBuffer(PakPlatformFile, FPaths::Combine(*MountPoint, TEXT("Media"), *ScreenshotFilename->AsString()), *SingleScreenshotData);
		ScreenshotData.Add(MakeShareable(new FImageData(ScreenshotFilename->AsString(), SingleScreenshotData)));
	}
	bPackValid = true;
}
FFeaturePackContentSource::FFeaturePackContentSource(FString InFeaturePackPath, bool bDontRegisterForSearch)
{
	FeaturePackPath = InFeaturePackPath;
	bPackValid = false;
	// Create a pak platform file and mount the feature pack file.
	FPakPlatformFile PakPlatformFile;
	FString CommandLine;
	PakPlatformFile.Initialize(&FPlatformFileManager::Get().GetPlatformFile(), TEXT(""));
	FString MountPoint = "root:/";
	PakPlatformFile.Mount(*InFeaturePackPath, 0, *MountPoint);
	
	// Gets the manifest file as a JSon string
	TArray<uint8> ManifestBuffer;
	if( LoadPakFileToBuffer(PakPlatformFile, FPaths::Combine(*MountPoint, TEXT("manifest.json")), ManifestBuffer) == false )
	{
		RecordAndLogError( FString::Printf(TEXT("Error in Feature pack %s. Cannot find manifest."), *InFeaturePackPath));
		Category = EContentSourceCategory::Unknown;
		return;
	}
	FString ManifestString;
	FFileHelper::BufferToString(ManifestString, ManifestBuffer.GetData(), ManifestBuffer.Num());

	// Populate text fields from the manifest.
	TSharedPtr<FJsonObject> ManifestObject;
	TSharedRef<TJsonReader<>> ManifestReader = TJsonReaderFactory<>::Create(ManifestString);
	FJsonSerializer::Deserialize(ManifestReader, ManifestObject);

	if (ManifestReader->GetErrorMessage().IsEmpty() == false)
	{
		RecordAndLogError( FString::Printf(TEXT("Error in Feature pack %s. Failed to parse manifest: %s"), *InFeaturePackPath, *ManifestReader->GetErrorMessage()));
		Category = EContentSourceCategory::Unknown;
		return;
	}

	TSharedPtr<FString> ManifestObjectErrorMessage;
	if (TryValidateManifestObject(ManifestObject, ManifestObjectErrorMessage) == false)
	{
		RecordAndLogError( FString::Printf(TEXT("Error in Feature pack %s. Manifest object error: %s"), *InFeaturePackPath, **ManifestObjectErrorMessage));
		Category = EContentSourceCategory::Unknown;
		return;
	}

	for (TSharedPtr<FJsonValue> NameValue : ManifestObject->GetArrayField("Name"))
	{
		TSharedPtr<FJsonObject> LocalizedNameObject = NameValue->AsObject();
		LocalizedNames.Add(FLocalizedText(
			LocalizedNameObject->GetStringField("Language"),
			FText::FromString(LocalizedNameObject->GetStringField("Text"))));
	}

	for (TSharedPtr<FJsonValue> DescriptionValue : ManifestObject->GetArrayField("Description"))
	{
		TSharedPtr<FJsonObject> LocalizedDescriptionObject = DescriptionValue->AsObject();
		LocalizedDescriptions.Add(FLocalizedText(
			LocalizedDescriptionObject->GetStringField("Language"),
			FText::FromString(LocalizedDescriptionObject->GetStringField("Text"))));
	}

	// Parse asset types field
	for (TSharedPtr<FJsonValue> AssetTypesValue : ManifestObject->GetArrayField("AssetTypes"))
	{
		TSharedPtr<FJsonObject> LocalizedAssetTypesObject = AssetTypesValue->AsObject();
		LocalizedAssetTypesList.Add(FLocalizedText(
			LocalizedAssetTypesObject->GetStringField("Language"),
			FText::FromString(LocalizedAssetTypesObject->GetStringField("Text"))));
	}
	
	// Parse asset types field
	if( ManifestObject->HasField("SearchTags")==true)
	{
		for (TSharedPtr<FJsonValue> AssetTypesValue : ManifestObject->GetArrayField("SearchTags"))
		{
			TSharedPtr<FJsonObject> LocalizedAssetTypesObject = AssetTypesValue->AsObject();
			LocalizedSearchTags.Add(FLocalizedTextArray(
				LocalizedAssetTypesObject->GetStringField("Language"),
				LocalizedAssetTypesObject->GetStringField("Text")));
		}
	}

	// Parse class types field
	ClassTypes = ManifestObject->GetStringField("ClassTypes");
	
	
	// Parse initial focus asset if we have one - this is not required
	if (ManifestObject->HasTypedField<EJson::String>("FocusAsset") == true)
	{
		FocusAssetIdent = ManifestObject->GetStringField("FocusAsset");
	}	

	// Use the path as the sort key - it will be alphabetical that way
	SortKey = FeaturePackPath;
	ManifestObject->TryGetStringField("SortKey", SortKey);

	FString CategoryString = ManifestObject->GetStringField("Category");	
	UEnum* Enum = FindObjectChecked<UEnum>(ANY_PACKAGE, TEXT("EContentSourceCategory"));
	int32 Index = Enum->FindEnumIndex(FName(*CategoryString));
	Category = Index != INDEX_NONE ? (EContentSourceCategory)Index : EContentSourceCategory::Unknown;

	// Load image data
	FString IconFilename = ManifestObject->GetStringField("Thumbnail");
	TSharedPtr<TArray<uint8>> IconImageData = MakeShareable(new TArray<uint8>());
	FString ThumbnailFile = FPaths::Combine(*MountPoint, TEXT("Media"), *IconFilename);
	if( LoadPakFileToBuffer(PakPlatformFile, ThumbnailFile, *IconImageData) == true)
	{
		IconData = MakeShareable(new FImageData(IconFilename, IconImageData));
	}
	else
	{
		RecordAndLogError( FString::Printf(TEXT("Error in Feature pack %s. Cannot find thumbnail %s."), *InFeaturePackPath, *ThumbnailFile ));
	}

	const TArray<TSharedPtr<FJsonValue>> ScreenshotFilenameArray = ManifestObject->GetArrayField("Screenshots");
	for (const TSharedPtr<FJsonValue> ScreenshotFilename : ScreenshotFilenameArray)
	{
		TSharedPtr<TArray<uint8>> SingleScreenshotData = MakeShareable(new TArray<uint8>);
		if( LoadPakFileToBuffer(PakPlatformFile, FPaths::Combine(*MountPoint, TEXT("Media"), *ScreenshotFilename->AsString()), *SingleScreenshotData) )
		{
			ScreenshotData.Add(MakeShareable(new FImageData(ScreenshotFilename->AsString(), SingleScreenshotData)));
		}
		else
		{
			RecordAndLogError( FString::Printf(TEXT("Error in Feature pack %s. Cannot find screenshot %s."), *InFeaturePackPath, *ScreenshotFilename->AsString() ));
		}
	}

	if( bDontRegisterForSearch == false )
	{
		FSuperSearchModule& SuperSearchModule = FModuleManager::LoadModuleChecked< FSuperSearchModule >(TEXT("SuperSearch"));
		SuperSearchModule.GetActOnSearchTextClicked().AddRaw(this, &FFeaturePackContentSource::HandleActOnSearchText);
		SuperSearchModule.GetSearchTextChanged().AddRaw(this, &FFeaturePackContentSource::HandleSuperSearchTextChanged);
	}
	bPackValid = true;
}