/// <summary>
        /// Recursively finds the targets of the specified path.
        /// </summary>
        private void GetTargets(Node start, IList <RelativePathElement> path, int index, BrowsePathResult result)
        {
            // check for invalid parameters.
            if (index >= path.Count)
            {
                return;
            }

            // look for list of references for node.
            ReferenceDescriptionCollection references = start.Handle as ReferenceDescriptionCollection;

            if (references == null || references.Count == 0)
            {
                return;
            }

            RelativePathElement element = path[index];

            // each list of references.
            for (int ii = 0; ii < references.Count; ii++)
            {
                ReferenceDescription reference = references[ii];

                // check for a reference match.
                if (element.IsInverse == reference.IsForward)
                {
                    continue;
                }

                if (element.ReferenceTypeId != reference.ReferenceTypeId)
                {
                    if (!element.IncludeSubtypes)
                    {
                        continue;
                    }

                    if (!Session.TypeTree.IsTypeOf(reference.ReferenceTypeId, element.ReferenceTypeId))
                    {
                        continue;
                    }
                }

                // check for a browse name match.
                if (element.TargetName != reference.BrowseName)
                {
                    continue;
                }

                // check for end of list.
                if (index == path.Count - 1)
                {
                    BrowsePathTarget item = new BrowsePathTarget();
                    item.TargetId           = reference.NodeId;
                    item.RemainingPathIndex = UInt32.MaxValue;
                    result.Targets.Add(item);
                    continue;
                }

                // check for external reference.
                if (reference.NodeId.IsAbsolute)
                {
                    BrowsePathTarget item = new BrowsePathTarget();
                    item.TargetId           = reference.NodeId;
                    item.RemainingPathIndex = (uint)index + 1;
                    result.Targets.Add(item);
                    continue;
                }

                // check for targets.
                Node target = null;

                if (!AvailableNodes.TryGetValue((NodeId)reference.NodeId, out target))
                {
                    BrowsePathTarget item = new BrowsePathTarget();
                    item.TargetId           = reference.NodeId;
                    item.RemainingPathIndex = (uint)index + 1;
                    result.Targets.Add(item);
                    continue;
                }

                // recursively follow targets.
                GetTargets(target, path, index + 1, result);
            }
        }
        /// <summary>
        /// Adds a single hop path for all references for the node.
        /// </summary>
        private void AddMultiHopPaths(
            Node node,
            Node baseNode,
            IList <RelativePathElement> basePath,
            BrowsePathCollection pathsToTranslate,
            int hops)
        {
            ReferenceDescriptionCollection references = node.Handle as ReferenceDescriptionCollection;

            if (references == null)
            {
                return;
            }

            for (int ii = 0; ii < references.Count; ii++)
            {
                ReferenceDescription reference = references[ii];

                BrowsePath browsePath = new BrowsePath();

                browsePath.StartingNode = baseNode.NodeId;
                browsePath.Handle       = baseNode;

                if (basePath != null)
                {
                    browsePath.RelativePath.Elements.AddRange(basePath);
                }

                RelativePathElement element = new RelativePathElement();

                element.ReferenceTypeId = ReferenceTypeIds.NonHierarchicalReferences;
                element.IsInverse       = !reference.IsForward;
                element.IncludeSubtypes = true;
                element.TargetName      = reference.BrowseName;

                browsePath.RelativePath.Elements.Add(element);
                pathsToTranslate.Add(browsePath);

                // only follow forward heiarchical
                if (!Session.TypeTree.IsTypeOf(reference.ReferenceTypeId, ReferenceTypeIds.HierarchicalReferences))
                {
                    continue;
                }

                element.ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences;

                // can't do anything with absolute or inverse references.
                if (!reference.IsForward || reference.NodeId.IsAbsolute)
                {
                    continue;
                }

                // look up target
                if (browsePath.RelativePath.Elements.Count < hops)
                {
                    Node target = null;

                    if (!AvailableNodes.TryGetValue((NodeId)reference.NodeId, out target))
                    {
                        continue;
                    }

                    AddMultiHopPaths(target, baseNode, browsePath.RelativePath.Elements, pathsToTranslate, hops);
                }
            }
        }