/// <summary> /// initializes the tree model /// </summary> /// <param name="pModel">the bmsc to create a tree from</param> public void Initialize(BMSCModel pModel) { //find start item //TODO assumption: all messages are perfectly horizontally aligned //check how many possible start messages exist var maxvalue = pModel.ObjectList.Where(t => t is Message).Max(t => t.Locationy); var startmessages = pModel.ObjectList.Where(t => t is Message && t.Locationy == maxvalue); //checks //case more than 1 possible starts found if (startmessages.Count() > 1) { throw new ValidationFailedException(startmessages.First(), "More than one possible starting message found."); } //case no start found else if (!startmessages.Any()) { throw new ValidationFailedException(null, "Start message not found"); } //start first node with first message var firstmessage = (Message)startmessages.First(); var node = firstmessage.FromObject; StartNode = new BmscNode((Item)node, null, 1, firstmessage.Locationy, new HashSet <Container>()); }
/// <summary> /// traverses the tree recursively /// </summary> /// <param name="pRoot">the node to start from</param> /// <param name="pPath">the current path</param> /// <param name="pValidpaths">all valid paths. return value</param> private static void TraverseNodes(BmscNode pRoot, List <BmscNode> pPath, List <List <BmscNode> > pValidpaths) { pPath.Add(pRoot); //check if leaf if (!pRoot.NextNodes.Any()) { pValidpaths.Add(pPath); } //if no leaf, continue pRoot.NextNodes.ForEach(t => TraverseNodes(t, new List <BmscNode>(pPath), pValidpaths)); }
/// <summary> /// creates a n-tree based from a root node /// </summary> /// <param name="pRoot">the root node to start the tree from</param> private void ValidateAllNodesInValidPaths(BmscNode pRoot) { //http://stackoverflow.com/questions/5691926/traverse-every-unique-path-from-root-to-leaf-in-an-arbitrary-tree-structure //create list and traverse tree. only return paths with enditem as leaf List <List <BmscNode> > validpaths = new List <List <BmscNode> >(); TraverseNodes(pRoot, new List <BmscNode>(), validpaths); //validpths should now contain all paths where .Last() == StartEndItem with !IsStart //take all items from valid paths and check if they are equal with all items in model //for bmsc: only instances are relevant as placeableobjects are not part of the tree var allitems = StartNode.Current.ParentModel.ObjectList.Where(t => t is Instance); var validpathitems = validpaths.SelectMany(t => t).Select(t => t.Current).Distinct(); var missingitems = allitems.Where(t => !validpathitems.Contains(t)).ToList(); if (missingitems.Any()) { missingitems.ForEach(t => ValidationFailedEvent?.Invoke(new ValidationFailedMessage(4, "Item has no valid path.", t))); } //check if all messages are traversed with valid paths var allmessages = StartNode.Current.ParentModel.ObjectList.Where(t => t is Message); var allnextvalidpathmessagesmessages = validpaths.SelectMany(t => t).SelectMany(t => t.NextMessages).ToList(); //special case: specifically add found messages var allnextvalidpathincomingmessages = validpaths.SelectMany(t => t).Select(t => t.IncomingMessage); allnextvalidpathmessagesmessages.AddRange(allnextvalidpathincomingmessages); var validpathmessages = allnextvalidpathmessagesmessages.Distinct(); var missingmessages = allmessages.Where(t => !validpathmessages.Contains(t)).ToList(); if (missingmessages.Any()) { missingmessages.ForEach(t => ValidationFailedEvent?.Invoke(new ValidationFailedMessage(4, $"Message({t.Text}) has no valid path.", t))); } }