void UK2Node_CallArrayFunction::GetArrayPins(TArray< FArrayPropertyPinCombo >& OutArrayPinInfo ) const
{
	OutArrayPinInfo.Empty();

	UFunction* TargetFunction = GetTargetFunction();
	check(TargetFunction);
	FString ArrayPointerMetaData = TargetFunction->GetMetaData(FBlueprintMetadata::MD_ArrayParam);
	TArray<FString> ArrayPinComboNames;
	ArrayPointerMetaData.ParseIntoArray(ArrayPinComboNames, TEXT(","), true);

	for(auto Iter = ArrayPinComboNames.CreateConstIterator(); Iter; ++Iter)
	{
		TArray<FString> ArrayPinNames;
		Iter->ParseIntoArray(ArrayPinNames, TEXT("|"), true);

		FArrayPropertyPinCombo ArrayInfo;
		ArrayInfo.ArrayPin = FindPin(ArrayPinNames[0]);
		if(ArrayPinNames.Num() > 1)
		{
			ArrayInfo.ArrayPropPin = FindPin(ArrayPinNames[1]);
		}

		if(ArrayInfo.ArrayPin)
		{
			OutArrayPinInfo.Add(ArrayInfo);
		}
	}
}
bool UK2Node_CallArrayFunction::IsWildcardProperty(UFunction* InArrayFunction, const UProperty* InProperty)
{
	if(InArrayFunction && InProperty)
	{
		FString ArrayPointerMetaData = InArrayFunction->GetMetaData(FBlueprintMetadata::MD_ArrayParam);
		TArray<FString> ArrayPinComboNames;
		ArrayPointerMetaData.ParseIntoArray(ArrayPinComboNames, TEXT(","), true);

		for(auto Iter = ArrayPinComboNames.CreateConstIterator(); Iter; ++Iter)
		{
			TArray<FString> ArrayPinNames;
			Iter->ParseIntoArray(ArrayPinNames, TEXT("|"), true);

			if(ArrayPinNames[0] == InProperty->GetName())
			{
				return true;
			}
		}
	}
	return false;
}
/** Tests to see if a pin is schema compatible with a property */
bool FKismetCompilerUtilities::IsTypeCompatibleWithProperty(UEdGraphPin* SourcePin, UProperty* Property, FCompilerResultsLog& MessageLog, const UEdGraphSchema_K2* Schema, UClass* SelfClass)
{
	check(SourcePin != NULL);
	const FEdGraphPinType& Type = SourcePin->PinType;
	const EEdGraphPinDirection Direction = SourcePin->Direction; 

	const FString& PinCategory = Type.PinCategory;
	const FString& PinSubCategory = Type.PinSubCategory;
	const UObject* PinSubCategoryObject = Type.PinSubCategoryObject.Get();

	UProperty* TestProperty = NULL;
	const UFunction* OwningFunction = Cast<UFunction>(Property->GetOuter());
	if( Type.bIsArray )
	{
		// For arrays, the property we want to test against is the inner property
		if( UArrayProperty* ArrayProp = Cast<UArrayProperty>(Property) )
		{
			if(OwningFunction)
			{
				// Check for the magic ArrayParm property, which always matches array types
				FString ArrayPointerMetaData = OwningFunction->GetMetaData(TEXT("ArrayParm"));
				TArray<FString> ArrayPinComboNames;
				ArrayPointerMetaData.ParseIntoArray(&ArrayPinComboNames, TEXT(","), true);

				for(auto Iter = ArrayPinComboNames.CreateConstIterator(); Iter; ++Iter)
				{
					TArray<FString> ArrayPinNames;
					Iter->ParseIntoArray(&ArrayPinNames, TEXT("|"), true);

					if( ArrayPinNames[0] == SourcePin->PinName )
					{
						return true;
					}
				}
			}

			TestProperty = ArrayProp->Inner;
		}
		else
		{
			MessageLog.Error(*LOCTEXT("PinSpecifiedAsArray_Error", "Pin @@ is specified as an array, but does not have a valid array property.").ToString(), SourcePin);
			return false;
		}
	}
	else
	{
		// For scalars, we just take the passed in property
		TestProperty = Property;
	}

	// Check for the early out...if this is a type dependent parameter in an array function
	if ( (OwningFunction != NULL) && OwningFunction->HasMetaData(TEXT("ArrayParm")) )
	{
		// Check to see if this param is type dependent on an array parameter
		const FString DependentParams = OwningFunction->GetMetaData(TEXT("ArrayTypeDependentParams"));
		TArray<FString>	DependentParamNames;
		DependentParams.ParseIntoArray(&DependentParamNames, TEXT(","), true);
		if (DependentParamNames.Find(SourcePin->PinName) != INDEX_NONE)
		{
			//@todo:  This assumes that the wildcard coersion has done its job...I'd feel better if there was some easier way of accessing the target array type
			return true;
		}
	}

	int32 NumErrorsAtStart = MessageLog.NumErrors;

	// First check the type
	bool bTypeMismatch = false;
	bool bSubtypeMismatch = false;
	FString DesiredSubType(TEXT(""));

	if (PinCategory == Schema->PC_Boolean)
	{
		UBoolProperty* SpecificProperty = Cast<UBoolProperty>(TestProperty);
		bTypeMismatch = (SpecificProperty == NULL);
	}
	else if (PinCategory == Schema->PC_Byte)
	{
		UByteProperty* SpecificProperty = Cast<UByteProperty>(TestProperty);
		bTypeMismatch = (SpecificProperty == NULL);
	}
	else if (PinCategory == Schema->PC_Class)
	{
		const UClass* ClassType = (PinSubCategory == Schema->PSC_Self) ? SelfClass : Cast<const UClass>(PinSubCategoryObject);

		if (ClassType == NULL)
		{
			MessageLog.Error(*FString::Printf(*LOCTEXT("FindClassForPin_Error", "Failed to find class for pin @@").ToString()), SourcePin);
		}
		else
		{
			const UClass* MetaClass = NULL;
			if (auto ClassProperty = Cast<UClassProperty>(TestProperty))
			{
				MetaClass = ClassProperty->MetaClass;
			}
			else if (auto AssetClassProperty = Cast<UAssetClassProperty>(TestProperty))
			{
				MetaClass = AssetClassProperty->MetaClass;
			}

			if (MetaClass != NULL)
			{
				DesiredSubType = MetaClass->GetName();

				const UClass* OutputClass = (Direction == EGPD_Output) ? ClassType :  MetaClass;
				const UClass* InputClass = (Direction == EGPD_Output) ? MetaClass : ClassType;

				// It matches if it's an exact match or if the output class is more derived than the input class
				bTypeMismatch = bSubtypeMismatch = !((OutputClass == InputClass) || (OutputClass->IsChildOf(InputClass)));
			}
			else
			{
				bTypeMismatch = true;
			}
		}
	}
	else if (PinCategory == Schema->PC_Float)
	{
		UFloatProperty* SpecificProperty = Cast<UFloatProperty>(TestProperty);
		bTypeMismatch = (SpecificProperty == NULL);
	}
	else if (PinCategory == Schema->PC_Int)
	{
		UIntProperty* SpecificProperty = Cast<UIntProperty>(TestProperty);
		bTypeMismatch = (SpecificProperty == NULL);
	}
	else if (PinCategory == Schema->PC_Name)
	{
		UNameProperty* SpecificProperty = Cast<UNameProperty>(TestProperty);
		bTypeMismatch = (SpecificProperty == NULL);
	}
	else if (PinCategory == Schema->PC_Delegate)
	{
		const UFunction* SignatureFunction = Cast<const UFunction>(PinSubCategoryObject);
		const UDelegateProperty* PropertyDelegate = Cast<const UDelegateProperty>(TestProperty);
		bTypeMismatch = !(SignatureFunction 
			&& PropertyDelegate 
			&& PropertyDelegate->SignatureFunction 
			&& PropertyDelegate->SignatureFunction->IsSignatureCompatibleWith(SignatureFunction));
	}
	else if (PinCategory == Schema->PC_Object)
	{
		const UClass* ObjectType = (PinSubCategory == Schema->PSC_Self) ? SelfClass : Cast<const UClass>(PinSubCategoryObject);

		if (ObjectType == NULL)
		{
			MessageLog.Error(*FString::Printf(*LOCTEXT("FindClassForPin_Error", "Failed to find class for pin @@").ToString()), SourcePin);
		}
		else
		{
			UObjectPropertyBase* ObjProperty = Cast<UObjectPropertyBase>(TestProperty);
			if (ObjProperty != NULL && ObjProperty->PropertyClass)
			{
				DesiredSubType = ObjProperty->PropertyClass->GetName();

				const UClass* OutputClass = (Direction == EGPD_Output) ? ObjectType : ObjProperty->PropertyClass;
				const UClass* InputClass = (Direction == EGPD_Output) ? ObjProperty->PropertyClass : ObjectType;

				// It matches if it's an exact match or if the output class is more derived than the input class
				bTypeMismatch = bSubtypeMismatch = !((OutputClass == InputClass) || (OutputClass->IsChildOf(InputClass)));
			}
			else if (UInterfaceProperty* IntefaceProperty = Cast<UInterfaceProperty>(TestProperty))
			{
				UClass const* InterfaceClass = IntefaceProperty->InterfaceClass;
				if (InterfaceClass == NULL)
				{
					bTypeMismatch = true;
				}
				else 
				{
					DesiredSubType = InterfaceClass->GetName();
					bTypeMismatch = ObjectType->ImplementsInterface(InterfaceClass);
				}
			}
			else
			{
				bTypeMismatch = true;
			}
		}
	}
	else if (PinCategory == Schema->PC_String)
	{
		UStrProperty* SpecificProperty = Cast<UStrProperty>(TestProperty);
		bTypeMismatch = (SpecificProperty == NULL);
	}
	else if (PinCategory == Schema->PC_Text)
	{
		UTextProperty* SpecificProperty = Cast<UTextProperty>(TestProperty);
		bTypeMismatch = (SpecificProperty == NULL);
	}
	else if (PinCategory == Schema->PC_Struct)
	{
		const UScriptStruct* StructType = Cast<const UScriptStruct>(PinSubCategoryObject);
		if (StructType == NULL)
		{
			MessageLog.Error(*FString::Printf(*LOCTEXT("FindStructForPin_Error", "Failed to find struct for pin @@").ToString()), SourcePin);
		}
		else
		{
			UStructProperty* StructProperty = Cast<UStructProperty>(TestProperty);
			if (StructProperty != NULL)
			{
				DesiredSubType = StructProperty->Struct->GetName();
				bSubtypeMismatch = bTypeMismatch = (StructType != StructProperty->Struct);
			}
			else
			{
				bTypeMismatch = true;
			}
		}
	}
	else
	{
		MessageLog.Error(*FString::Printf(*LOCTEXT("UnsupportedTypeForPin", "Unsupported type (%s) on @@").ToString(), *UEdGraphSchema_K2::TypeToString(Type)), SourcePin);
	}

	if (bTypeMismatch)
	{
		MessageLog.Error(*FString::Printf(*LOCTEXT("TypeDoesNotMatchPropertyOfType_Error", "@@ of type %s doesn't match the property %s of type %s").ToString(),
			*UEdGraphSchema_K2::TypeToString(Type),
			*Property->GetName(),
			*UEdGraphSchema_K2::TypeToString(Property)),
			SourcePin);
	}

	// Now check the direction
	if (Property->HasAnyPropertyFlags(CPF_Parm))
	{
		// Parameters are directional
		const bool bOutParam = (Property->HasAnyPropertyFlags(CPF_OutParm | CPF_ReturnParm) && !(Property->HasAnyPropertyFlags(CPF_ReferenceParm)));

		if ( ((SourcePin->Direction == EGPD_Input) && bOutParam) || ((SourcePin->Direction == EGPD_Output) && !bOutParam))
		{
			MessageLog.Error(*FString::Printf(*LOCTEXT("DirectionMismatchParameter_Error", "The direction of @@ doesn't match the direction of parameter %s").ToString(), *Property->GetName()), SourcePin);
		}

 		if (Property->HasAnyPropertyFlags(CPF_ReferenceParm))
 		{
			TArray<FString> AutoEmittedTerms;
			Schema->GetAutoEmitTermParameters(OwningFunction, AutoEmittedTerms);
			const bool bIsAutoEmittedTerm = AutoEmittedTerms.Contains(SourcePin->PinName);

			// Make sure reference parameters are linked, except for FTransforms, which have a special node handler that adds an internal constant term
 			if (!bIsAutoEmittedTerm
				&& (SourcePin->LinkedTo.Num() == 0)
				&& (!SourcePin->PinType.PinSubCategoryObject.IsValid() || SourcePin->PinType.PinSubCategoryObject.Get()->GetName() != TEXT("Transform")) )
 			{
 				MessageLog.Error(*LOCTEXT("PassLiteral_Error", "Cannot pass a literal to @@.  Connect a variable to it instead.").ToString(), SourcePin);
 			}
 		}
	}

	return NumErrorsAtStart == MessageLog.NumErrors;
}