local Rx = require 'Rx'

local AnonymousObservable = Rx.AnonymousObservable
local CompositeDisposable = Rx.CompositeDisposable
local Observer = Rx.Observer
local SingleAssignmentDisposable = Rx.SingleAssignmentDisposable

local observerCreate = Observer.create

--------------------------------------------------------------------------------

return function(self, rightSource)

    local leftSource = self

    return AnonymousObservable(function(observer)

        local choice

        local leftSubscription = SingleAssignmentDisposable()
        local rightSubscription = SingleAssignmentDisposable()

        local function choiceL()
            if not choice then
                choice = 'L'
                rightSubscription:dispose()
            end
        end

        local function choiceR()
            if not choice then
                choice = 'R'
                leftSubscription:dispose()
            end
        end

        local leftObserver = observerCreate(
            function(...)
                choiceL()
                if choice == 'L' then
                    observer:onNext(...)
                end
            end,
            function(...)
                choiceL()
                if choice == 'L' then
                    observer:onError(...)
                end
            end,
            function()
                choiceL()
                if choice == 'L' then
                    observer:onCompleted()
                end
            end)

        local rightObserver = observerCreate(
            function(...)
                choiceR()
                if choice == 'R' then
                    observer:onNext(...)
                end
            end,
            function(...)
                choiceR()
                if choice == 'R' then
                    observer:onError(...)
                end
            end,
            function()
                choiceR()
                if choice == 'R' then
                    observer:onCompleted()
                end
            end)

        leftSubscription:setDisposable(leftSource:subscribe(leftObserver))
        rightSubscription:setDisposable(rightSource:subscribe(rightObserver))

        return CompositeDisposable(
            leftSubscription, rightSubscription,
            leftObserver, rightObserver
        )

    end)

end
