class SwitchableSubscriptionSubscriber implements MultiSubscriber<O>, Subscription {

    void drainLoop() {
        int missed = 1;

        long requestAmount = 0L;
        Subscription requestTarget = null;

        for (;;) {

            Subscription nextUpstream = pendingSubscription.getAndSet(null);
            long pendingRequests = missedRequested.getAndSet(0L);
            long pendingItems = missedItems.getAndSet(0L);
            Subscription upstream = currentUpstream.get();

            if (cancelled.get()) {
                // Cancel and release all.
                if (upstream != null) {
                    upstream.cancel();
                    currentUpstream.set(null);
                }
                if (nextUpstream != null) {
                    nextUpstream.cancel();
                }
            } else {
                long req = requested;
                if (req != Long.MAX_VALUE) {
                    long res = Subscriptions.add(req, pendingRequests);
                    if (res != Long.MAX_VALUE) {
                        long remaining = res - pendingItems;
                        if (remaining < 0L) {
                            remaining = 0;
                        }
                        req = remaining;
                    } else {
                        req = res;
                    }
                    requested = req;
                }

                // Perform the switch
                if (nextUpstream != null) {
                    if (upstream != null && cancelUpstreamOnSwitch()) {
                        upstream.cancel();
                    }
                    currentUpstream.set(nextUpstream);
                    if (req != 0L) {
                        requestAmount = Subscriptions.add(requestAmount, req);
                        requestTarget = nextUpstream;
                    }
                } else if (pendingRequests != 0L && upstream != null) {
                    requestAmount = Subscriptions.add(requestAmount, pendingRequests);
                    requestTarget = upstream;
                }
            }

            missed = wip.addAndGet(-missed);
            if (missed == 0) {
                if (requestAmount != 0L) {
                    requestTarget.request(requestAmount);
                }
                return;
            }
        }
    }

    public  SwitchableSubscriptionSubscriber(MultiSubscriber<? super O> downstream);

}