private bool AllowsForTraffic(IZoneInfoPathNode node)
        {
            return(node.EnumeratePathBackwards().All(member =>
            {
                _cancellationToken.ThrowIfCancellationRequested();
                var roadZoneConsumption = member.ZoneInfo
                                          .GetNetworkZoneConsumption <RoadZoneConsumption>();

                if (roadZoneConsumption.HasMatch)
                {
                    if (_roadZonesAndTraffic.ContainsKey(roadZoneConsumption.MatchingObject))
                    {
                        return _roadZonesAndTraffic[roadZoneConsumption.MatchingObject].OldDensity < 600;
                    }
                }
                return true;
            }));
        }
        private ZoneInfoPathNode(
            IZoneInfo zoneInfo,
            Func <IZoneInfoPathNode, QueryResult <IZoneInfo, RelativeZoneInfoQuery>, bool> canBeJoinedFunc,
            Func <IZoneInfo, int?> getDestinationHashCode,
            IZoneInfoPathNode previousPathNode,
            IZoneInfoPathNode originParentPathNode,
            int distance,
            ZoneInfoDistanceTracker distanceTracker)
        {
            ZoneInfo         = zoneInfo;
            PreviousPathNode = previousPathNode;

            _originParentPathNode = originParentPathNode ?? this;

            DestinationHashCode = getDestinationHashCode(zoneInfo);

            Distance = distance;

            _childPathsLazy = new Lazy <List <IZoneInfoPathNode> >(() =>
                                                                   !distanceTracker.IsPreviouslyNotSeenOrSeenAtLargerDistance(ZoneInfo, distance, previousPathNode)
                ? Enumerable.Empty <IZoneInfoPathNode>().ToList()
                : ZoneInfo
                                                                   .GetNorthEastSouthWest()
                                                                   .Where(x => x.HasMatch)
                                                                   .Where(x => x.MatchingObject != PreviousPathNode?.ZoneInfo)
                                                                   .Where(x => distanceTracker.DoesNotExceedMaximumDistanceForAllCriteria(ZoneInfo, distance))
                                                                   .Where(x => canBeJoinedFunc(this, x))
                                                                   .Select(x => new ZoneInfoPathNode(
                                                                               zoneInfo: x.MatchingObject,
                                                                               canBeJoinedFunc: canBeJoinedFunc,
                                                                               getDestinationHashCode: getDestinationHashCode,
                                                                               previousPathNode: this,
                                                                               originParentPathNode: _originParentPathNode,
                                                                               distance: Distance + x.MatchingObject.GetDistanceScoreBasedOnConsumption(),
                                                                               distanceTracker: distanceTracker
                                                                               ))
                                                                   .ToList <IZoneInfoPathNode>());
        }
        public bool IsPreviouslyNotSeenOrSeenAtLargerDistance(IZoneInfo node, int distance, IZoneInfoPathNode previousPathNode)
        {
            var currentConsumption  = node.ConsumptionState.GetZoneConsumption();
            var previousConsumption = previousPathNode?.ZoneInfo.ConsumptionState.GetZoneConsumption();

            if (currentConsumption is IntersectingZoneConsumption)
            {
                var currentConsumptionAsIntersection = currentConsumption as IntersectingZoneConsumption;
                if (!_intersectionsAndSeenTypes.ContainsKey(currentConsumptionAsIntersection))
                {
                    _intersectionsAndSeenTypes.Add(currentConsumptionAsIntersection, new HashSet <Type>());
                }
                if (previousConsumption != null)
                {
                    return(_intersectionsAndSeenTypes[currentConsumptionAsIntersection].Add(previousConsumption.GetType()));
                }
                else
                {
                    throw new InvalidOperationException();
                }
            }

            if (_nodesAndDistances.ContainsKey(node))
            {
                if (_nodesAndDistances[node].Distance > distance)
                {
                    _nodesAndDistances[node].UpdateDistance(distance);
                    return(true);
                }
                return(false);
            }
            else
            {
                _nodesAndDistances.Add(node, new DistanceAndConsumption(distance));
                return(true);
            }
        }