/// <summary>
        /// The given loc has waited at it's destination.
        /// Let's assign a new route.
        /// </summary>
        /// <returns>The timespan before this method wants to be called again.</returns>
        private TimeSpan OnWaitingForDestinationGroupMinimum(ILocState loc, int generationDelta)
        {
            // Check state
            var state = loc.AutomaticState.Actual;

            if (state != AutoLocState.WaitingForDestinationGroupMinimum)
            {
                log.Warn("Loc {0} in valid state ({1}) at destination timeout.", loc, loc.AutomaticState);
                return(TimeSpan.MaxValue);
            }

            // Log state
            log.Trace("OnWaitingForDestinationGroupMinimum {0}", loc);

            // Do we still control this loc?
            if (!ShouldControlAutomatically(loc))
            {
                RemoveLocFromAutomaticControl(loc);
                return(TimeSpan.MaxValue);
            }

            // Timeout reached?
            if (loc.CanLeaveCurrentBlock() || overrideLeaveCurrentBlock(generationDelta))
            {
                // Yes, let's assign a new route
                loc.AutomaticState.Actual = AutoLocState.AssignRoute;
                return(TimeSpan.Zero);
            }

            // Nothing changed
            return(TimeSpan.MaxValue);
        }
        /// <summary>
        /// The given loc has waited at it's destination.
        /// Let's assign a new route.
        /// </summary>
        /// <returns>The timespan before this method wants to be called again.</returns>
        private TimeSpan OnWaitingForDestinationTimeout(ILocState loc)
        {
            // Check state
            var state = loc.AutomaticState.Actual;

            if (state != AutoLocState.WaitingForDestinationTimeout)
            {
                log.Warn("Loc {0} in valid state ({1}) at destination timeout.", loc, loc.AutomaticState);
                return(TimeSpan.MaxValue);
            }

            // Log state
            log.Trace("OnWaitingForDestinationTimeout {0}", loc);

            // Do we still control this loc?
            if (!ShouldControlAutomatically(loc))
            {
                RemoveLocFromAutomaticControl(loc);
                return(TimeSpan.MaxValue);
            }

            // Timeout reached?
            var startNextRouteTime = loc.StartNextRouteTime.Actual;
            var now = DateTime.Now;

            if (now >= startNextRouteTime)
            {
                // Check the block group, see if we can leave
                if (loc.CanLeaveCurrentBlock())
                {
                    // Yes, let's assign a new route
                    loc.AutomaticState.Actual = AutoLocState.AssignRoute;
                    return(TimeSpan.Zero);
                }
                else
                {
                    // No we cannot leave yet
                    loc.AutomaticState.Actual = AutoLocState.WaitingForDestinationGroupMinimum;
                    return(TimeSpan.MaxValue);
                }
            }

            // Nothing changed
            return(startNextRouteTime.Subtract(now));
        }
        /// <summary>
        /// Try to assign a route to the given loc.
        /// </summary>
        /// <returns>The timespan before this method wants to be called again.</returns>
        private TimeSpan OnAssignRoute(ILocState loc, int generationDelta, ref int locsWithNoRoute)
        {
            // Check state
            var state = loc.AutomaticState.Actual;

            if (state != AutoLocState.AssignRoute)
            {
                log.Warn("Cannot assign route to loc {0} in {1} state.", loc, loc.AutomaticState);
                return(TimeSpan.MaxValue);
            }

            // Log state
            log.Trace("OnAssignRoute {0}", loc);

            // Does the locs still wants to be controlled?
            if (!ShouldControlAutomatically(loc))
            {
                RemoveLocFromAutomaticControl(loc);
                return(TimeSpan.MaxValue);
            }

            // Look for a free route from the current destination
            var block = loc.CurrentBlock.Actual;

            if (block == null)
            {
                // Oops, no current block, we cannot control this loc
                RemoveLocFromAutomaticControl(loc);
                return(TimeSpan.MaxValue);
            }

            // Is a reversing block on a block where it must un-reverse?
            if (loc.Reversing.Actual && block.ChangeDirectionReversingLocs)
            {
                // Change direction and clear the reversing flag
                loc.CurrentBlockEnterSide.Actual = loc.CurrentBlockEnterSide.Actual.Invert();
                loc.Reversing.Actual             = false;
                loc.Direction.Requested          = loc.Direction.Actual.Invert();
                loc.AutomaticState.Actual        = AutoLocState.ReversingWaitingForDirectionChange;
                loc.PossibleDeadlock.Actual      = false;
                return(TimeSpan.Zero);
            }

            // Select next route
            var route = loc.NextRoute.Actual;

            if (route == null)
            {
                // No next route was set
                if ((loc.Speed.Requested == 0) && (!loc.CanLeaveCurrentBlock()) && (!overrideLeaveCurrentBlock(generationDelta)))
                {
                    // We're not running and we're not allowed to leave the current block
                    loc.AutomaticState.Actual   = AutoLocState.WaitingForDestinationGroupMinimum;
                    loc.PossibleDeadlock.Actual = false;
                    return(TimeSpan.FromMinutes(1));
                }

                // Choose a next route now
                route = ChooseRoute(loc, block, loc.CurrentBlockEnterSide.Actual.Invert(), false, generationDelta);
            }
            if (route == null)
            {
                // No possible routes right now, try again
                locsWithNoRoute++;
                DateTime since;
                if (!locHasNoRouteSince.TryGetValue(loc, out since))
                {
                    locHasNoRouteSince[loc] = DateTime.Now;
                }
                else
                {
                    loc.PossibleDeadlock.Actual = (DateTime.Now.Subtract(since).TotalSeconds > 30);
                }
                return(TimeSpan.FromSeconds(5));
            }
            else
            {
                locHasNoRouteSince.Remove(loc);
                loc.PossibleDeadlock.Actual = false;
            }

            // Lock the route
            route.Lock(loc);
            // Setup waiting after block (do this before assigning the route)
            if (route.To.WaitPermissions.Evaluate(loc))
            {
                // Waiting allowed, gamble for it.
                var waitProbability = route.To.WaitProbability;
                loc.WaitAfterCurrentRoute.Actual = ThreadStatics.Random.Gamble(waitProbability);
            }
            else
            {
                // Waiting not allowed.
                loc.WaitAfterCurrentRoute.Actual = false;
            }
            // Assign the route
            loc.CurrentRoute.Actual = route.CreateStateForLoc(loc);

            // Clear next route
            loc.NextRoute.Actual = null;

            // Should we change direction?
            var enteredSide = loc.CurrentBlockEnterSide.Actual;
            var leavingSide = route.FromBlockSide;

            if (enteredSide == leavingSide)
            {
                // Reverse direction
                loc.Direction.Requested = loc.Direction.Actual.Invert();

                // Are we reversing now?
                if (loc.ChangeDirection == ChangeDirection.Avoid)
                {
                    loc.Reversing.Actual = !loc.Reversing.Actual;
                }

                // When reversing, check the state of the target block
                if (loc.Reversing.Actual && route.To.ChangeDirectionReversingLocs)
                {
                    // We must stop at the target block
                    loc.WaitAfterCurrentRoute.Actual = true;
                }
            }

            // Change state
            loc.AutomaticState.Actual = AutoLocState.WaitingForAssignedRouteReady;

            // Prepare the route?
            route.Prepare();

            // We're done
            return(TimeSpan.Zero);
        }