/**
 * Debug spew for components
 * @param Object object to dump component spew for
 */
void DumpComponents(UObject *Object)
{
    for ( FObjectIterator It; It; ++It )
    {
        It->UnMark(EObjectMark(OBJECTMARK_TagImp | OBJECTMARK_TagExp));
    }

    if (FPlatformMisc::IsDebuggerPresent() )
    {
        // if we have a debugger attached, the watch window won't be able to display the full output if we attempt to log it as a single string
        // so pass in GLog instead so that each line is sent separately;  this causes the output to have an extra line break between each log statement,
        // but at least we'll be able to see the full output in the debugger's watch window
        UE_LOG(LogExporter, Log, TEXT("Components for '%s':"), *Object->GetFullName());
        ExportProperties( NULL, *GLog, Object->GetClass(), (uint8*)Object, 0, NULL, NULL, Object, PPF_SubobjectsOnly );
        UE_LOG(LogExporter, Log, TEXT("<--- DONE!"));
    }
    else
    {
        FStringOutputDevice Output;
        Output.Logf(TEXT("Components for '%s':\r\n"), *Object->GetFullName());
        ExportProperties( NULL, Output, Object->GetClass(), (uint8*)Object, 2, NULL, NULL, Object, PPF_SubobjectsOnly );
        Output.Logf(TEXT("<--- DONE!\r\n"));
        UE_LOG(LogExporter, Log, TEXT("%s"), *Output);
    }
}
/**
 * Removes marks from and object
 *
 * @param	Object	Object to remove marks from
 * @param	Marks	Logical OR of OBJECTMARK_'s to remove 
 */
void UnMarkObject(const class UObjectBase* Object, EObjectMark Marks)
{
	FObjectMark Annotation = MarkAnnotation.GetAnnotation(Object);
	if(Annotation.Marks & Marks)
	{
		MarkAnnotation.AddAnnotation(Object,FObjectMark(EObjectMark(Annotation.Marks & ~Marks)));
	}
}
FString DumpObjectToString(UObject* Object)
{
    UnMarkAllObjects(EObjectMark(OBJECTMARK_TagExp | OBJECTMARK_TagImp));

    FStringOutputDevice Archive;
    const FExportObjectInnerContext Context;
    UExporter::ExportToOutputDevice(&Context, Object, NULL, Archive, TEXT("copy"), 0, PPF_Copy | PPF_DebugDump, false);

    return Archive;
}
FString DumpComponentsToString(UObject *Object)
{
    UnMarkAllObjects(EObjectMark(OBJECTMARK_TagExp | OBJECTMARK_TagImp));

    FStringOutputDevice Output;
    Output.Logf(TEXT("Components for '%s':\r\n"), *Object->GetFullName());
    ExportProperties(NULL, Output, Object->GetClass(), (uint8*)Object, 2, NULL, NULL, Object, PPF_SubobjectsOnly);
    Output.Logf(TEXT("<--- DONE!\r\n"));
    return Output;
}
void DumpObject(const TCHAR *Label, UObject* Object)
{
	UnMarkAllObjects(EObjectMark(OBJECTMARK_TagExp | OBJECTMARK_TagImp));

	FStringOutputDevice Archive;
	const FExportObjectInnerContext Context;
	UExporter::ExportToOutputDevice(&Context, Object, NULL, Archive, TEXT("copy"), 0, PPF_Copy | PPF_DebugDump, false);

	FString ExportedText;
	ExportedText = Archive;

	UE_LOG(LogExporter, Display, TEXT("%s"), Label);
	UE_LOG(LogExporter, Display, TEXT("%s"), *ExportedText);
}
void UnMarkAllObjects(EObjectMark Marks)
{
	if (Marks == OBJECTMARK_ALLMARKS)
	{
		MarkAnnotation.RemoveAllAnnotations();
	}
	else
	{
		const TMap<const UObjectBase *, FObjectMark>& Map = MarkAnnotation.GetAnnotationMap();
		for (TMap<const UObjectBase *, FObjectMark>::TConstIterator It(Map); It; ++It)
		{
			if(It.Value().Marks & Marks)
			{
				MarkAnnotation.AddAnnotation((UObject*)It.Key(),FObjectMark(EObjectMark(It.Value().Marks & ~Marks)));
			}
		}
	}
}
// Exports a set of nodes to text
void FEdGraphUtilities::ExportNodesToText(TSet<UObject*> NodesToExport, /*out*/ FString& ExportedText)
{
	// Clear the mark state for saving.
	UnMarkAllObjects(EObjectMark(OBJECTMARK_TagExp | OBJECTMARK_TagImp));

	FStringOutputDevice Archive;
	const FExportObjectInnerContext Context;

	// Export each of the selected nodes
	UObject* LastOuter = NULL;
	for (TSet<UObject*>::TConstIterator NodeIt(NodesToExport); NodeIt; ++NodeIt)
	{
		UObject* Node = *NodeIt;

		// The nodes should all be from the same scope
		UObject* ThisOuter = Node->GetOuter();
		check((LastOuter == ThisOuter) || (LastOuter == NULL));
		LastOuter = ThisOuter;

		UExporter::ExportToOutputDevice(&Context, Node, NULL, Archive, TEXT("copy"), 0, PPF_ExportsNotFullyQualified|PPF_Copy|PPF_Delimited, false, ThisOuter);
	}

	ExportedText = Archive;
}
void FComponentEditorUtils::CopyComponents(const TArray<UActorComponent*>& ComponentsToCopy)
{
	FStringOutputDevice Archive;
	const FExportObjectInnerContext Context;

	// Clear the mark state for saving.
	UnMarkAllObjects(EObjectMark(OBJECTMARK_TagExp | OBJECTMARK_TagImp));

	// Duplicate the selected component templates into temporary objects that we can modify
	TMap<FName, FName> ParentMap;
	TMap<FName, UActorComponent*> ObjectMap;
	for (UActorComponent* Component : ComponentsToCopy)
	{
		// Duplicate the component into a temporary object
		UObject* DuplicatedComponent = StaticDuplicateObject(Component, GetTransientPackage(), Component->GetFName(), RF_AllFlags & ~RF_ArchetypeObject);
		if (DuplicatedComponent)
		{
			// If the duplicated component is a scene component, wipe its attach parent (to prevent log warnings for referencing a private object in an external package)
			if (auto DuplicatedCompAsSceneComp = Cast<USceneComponent>(DuplicatedComponent))
			{
				DuplicatedCompAsSceneComp->AttachParent = nullptr;
			}

			// Find the closest parent component of the current component within the list of components to copy
			USceneComponent* ClosestSelectedParent = FindClosestParentInList(Component, ComponentsToCopy);
			if (ClosestSelectedParent)
			{
				// If the parent is included in the list, record it into the node->parent map
				ParentMap.Add(Component->GetFName(), ClosestSelectedParent->GetFName());
			}

			// Record the temporary object into the name->object map
			ObjectMap.Add(Component->GetFName(), CastChecked<UActorComponent>(DuplicatedComponent));
		}
	}

	// Export the component object(s) to text for copying
	for (auto ObjectIt = ObjectMap.CreateIterator(); ObjectIt; ++ObjectIt)
	{
		// Get the component object to be copied
		UActorComponent* ComponentToCopy = ObjectIt->Value;
		check(ComponentToCopy);

		// If this component object had a parent within the selected set
		if (ParentMap.Contains(ComponentToCopy->GetFName()))
		{
			// Get the name of the parent component
			FName ParentName = ParentMap[ComponentToCopy->GetFName()];
			if (ObjectMap.Contains(ParentName))
			{
				// Ensure that this component is a scene component
				USceneComponent* SceneComponent = Cast<USceneComponent>(ComponentToCopy);
				if (SceneComponent)
				{
					// Set the attach parent to the matching parent object in the temporary set. This allows us to preserve hierarchy in the copied set.
					SceneComponent->AttachParent = Cast<USceneComponent>(ObjectMap[ParentName]);
				}
			}
		}

		// Export the component object to the given string
		UExporter::ExportToOutputDevice(&Context, ComponentToCopy, NULL, Archive, TEXT("copy"), 0, PPF_ExportsNotFullyQualified | PPF_Copy | PPF_Delimited, false, ComponentToCopy->GetOuter());
	}

	// Copy text to clipboard
	FString ExportedText = Archive;
	FPlatformMisc::ClipboardCopy(*ExportedText);
}
/**
 * Adds marks to an object
 *
 * @param	Object	Object to add marks to
 * @param	Marks	Logical OR of OBJECTMARK_'s to apply 
 */
void MarkObject(const class UObjectBase* Object, EObjectMark Marks)
{
	MarkAnnotation.AddAnnotation(Object,FObjectMark(EObjectMark(MarkAnnotation.GetAnnotation(Object).Marks | Marks)));
}