private bool RelatedTo(FilterContext context, IFilterTarget target, ContentFilterElement element, NodeId intermediateNodeId)
{
// RelatedTo only supported in advanced filter targets.
IAdvancedFilterTarget advancedTarget = target as IAdvancedFilterTarget;
if (advancedTarget == null)
{
return false;
}
FilterOperand[] operands = GetOperands(element, 6);
// get the type of the source.
NodeId sourceTypeId = GetValue(context, operands[0], target) as NodeId;
if (sourceTypeId == null)
{
return false;
}
// get the type of reference to follow.
NodeId referenceTypeId = GetValue(context, operands[2], target) as NodeId;
if (referenceTypeId == null)
{
return false;
}
// get the number of hops
int? hops = 1;
object hopsValue = GetValue(context, operands[3], target);
if (hopsValue != null)
{
hops = Cast(hopsValue, BuiltInType.Int32) as int?;
if (hops == null)
{
hops = 1;
}
}
// get whether to include type definition subtypes.
bool? includeTypeDefinitionSubtypes = true;
object includeValue = GetValue(context, operands[4], target);
if (includeValue != null)
{
includeTypeDefinitionSubtypes = Cast(includeValue, BuiltInType.Boolean) as bool?;
if (includeTypeDefinitionSubtypes == null)
{
includeTypeDefinitionSubtypes = true;
}
}
// get whether to include reference type subtypes.
bool? includeReferenceTypeSubtypes = true;
includeValue = GetValue(context, operands[5], target);
if (includeValue != null)
{
includeReferenceTypeSubtypes = Cast(includeValue, BuiltInType.Boolean) as bool?;
if (includeReferenceTypeSubtypes == null)
{
includeReferenceTypeSubtypes = true;
}
}
NodeId targetTypeId = null;
// check if elements are chained.
ElementOperand chainedOperand = operands[1] as ElementOperand;
if (chainedOperand != null)
{
if (chainedOperand.Index < 0 || chainedOperand.Index >= Elements.Count)
{
return false;
}
ContentFilterElement chainedElement = Elements[(int)chainedOperand.Index];
// get the target type from the first operand of the chained element.
if (chainedElement.FilterOperator == FilterOperator.RelatedTo)
{
FilterOperand nestedType = ExtensionObject.ToEncodeable(chainedElement.FilterOperands[0]) as FilterOperand;
targetTypeId = GetValue(context, nestedType, target) as NodeId;
if (targetTypeId == null)
{
return false;
}
// find the nodes that meet the criteria in the first link of the chain.
IList<NodeId> nodeIds = advancedTarget.GetRelatedNodes(
context,
intermediateNodeId,
sourceTypeId,
targetTypeId,
referenceTypeId,
hops.Value,
includeTypeDefinitionSubtypes.Value,
includeReferenceTypeSubtypes.Value);
if (nodeIds == null || nodeIds.Count == 0)
{
return false;
}
// recursively follow the chain.
for (int ii = 0; ii < nodeIds.Count; ii++)
{
// one match is all that is required.
if (RelatedTo(context, target, chainedElement, nodeIds[ii]))
{
return true;
}
}
// no matches.
return false;
}
}
// get the type of the target.
if (targetTypeId == null)
{
targetTypeId = GetValue(context, operands[1], target) as NodeId;
if (targetTypeId == null)
{
return false;
}
}
// check the target.
try
{
bool relatedTo = advancedTarget.IsRelatedTo(
context,
intermediateNodeId,
sourceTypeId,
targetTypeId,
referenceTypeId,
hops.Value,
includeTypeDefinitionSubtypes.Value,
includeReferenceTypeSubtypes.Value);
return relatedTo;
}
catch
{
return false;
}
}
#endregion