public async Task <string> GetPreviousNode(string formKey, string currentNodeId) { var form = await _formRepository.GetForm(formKey); var currentNode = form.Nodes.FindByKey(new Key(currentNodeId)); var taskFormNode = currentNode.AssertType <PhysicalTaskFormNode>(); var taskRouterNode = form.Nodes.FindByKey(Key.ForDecisionTaskRouter(taskFormNode.TaskId)); taskRouterNode.AssertType <TaskRouterFormNode>(); // We prevent queueing from the task list so that we don't have to iterate over other tasks var stopKey = Key.ForTaskList(); var pathFinder = new GraphPathFinderBuilder <Key, FormNode>(PathFinderType.PriorityPathFinder) .WithOnEdgeDiscoveredHandler((e, output) => { if (e.ToNode.Key.Equals(stopKey)) { output.ShouldQueue = false; } }) .Build(); var pathResult = pathFinder.FindPath(form, taskRouterNode, currentNode); // Skip the current node then find the first physical node var reversedPath = pathResult.Path.Reverse(); var physicalNode = reversedPath.Skip(1).FirstOrDefault(x => !x.Value.IsDecisionNode); return(physicalNode is null?Key.ForTaskList().Value : physicalNode.Key.Value); }
public async Task PathFindingTest() { var repo = new Mock <IFormRepository>(); var provider = new Mock <IStaticFormProvider>(); var service = new FormService(repo.Object, provider.Object); var form = await service.InitialiseForm("test", FormType.Test); var fromNode = form.Nodes.FindByKey(Key.ForTaskList()); var toNode = form.Nodes.FindByKey(Key.ForPostTaskPage("last-task")); var stopKey = Key.ForTaskList(); var pathFinder = new GraphPathFinderBuilder <Key, FormNode>(PathFinderType.PriorityPathFinder) .WithOnEdgeDiscoveredHandler((e, output) => { if (e.ToNode.Key.Equals(stopKey)) { output.ShouldQueue = false; } }) .Build(); var result = pathFinder.FindPath(form, fromNode, toNode); Assert.Equal(18, result.Cost); }
public async Task <(int questionNumber, int totalQuestions)> GetQuestionNumber(string formKey, string questionPageNodeId) { var form = await _formRepository.GetForm(formKey); var questionPageFormNode = form.Nodes.FindByKey(new Key(questionPageNodeId)); var questionPageValue = questionPageFormNode.AssertType <TaskQuestionPageFormNode>(); var taskListNode = form.Nodes.FindByKey(Key.ForTaskList()); var taskRouterNode = taskListNode.Neighbors.First(x => x.IsTaskRouterNode(out var taskRouter) && taskRouter.TaskId == questionPageValue.TaskId); var taskItemRouterNode = taskRouterNode.Neighbors.First(x => x.IsTaskItemRouterNode(out var tir) && tir.RepeatIndex == questionPageValue.RepeatIndices.First()); var postTaskNode = taskRouterNode.Neighbors.First(GraphNodePredicates.IsAnyPostTaskNode); var pathFinder = new GraphPathFinderBuilder <Key, FormNode>(PathFinderType.PriorityPathFinder) .WithOnNodeDequeuedHandler((props, output) => { // We don't need to queue beyond the PostTask as all the question nodes lie between the item router and post task nodes if ((props.Node.Value.IsDecisionNode && props.Node.Value is DecisionFormNode dfn && dfn.DecisionFormNodeType == DecisionFormNodeType.PostTaskGhost) || (!props.Node.Value.IsDecisionNode && props.Node.Value is PhysicalFormNode pfn && pfn.PhysicalFormNodeType == PhysicalFormNodeType.PostTask)) { output.Skip = true; } }) .Build(); var taskItemToQuestionPath = pathFinder.FindPath(form, taskItemRouterNode, questionPageFormNode); var questionToSummaryPath = pathFinder.FindPath(form, questionPageFormNode, postTaskNode); var questionNumber = taskItemToQuestionPath.Path.Count(GraphNodePredicates.IsTaskQuestionPageNode); var remainingQuestionCount = questionToSummaryPath.Path.Count(GraphNodePredicates.IsTaskQuestionPageNode) - 1; // -1 so we don't include the current question twice return(questionNumber, questionNumber + remainingQuestionCount); }