Пример #1
0
        protected void MatchWithContextsReferencingSubContext(List <ContextNode> matches)
        {
            // For each match, see if there are other super-contexts that reference this same matching context.
            // If so, these should be added to the list of matches.
            // TODO: Would this be easier if we change ContextNode.Parent from a singleton to a List<ContextNode> ?
            // Clone, otherwise we may end up modifying the list of known matches.
            foreach (ContextNode match in matches.ToList())
            {
                List <Guid> matchParentPath = match.GetParentInstancePath();

                // We only want root contexts.
                foreach (var nodes in flatView.Values.Where(n => n.Last().Parent.InstanceId == Guid.Empty))
                {
                    ContextNode lastNode = nodes.Last();

                    foreach (var childNodeIdPath in lastNode.ChildInstancePaths())
                    {
                        // We attempt to find a node where any sub-context ID equals the match last ID, as this gives us at least
                        // one context node in which we know that there is another reference.
                        // This, incidentally, is the common context type that we're searching on.
                        if (childNodeIdPath.Any(id => id == match.InstanceId))
                        {
                            // The root instance ID for this match should be different than any existing match.
                            if (!matches.Any(m => m.GetParentInstancePath().First() == nodes.First().InstanceId))
                            {
                                // Add this other context, that is referencing the context we matched on.
                                matches.Add(lastNode);
                            }
                        }
                    }
                }
            }
        }
Пример #2
0
        public bool TryGetContextNode(Field field, Guid rootId, int recordNumber, out ContextNode node, out List <Guid> instanceIdPath)
        {
            instanceIdPath = new List <Guid>();
            instanceIdPath.Add(rootId);
            ContextNode dictNode = tree.Children.Single(c => c.InstanceId == rootId);

            // Traverse the dictionary up to the node containing the ContextValue.
            // We traverse by type, building the instance ID list as we go.
            for (int i = 1; i < (field.ContextPath.Count - 1) && dictNode != null; i++)
            {
                dictNode = dictNode.Children.SingleOrDefault(c => c.Type == field.ContextPath[i].Type);

                if (dictNode != null)
                {
                    instanceIdPath.Add(dictNode.InstanceId);
                }
            }

            if (dictNode != null)
            {
                // Acquire the ContextValue based on field type and record number.
                dictNode = dictNode.Children.SingleOrDefault(c => c.Type == field.ContextPath[field.ContextPath.Count - 1].Type && c.ContextValue.RecordNumber == recordNumber);

                if (dictNode != null)
                {
                    instanceIdPath.Add(dictNode.InstanceId);
                }
            }

            node = dictNode;

            return(node != null);
        }
Пример #3
0
        public Type GetRootType(Guid rootId)
        {
            ContextNode dictNode = tree.Children.Single(c => c.InstanceId == rootId);
            Type        rootType = dictNode.Type;

            return(rootType);
        }
Пример #4
0
        public IReadOnlyList <ContextValue> GetContextValues(ContextNode node)
        {
            List <ContextValue> contextValues = new List <ContextValue>();

            GetContextValues(contextValues, node);

            return(contextValues.AsReadOnly());
        }
Пример #5
0
        public string Render(ContextNode contextNode, ContextValueDictionary cvd, int recNum, IReadOnlyList <ContextValue> contextValues)
        {
            StringBuilder sb = new StringBuilder();

            foreach (var component in components)
            {
                sb.Append(component.Render(contextNode, cvd, recNum, contextValues));
            }

            return(sb.ToString());
        }
Пример #6
0
        protected void GetContextValues(List <ContextValue> contextValues, ContextNode node)
        {
            foreach (var child in node.Children)
            {
                GetContextValues(contextValues, child);

                if (child.ContextValue != null)
                {
                    contextValues.Add(child.ContextValue);
                }
            }
        }
Пример #7
0
        public override string Render(ContextNode contextNode, ContextValueDictionary cvd, int recNum, IReadOnlyList <ContextValue> contextValues)
        {
            var    contextValue = contextValues.SingleOrDefault(cv => cv.Type == ValueEntity && cv.RecordNumber == recNum);
            string ret          = String.Empty;

            if (contextValue != null)
            {
                ret = contextValue.Value;
            }

            return(ret);
        }
Пример #8
0
        /// <summary>
        /// The parent instance chain from this child, including this child's ID.
        /// </summary>
        public List <Guid> GetParentInstancePath()
        {
            List <Guid> path = new List <Guid>();

            path.Add(InstanceId);
            ContextNode parentNode = Parent;

            while (parentNode != null)
            {
                path.Insert(0, parentNode.InstanceId);
                parentNode = parentNode.Parent;
            }

            return(path.Skip(1).ToList());            // Exclude the Guid.Empty root.
        }
Пример #9
0
        protected ContextNode CreateNode(int i, Guid id, ContextValue cv, ContextNode node, Type type)
        {
            if (i == cv.TypePath.Count - 1)
            {
                // At this point, node.Children[].Type && node.Children[].ContextValue.RecordNumber must be unique!
                Assert.That <ContextValueDictionaryException>(!node.Children.Any(c => c.Type == type && c.ContextValue.RecordNumber == cv.RecordNumber), "ContextValue type and record number must be unique to parent context.");
            }

            ContextNode childNode = new ContextNode(id, type);

            node.AddChild(childNode);

            // Since we're creating a node, add it to the flat tree view.
            if (!flatView.TryGetValue(type, out List <ContextNode> nodes))
            {
                flatView[type] = new List <ContextNode>();
            }

            flatView[type].Add(childNode);

            return(childNode);
        }
Пример #10
0
        public void Load()
        {
            // https://stackoverflow.com/questions/7397207/json-net-error-self-referencing-loop-detected-for-type
            var settings = new JsonSerializerSettings();

            settings.ReferenceLoopHandling      = ReferenceLoopHandling.Serialize;
            settings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
            settings.TypeNameHandling           = TypeNameHandling.Auto;
            settings.ConstructorHandling        = ConstructorHandling.AllowNonPublicDefaultConstructor;
            settings.ObjectCreationHandling     = ObjectCreationHandling.Auto;

            if (File.Exists("tree.cvd"))
            {
                string jsonTree = File.ReadAllText("tree.cvd");
                tree = JsonConvert.DeserializeObject <ContextNode>(jsonTree, settings);
            }

            if (File.Exists("flatView.cvd"))
            {
                string jsonFlatView = File.ReadAllText("flatView.cvd");
                flatView = JsonConvert.DeserializeObject <Dictionary <Type, List <ContextNode> > >(jsonFlatView, settings);
            }
        }
Пример #11
0
        /// <summary>
        /// Give a child node, returns the full path, starting from the topmost node, of the node hierarchy.
        /// </summary>
        public ContextNodePath GetPath(ContextNode node)
        {
            // A LINQ way of traversing the tree to its root.  Seems more complicated than the approach here.
            // https://stackoverflow.com/questions/34741456/linq-traverse-upwards-and-retrieve-parent-child-relationship
            // Also an interesting read:
            // https://www.codeproject.com/Articles/62397/LINQ-to-Tree-A-Generic-Technique-for-Querying-Tree
            Type rootType = node.Type;
            Guid rootGuid = node.InstanceId;
            List <NodeTypeInstance> path = new List <NodeTypeInstance>()
            {
                new NodeTypeInstance()
                {
                    Type = node.Type, InstanceId = node.InstanceId
                }
            };

            var parent = node.Parent;

            while (parent != null && parent.InstanceId != Guid.Empty)
            {
                rootType = parent.Type;
                rootGuid = parent.InstanceId;
                path.Insert(0, new NodeTypeInstance()
                {
                    Type = parent.Type, InstanceId = parent.InstanceId
                });
                parent = parent.Parent;
            }

            var match = new ContextNodePath()
            {
                Type = rootType, Name = rootType.Name, Path = path
            };

            return(match);
        }
Пример #12
0
        public void AddOrUpdate(ContextValue cv)
        {
            // We have to process this synchronously!
            // If async, we might get simultaneous requests (particularly from the browser's async PUT calls) to add a value.
            // While we're constructing the dictionary entry for one context path, another request might come in before we've
            // created all the nodes for the first call.
            lock (this)
            {
                // Walk the instance/path, creating new nodes in the context tree as required.

                Assert.That(cv.TypePath.Count == cv.InstancePath.Count, "type path and instance path should have the same number of entries.");
                ContextNode node = tree;

                for (int i = 0; i < cv.TypePath.Count; i++)
                {
                    // Walk the tree.
                    var(id, type) = (cv.InstancePath[i], cv.TypePath[i]);

                    if (node.Children.TryGetSingle(c => c.InstanceId == id, out ContextNode childNode))
                    {
                        node = childNode;
                    }
                    else
                    {
                        // Are we referencing an existing sub-context?
                        if (flatView.TryGetValue(type, out List <ContextNode> nodes))
                        {
                            // The instance path of the node must match all the remaining instance paths in the context
                            // we're adding/updating!
                            bool foundExistingSubContext = false;

                            foreach (var fvnode in nodes)
                            {
                                foreach (var fvnodepath in fvnode.ChildInstancePaths())
                                {
                                    if (cv.InstancePath.Skip(i).SequenceEqual(fvnodepath))
                                    {
                                        // This node get's a child referencing the existing sub-context node.
                                        node.AddChild(fvnode);
                                        node = fvnode;
                                        foundExistingSubContext = true;
                                        break;
                                    }
                                }

                                if (foundExistingSubContext)
                                {
                                    break;
                                }
                            }

                            if (!foundExistingSubContext)
                            {
                                node = CreateNode(i, id, cv, node, type);
                            }
                        }
                        else
                        {
                            node = CreateNode(i, id, cv, node, type);
                        }
                    }
                }

                // The last entry in the tree gets the actual context value.  We've either added this node to the tree
                // or updating an existing node.
                node.ContextValue = cv;
            }
        }
Пример #13
0
 public void AddChild(ContextNode node)
 {
     children.Add(node);
     node.Parent = this;
 }
Пример #14
0
 public override string Render(ContextNode contextNode, ContextValueDictionary cvd, int recNum, IReadOnlyList <ContextValue> contextValues)
 {
     return(Text);
 }
Пример #15
0
 public abstract string Render(ContextNode contextNode, ContextValueDictionary cvd, int recNum, IReadOnlyList <ContextValue> contextValues);