bool FStructureEditorUtils::CanHaveAMemberVariableOfType(const UBlueprintGeneratedStruct* Struct, const FEdGraphPinType& VarType, FString* OutMsg)
{
	const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
	if ((VarType.PinCategory == K2Schema->PC_Struct) && Struct)
	{
		if (const UScriptStruct* SubCategoryStruct = Cast<const UScriptStruct>(VarType.PinSubCategoryObject.Get()))
		{
			const EStructureError Result = IsStructureValid(SubCategoryStruct, Struct, OutMsg);
			if (EStructureError::Ok != Result)
			{
				return false;
			}
		}
		else
		{
			if (OutMsg)
			{
				*OutMsg = LOCTEXT("StructureIncorrectStructType", "Icorrect struct type in a structure member variable.").ToString();
			}
			return false;
		}
	}
	else if ((VarType.PinCategory == K2Schema->PC_Exec) || (VarType.PinCategory == K2Schema->PC_Meta) || (VarType.PinCategory == K2Schema->PC_Wildcard))
	{
		if (OutMsg)
		{
			*OutMsg = LOCTEXT("StructureIncorrectTypeCategory", "Icorrect type for a structure member variable.").ToString();
		}
		return false;
	}
	return true;
}
bool FStructureEditorUtils::CanHaveAMemberVariableOfType(const UUserDefinedStruct* Struct, const FEdGraphPinType& VarType, FString* OutMsg)
{
    const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
    if ((VarType.PinCategory == K2Schema->PC_Struct) && Struct)
    {
        if (const UScriptStruct* SubCategoryStruct = Cast<const UScriptStruct>(VarType.PinSubCategoryObject.Get()))
        {
            const EStructureError Result = IsStructureValid(SubCategoryStruct, Struct, OutMsg);
            if (EStructureError::Ok != Result)
            {
                return false;
            }
        }
        else
        {
            if (OutMsg)
            {
                *OutMsg = LOCTEXT("StructureIncorrectStructType", "Incorrect struct type in a structure member variable.").ToString();
            }
            return false;
        }
    }
    else if ((VarType.PinCategory == K2Schema->PC_Exec)
             || (VarType.PinCategory == K2Schema->PC_Wildcard)
             || (VarType.PinCategory == K2Schema->PC_MCDelegate)
             || (VarType.PinCategory == K2Schema->PC_Delegate))
    {
        if (OutMsg)
        {
            *OutMsg = LOCTEXT("StructureIncorrectTypeCategory", "Incorrect type for a structure member variable.").ToString();
        }
        return false;
    }
    else
    {
        const auto PinSubCategoryClass = Cast<const UClass>(VarType.PinSubCategoryObject.Get());
        if (PinSubCategoryClass && PinSubCategoryClass->IsChildOf(UBlueprint::StaticClass()))
        {
            if (OutMsg)
            {
                *OutMsg = LOCTEXT("StructureUseBlueprintReferences", "Struct cannot use any blueprint references").ToString();
            }
            return false;
        }
    }
    return 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;
}