private void FindGraphCycles(out List <Stack <ParsedCell> > cycles)
        {
            cycles = new List <Stack <ParsedCell> >();

            var unvisited = new HashSet <ParsedCell>(cellGraph.Keys);

            while (unvisited.Count > 0)
            {
                ParsedCell curNode = null;
                foreach (var node in unvisited)
                {
                    curNode = node; break;
                }

                var path = new Stack <ParsedCell>();
                if (HasCycleWithNode(path, new HashSet <ParsedCell>(), curNode, curNode))
                {
                    cycles.Add(path);
                    foreach (var node in path)
                    {
                        unvisited.Remove(node);
                    }
                }
                else
                {
                    unvisited.Remove(curNode);
                }
            }
        }
        private void RemoveParentFromChildren(ParsedCell parent)
        {
            if (!cellGraph.ContainsKey(parent))
            {
                return;
            }
            var children = cellGraph[parent].children;

            foreach (var child in children)
            {
                if (!cellGraph.ContainsKey(child))
                {
                    continue;
                }

                var childNode = cellGraph[child];
                if (!childNode.parents.Contains(parent))
                {
                    continue;
                }

                childNode.parents.Remove(parent);
                if (childNode.parents.Count == 0 && childNode.children.Count == 0)
                {
                    cellGraph.Remove(child);
                }
            }
        }
 private void ListenToChildsErrors(ParsedCell listener)
 {
     Debug.Assert(cellGraph.ContainsKey(listener));
     SubscribeToChildError(new HashSet <ParsedCell>()
     {
         listener
     }, cellGraph[listener].children, listener);
 }
 private void AddParentToChildren(ParsedCell parent, HashSet <ParsedCell> children)
 {
     foreach (var child in children)
     {
         if (!cellGraph.ContainsKey(child))
         {
             cellGraph.Add(child, (new HashSet <ParsedCell>(), new HashSet <ParsedCell>()));
         }
         cellGraph[child].parents.Add(parent);
     }
 }
        private void SpreadErrorFromCell(ParsedCell cell, GridCoordinates cords)
        {
            if (!spreadErrorListeners.ContainsKey(cords))
            {
                spreadErrorListeners.Add(cords, new HashSet <ParsedCell>());
            }

            SpreadToParents(new HashSet <ParsedCell> {
                cell
            }, cellGraph[cell].parents, cords);
        }
        private void CalculateGrid()
        {
            var childDictionary = new Dictionary <GridCoordinates, object>();
            var unvisited       = new HashSet <ParsedCell>(cellGraph.Keys.Where((cell) => cell.Calculable));

            while (unvisited.Count > 0)
            {
                ParsedCell targetCell = null;
                foreach (var cell in unvisited)
                {
                    targetCell = cell; break;
                }

                TryCalculateCell(unvisited, childDictionary, targetCell);
            }
        }
        private string GenerateCycleErrorMessage(Stack <ParsedCell> path, ParsedCell initCell)
        {
            var sb = new StringBuilder();

            sb.Append("Recursive dependency: \n");

            var pathList = new List <ParsedCell>(path);
            var shift    = pathList.IndexOf(initCell);

            Debug.Assert(shift >= 0);

            for (int i = 0; i < pathList.Count; i++)
            {
                var cell = pathList[(shift + pathList.Count - i) % pathList.Count];
                (string x, string y) = cell.Coordinates.GetStringCoords();
                sb.Append($"{x}{y} ");
            }
            return(sb.ToString());
        }
        private void UpdateGraphForCell(ParsedCell targetCell)
        {
            if (!cellGraph.ContainsKey(targetCell))
            {
                cellGraph.Add(targetCell, (new HashSet <ParsedCell>(), new HashSet <ParsedCell>()));
            }
            else
            {
                RemoveParentFromChildren(targetCell);
                cellGraph[targetCell].children.Clear();
            }

            cellGraph[targetCell].children.UnionWith(ExtractCellsFromCoords(targetCell.ChildCells));
            AddParentToChildren(targetCell, cellGraph[targetCell].children);

            if (cellGraph[targetCell].children.Count == 0 && cellGraph[targetCell].parents.Count == 0)
            {
                cellGraph.Remove(targetCell);
            }
        }
        private bool HasCycleWithNode(Stack <ParsedCell> path, HashSet <ParsedCell> visited, ParsedCell currCell, ParsedCell initCell)
        {
            if (visited.Contains(currCell))
            {
                return(false);
            }
            visited.Add(currCell);
            path.Push(currCell);

            foreach (var child in cellGraph[currCell].children)
            {
                if (child == initCell)
                {
                    return(true);
                }

                if (visited.Contains(child))
                {
                    continue;
                }

                if (HasCycleWithNode(path, visited, child, initCell))
                {
                    return(true);
                }
            }

            path.Pop();
            return(false);
        }
        private void SubscribeToChildError(HashSet <ParsedCell> visited, HashSet <ParsedCell> children, ParsedCell initListener)
        {
            foreach (var child in children)
            {
                if (visited.Contains(child))
                {
                    continue;
                }
                visited.Add(child);

                if (child.HasError)
                {
                    var childCords = child.Coordinates;
                    if (!spreadErrorListeners.ContainsKey(childCords))
                    {
                        spreadErrorListeners.Add(childCords, new HashSet <ParsedCell>());
                    }

                    initListener.AddSpreadErrorSource(childCords);
                    spreadErrorListeners[childCords].Add(initListener);
                }
                else
                {
                    Debug.Assert(cellGraph.ContainsKey(child));
                    SubscribeToChildError(visited, cellGraph[child].children, initListener);
                }
            }
        }
        private bool TryCalculateCell(HashSet <ParsedCell> unvisited, Dictionary <GridCoordinates, object> calculated, ParsedCell curCell)
        {
            unvisited.Remove(curCell);

            bool success = true;

            foreach (GridCoordinates childCoords in curCell.ChildCells)
            {
                if (calculated.ContainsKey(childCoords))
                {
                    continue;
                }
                var childCell = FromCoords(childCoords);

                if (childCell == null)
                {
                    calculated.Add(childCoords, (Decimal)0);
                }

                if (unvisited.Contains(childCell))
                {
                    success &= TryCalculateCell(unvisited, calculated, childCell);
                }
            }

            if (success)
            {
                var result = curCell.Calculate(calculated);
                calculated.Add(curCell.Coordinates, curCell.Value);
                return(result);
            }

            return(false);
        }