//TODO: Move to blueprint utils
void FStructureEditorUtils::RemoveInvalidStructureMemberVariableFromBlueprint(UBlueprint* Blueprint)
{
    if (Blueprint)
    {
        const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
        const UScriptStruct* FallbackStruct = GetFallbackStruct();

        FString DislpayList;
        TArray<FName> ZombieMemberNames;
        for (int32 VarIndex = 0; VarIndex < Blueprint->NewVariables.Num(); ++VarIndex)
        {
            const FBPVariableDescription& Var = Blueprint->NewVariables[VarIndex];
            if (Var.VarType.PinCategory == K2Schema->PC_Struct)
            {
                const UScriptStruct* ScriptStruct = Cast<const UScriptStruct>(Var.VarType.PinSubCategoryObject.Get());
                const bool bInvalidStruct = (NULL == ScriptStruct) || (FallbackStruct == ScriptStruct);
                if (bInvalidStruct)
                {
                    DislpayList += Var.FriendlyName.IsEmpty() ? Var.VarName.ToString() : Var.FriendlyName;
                    DislpayList += TEXT("\n");
                    ZombieMemberNames.Add(Var.VarName);
                }
            }
        }

        if (ZombieMemberNames.Num())
        {
            auto Response = FMessageDialog::Open(
                                EAppMsgType::OkCancel,
                                FText::Format(
                                    LOCTEXT("RemoveInvalidStructureMemberVariable_Msg", "The following member variables in blueprint '{0}' have invalid type. Would you like to remove them? \n\n{1}"),
                                    FText::FromString(Blueprint->GetFullName()),
                                    FText::FromString(DislpayList)
                                ));
            check((EAppReturnType::Ok == Response) || (EAppReturnType::Cancel == Response));

            if (EAppReturnType::Ok == Response)
            {
                Blueprint->Modify();

                for (auto NameIter = ZombieMemberNames.CreateConstIterator(); NameIter; ++NameIter)
                {
                    const FName Name = *NameIter;
                    Blueprint->NewVariables.RemoveAll(FFindByNameHelper<FBPVariableDescription>(Name)); //TODO: Add RemoveFirst to TArray
                    FBlueprintEditorUtils::RemoveVariableNodes(Blueprint, Name);
                }
            }
        }
    }
}
void UStructProperty::LinkInternal(FArchive& Ar)
{
	// We potentially have to preload the property itself here, if we were the inner of an array property
	if(HasAnyFlags(RF_NeedLoad))
	{
		GetLinker()->Preload(this);
	}

#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	if (Struct == NULL)
	{
		UE_LOG(LogProperty, Error, TEXT("Struct type unknown for property '%s'; perhaps the USTRUCT() was renamed or deleted?"), *GetFullName());
	}
#endif

	// Preload is required here in order to load the value of Struct->PropertiesSize
	Ar.Preload(Struct);
	if ( !ensure(Struct) )
	{
		Struct = GetFallbackStruct();
	}
	PreloadInnerStructMembers(this);
	
	ElementSize = Align(Struct->PropertiesSize, Struct->GetMinAlignment());
	if (Struct->StructFlags & STRUCT_IsPlainOldData) // if there is nothing to construct or the struct is known to be memcpy-able, then allow memcpy
	{
		PropertyFlags |= CPF_IsPlainOldData;
	}
	if (Struct->StructFlags & STRUCT_NoDestructor)
	{
		PropertyFlags |= CPF_NoDestructor;
	}
	if (Struct->StructFlags & STRUCT_ZeroConstructor)
	{
		PropertyFlags |= CPF_ZeroConstructor;
	}
}
void UStructProperty::Serialize( FArchive& Ar )
{
	Super::Serialize( Ar );

	static UScriptStruct* FallbackStruct = GetFallbackStruct();
	
	if (Ar.IsPersistent() && Ar.GetLinker() && Ar.IsLoading() && !Struct)
	{
		// It's necessary to solve circular dependency problems, when serializing the Struct causes linking of the Property.
		Struct = FallbackStruct;
	}

	Ar << Struct;
#if WITH_EDITOR
	if (Ar.IsPersistent() && Ar.GetLinker())
	{
		if (!Struct && Ar.IsLoading())
		{
			UE_LOG(LogProperty, Error, TEXT("UStructProperty::Serialize Loading: Property '%s'. Unknown structure."), *GetFullName());
			Struct = FallbackStruct;
		}
		else if ((FallbackStruct == Struct) && Ar.IsSaving())
		{
			UE_LOG(LogProperty, Error, TEXT("UStructProperty::Serialize Saving: Property '%s'. FallbackStruct structure."), *GetFullName());
		}
	}
#endif // WITH_EDITOR
	if (Struct)
	{
		PreloadInnerStructMembers(this);
	}
	else
	{
		ensure(true);
	}
}
FStructureEditorUtils::EStructureError FStructureEditorUtils::IsStructureValid(const UScriptStruct* Struct, const UStruct* RecursionParent, FString* OutMsg)
{
    check(Struct);
    if (Struct == RecursionParent)
    {
        if (OutMsg)
        {
            *OutMsg = FString::Printf(*LOCTEXT("StructureRecursion", "Recursion: Struct cannot have itself as a member variable. Struct '%s', recursive parent '%s'").ToString(),
                                      *Struct->GetFullName(), *RecursionParent->GetFullName());
        }
        return EStructureError::Recursion;
    }

    const UScriptStruct* FallbackStruct = GetFallbackStruct();
    if (Struct == FallbackStruct)
    {
        if (OutMsg)
        {
            *OutMsg = LOCTEXT("StructureUnknown", "Struct unknown (deleted?)").ToString();
        }
        return EStructureError::FallbackStruct;
    }

    if (Struct->GetStructureSize() <= 0)
    {
        if (OutMsg)
        {
            *OutMsg = FString::Printf(*LOCTEXT("StructureSizeIsZero", "Struct '%s' is empty").ToString(), *Struct->GetFullName());
        }
        return EStructureError::EmptyStructure;
    }

    if (const UUserDefinedStruct* UDStruct = Cast<const UUserDefinedStruct>(Struct))
    {
        if (UDStruct->Status != EUserDefinedStructureStatus::UDSS_UpToDate)
        {
            if (OutMsg)
            {
                *OutMsg = FString::Printf(*LOCTEXT("StructureNotCompiled", "Struct '%s' is not compiled").ToString(), *Struct->GetFullName());
            }
            return EStructureError::NotCompiled;
        }

        for (const UProperty* P = Struct->PropertyLink; P; P = P->PropertyLinkNext)
        {
            const UStructProperty* StructProp = Cast<const UStructProperty>(P);
            if (NULL == StructProp)
            {
                if (const UArrayProperty* ArrayProp = Cast<const UArrayProperty>(P))
                {
                    StructProp = Cast<const UStructProperty>(ArrayProp->Inner);
                }
            }

            if (StructProp)
            {
                if ((NULL == StructProp->Struct) || (FallbackStruct == StructProp->Struct))
                {
                    if (OutMsg)
                    {
                        *OutMsg = FString::Printf(*LOCTEXT("StructureUnknownProperty", "Struct unknown (deleted?). Parent '%s' Property: '%s'").ToString(),
                                                  *Struct->GetFullName(), *StructProp->GetName());
                    }
                    return EStructureError::FallbackStruct;
                }

                FString OutMsgInner;
                const EStructureError Result = IsStructureValid(
                                                   StructProp->Struct,
                                                   RecursionParent ? RecursionParent : Struct,
                                                   OutMsg ? &OutMsgInner : NULL);
                if (EStructureError::Ok != Result)
                {
                    if (OutMsg)
                    {
                        *OutMsg = FString::Printf(*LOCTEXT("StructurePropertyErrorTemplate", "Struct '%s' Property '%s' Error ( %s )").ToString(),
                                                  *Struct->GetFullName(), *StructProp->GetName(), *OutMsgInner);
                    }
                    return Result;
                }
            }
        }
    }

    return EStructureError::Ok;
}
FStructureEditorUtils::EStructureError FStructureEditorUtils::IsStructureValid(const UScriptStruct* Struct, const UStruct* RecursionParent, FString* OutMsg)
{
	check(Struct);
	if (Struct == RecursionParent)
	{
		if (OutMsg)
		{
			 *OutMsg = FString::Printf(*LOCTEXT("StructureRecursion", "Recursion: Struct cannot have itself as a member variable. Struct '%s', recursive parent '%s'").ToString(), 
				 *Struct->GetFullName(), *RecursionParent->GetFullName());
		}
		return EStructureError::Recursion;
	}

	const UScriptStruct* FallbackStruct = GetFallbackStruct();
	if (Struct == FallbackStruct)
	{
		if (OutMsg)
		{
			*OutMsg = LOCTEXT("StructureUnknown", "Struct unknown (deleted?)").ToString();
		}
		return EStructureError::FallbackStruct;
	}

	if (const UBlueprintGeneratedStruct* BPGStruct = Cast<const UBlueprintGeneratedStruct>(Struct))
	{
		static const FName BlueprintTypeName(TEXT("BlueprintType"));
		if (!Struct->GetBoolMetaData(BlueprintTypeName))
		{
			if (OutMsg)
			{
				*OutMsg = FString::Printf(*LOCTEXT("StructureNotBlueprintType", "Struct '%s' is not BlueprintType").ToString(), *Struct->GetFullName());
			}
			return EStructureError::NotBlueprintType;
		}

		if (BPGStruct->Status != EBlueprintStructureStatus::BSS_UpToDate)
		{
			if (OutMsg)
			{
				*OutMsg = FString::Printf(*LOCTEXT("StructureNotCompiled", "Struct '%s' is not compiled").ToString(), *Struct->GetFullName());
			}
			return EStructureError::NotCompiled;
		}

		for (const UProperty * P = Struct->PropertyLink; P; P = P->PropertyLinkNext)
		{
			const UStructProperty* StructProp = Cast<const UStructProperty>(P);
			if (NULL == StructProp)
			{
				if (const UArrayProperty* ArrayProp = Cast<const UArrayProperty>(P))
				{
					StructProp = Cast<const UStructProperty>(ArrayProp->Inner);
				}
			}

			if (StructProp)
			{
				if ((NULL == StructProp->Struct) || (FallbackStruct == StructProp->Struct))
				{
					if (OutMsg)
					{
						*OutMsg = FString::Printf(*LOCTEXT("StructureUnknownProperty", "Struct unknown (deleted?). Parent '%s' Property: '%s").ToString(), 
							*Struct->GetFullName(), *StructProp->GetName());
					}
					return EStructureError::FallbackStruct;
				}

				const EStructureError Result = IsStructureValid(StructProp->Struct, RecursionParent ? RecursionParent : Struct, OutMsg);
				if (EStructureError::Ok != Result) 
				{
					return Result;
				}
			}
		}
	}

	return EStructureError::Ok;
}