/** 
 * Perform some collision sweep tests. Creates a given shape mesh and checks collision normal against a collision shape type.
 * Data for tests is in the [/Script/UnrealEd.CollisionAutomationTestConfigData] section of BaseEditor.ini
 *
 * @param Parameters - Unused for this test
 * @return	TRUE if the test was successful, FALSE otherwise
 */
bool FComponentSweepMultiTest::RunTest(const FString& Parameters)
{	
	CollisionAutomationTests::TestBase = this;
	// Create map
	UWorld* World = FAutomationEditorCommonUtils::CreateNewMap();
	TestNotNull( TEXT("Failed to create world for Physics.Collision.Ray Test. Tests aborted."), World );

	static FName TraceIdent = FName(TEXT("TestTrace"));
	
	FVector StartPos;
	FVector EndPos;
	ECollisionChannel Channel = ECC_WorldStatic;
	
	UCollisionAutomationTestConfigData* Data = UCollisionAutomationTestConfigData::StaticClass()->GetDefaultObject<UCollisionAutomationTestConfigData>();
	
	// Get the tests
	for (int32 iTest = 0; iTest < Data->ComponentSweepMultiTests.Num(); iTest++)
	{
		FCollisionTestEntry OneElement = Data->ComponentSweepMultiTests[iTest];

		// Create the Actor to check against
		AStaticMeshActor* TestRayMeshActor = CollisionAutomationTests::CreateShapeMeshActor( *OneElement.RootShapeAsset, OneElement.HitResult.TraceEnd);
		// Create the collision component
		AActor* TestRayCollisionActor = CollisionAutomationTests::CreateCollisionShape( World, OneElement.ShapeType, OneElement.HitResult.TraceStart);
		
		if ((TestRayMeshActor != nullptr) && (TestRayCollisionActor != nullptr))
		{			
			// Set the collision profile and enable collision and physics
			TestRayMeshActor->GetStaticMeshComponent()->BodyInstance.SetCollisionProfileName(TEXT("BlockAll"));
			TestRayMeshActor->SetActorEnableCollision(true);
			TestRayMeshActor->GetStaticMeshComponent()->BodyInstance.bSimulatePhysics = true;
			UShapeComponent* CollisionComponent = Cast<UShapeComponent>(TestRayCollisionActor->GetRootComponent());
			TestRayCollisionActor->SetActorEnableCollision(true);
			if( CollisionComponent != nullptr )
			{
				CollisionComponent->SetCollisionProfileName(TEXT("BlockAll"));
				CollisionComponent->SetSimulatePhysics(true);
			}
			
			// Setup positions
			StartPos = TestRayCollisionActor->GetActorLocation();
			EndPos = TestRayMeshActor->GetActorLocation();
			// Setup the query
			FComponentQueryParams ShapeQueryParameters(TraceIdent, nullptr);
			ShapeQueryParameters.bTraceComplex = true;
			ShapeQueryParameters.bTraceAsyncScene = true;

			// Perform test
			TArray<FHitResult> OutHits;
			bool WasBlocked = World->ComponentSweepMulti(OutHits, CollisionComponent, StartPos, EndPos, FRotator::ZeroRotator, ShapeQueryParameters);
			bool BlockedBySpecified = false;
			if (WasBlocked == true)
			{
				for (int32 iHits = 0; iHits < OutHits.Num(); iHits++)
				{
					AActor* EachActor = OutHits[iHits].GetActor();
					if (EachActor == TestRayMeshActor)
					{
						BlockedBySpecified = true;	
						// This generates a snippet you can copy/paste into the ini file for test validation
						//UE_LOG(CollisionAutomationTestLog, Log, TEXT("%d:HitResult=(%s)"), iTest+1, *(CollisionAutomationTests::HitToString(OutHits[iHits])));

						CollisionAutomationTests::CheckVector( OutHits[iHits].ImpactNormal, OneElement.HitResult.ImpactNormal, TEXT("ComponentSweepMulti"), TEXT("ImpactNormal"), iTest );
						CollisionAutomationTests::CheckVector( OutHits[iHits].Normal, OneElement.HitResult.Normal, TEXT("ComponentSweepMulti"), TEXT("Normal"), iTest );
						CollisionAutomationTests::CheckVector( OutHits[iHits].ImpactPoint, OneElement.HitResult.ImpactPoint, TEXT("ComponentSweepMulti"), TEXT("ImpactPoint"), iTest );
						CollisionAutomationTests::CheckFloat( OutHits[iHits].Time, OneElement.HitResult.Time, TEXT("ComponentSweepMulti"), TEXT("Time"), iTest );
					}
				}
			}
			TestTrue(FString::Printf(TEXT("Test %d:ComponentSweepMulti from %s to %s failed. Should return blocking hit"), iTest+1, *TestRayMeshActor->GetName(), *TestRayCollisionActor->GetName()), BlockedBySpecified);
		}
		// Remove the actors
		TestRayMeshActor->Destroy();
		TestRayCollisionActor->Destroy();
	}

	return true;
}