/**
 * Enacts the transaction.
 */
void FTransaction::Apply()
{
	checkSlow(Inc==1||Inc==-1);

	// Figure out direction.
	const int32 Start = Inc==1 ? 0             : Records.Num()-1;
	const int32 End   = Inc==1 ? Records.Num() :              -1;

	// Init objects.
	TArray<UObject*> ChangedObjects;
	for( int32 i=Start; i!=End; i+=Inc )
	{
		Records[i].bRestored = false;
		if(ChangedObjects.Find(Records[i].Object) == INDEX_NONE)
		{
			Records[i].Object->CheckDefaultSubobjects();
			Records[i].Object->PreEditUndo();
			ChangedObjects.Add(Records[i].Object);
		}
	}
	for( int32 i=Start; i!=End; i+=Inc )
	{
		Records[i].Restore( this );
	}

	NumModelsModified = 0;		// Count the number of UModels that were changed.
	for(int32 ObjectIndex = 0;ObjectIndex < ChangedObjects.Num();ObjectIndex++)
	{
		UObject* ChangedObject = ChangedObjects[ObjectIndex];
		UModel* Model = Cast<UModel>(ChangedObject);
		if( Model && Model->Nodes.Num() )
		{
			FBSPOps::bspBuildBounds( Model );
			++NumModelsModified;
		}
		ChangedObject->PostEditUndo();
	}
	
	// Rebuild BSP here instead of waiting for the next tick since
	// multiple transaction events can occur in a single tick
	if (ABrush::NeedsRebuild())
	{
		GEditor->RebuildAlteredBSP();
	}

	// Flip it.
	if( bFlip )
	{
		Inc *= -1;
	}
	for(int32 ObjectIndex = 0;ObjectIndex < ChangedObjects.Num();ObjectIndex++)
	{
		UObject* ChangedObject = ChangedObjects[ObjectIndex];
		ChangedObject->CheckDefaultSubobjects();
	}
}
/**
 * Enacts the transaction.
 */
void FTransaction::Apply()
{
	checkSlow(Inc==1||Inc==-1);

	// Figure out direction.
	const int32 Start = Inc==1 ? 0             : Records.Num()-1;
	const int32 End   = Inc==1 ? Records.Num() :              -1;

	// Init objects.
	for( int32 i=Start; i!=End; i+=Inc )
	{
		FObjectRecord& Record = Records[i];
		Record.bRestored = false;

		UObject* Object = Record.Object.Get();
		if (Object)
		{
			if (!ChangedObjects.Contains(Object))
			{
				Object->CheckDefaultSubobjects();
				Object->PreEditUndo();
			}

			ChangedObjects.Add(Object, Record.ObjectAnnotation);
		}
	}

	if (bFlip)
	{
		for (int32 i = Start; i != End; i += Inc)
		{
			Records[i].Save(this);
		}
		for (int32 i = Start; i != End; i += Inc)
		{
			Records[i].Load(this);
		}
	}
	else
	{
		for (int32 i = Start; i != End; i += Inc)
		{
			Records[i].Restore(this);
		}
	}

	// An Actor's components must always get its PostEditUndo before the owning Actor so do a quick sort
	ChangedObjects.KeySort([](UObject& A, UObject& B)
	{
		UActorComponent* BAsComponent = Cast<UActorComponent>(&B);
		return (BAsComponent ? (BAsComponent->GetOwner() != &A) : true);
	});

	TArray<ULevel*> LevelsToCommitModelSurface;
	NumModelsModified = 0;		// Count the number of UModels that were changed.
	for (auto ChangedObjectIt : ChangedObjects)
	{
		UObject* ChangedObject = ChangedObjectIt.Key;
		UModel* Model = Cast<UModel>(ChangedObject);
		if (Model && Model->Nodes.Num())
		{
			FBSPOps::bspBuildBounds(Model);
			++NumModelsModified;
		}
		
		if (UModelComponent* ModelComponent = Cast<UModelComponent>(ChangedObject))
		{
			ULevel* Level = ModelComponent->GetTypedOuter<ULevel>();
			check(Level);
			LevelsToCommitModelSurface.AddUnique(Level);
		}

		TSharedPtr<ITransactionObjectAnnotation> ChangedObjectTransactionAnnotation = ChangedObjectIt.Value;
		if (ChangedObjectTransactionAnnotation.IsValid())
		{
			ChangedObject->PostEditUndo(ChangedObjectTransactionAnnotation);
		}
		else
		{
			ChangedObject->PostEditUndo();
		}
	}

	// Commit model surfaces for unique levels within the transaction
	for (ULevel* Level : LevelsToCommitModelSurface)
	{
		Level->CommitModelSurfaces();
	}

	// Flip it.
	if (bFlip)
	{
		Inc *= -1;
	}
	for (auto ChangedObjectIt : ChangedObjects)
	{
		UObject* ChangedObject = ChangedObjectIt.Key;
		ChangedObject->CheckDefaultSubobjects();
	}

	ChangedObjects.Empty();
}