local Rx = require 'Rx'

local AbstractObserver = Rx.AbstractObserver
local Observer = Rx.Observer
local SerialDisposable = Rx.SerialDisposable

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

local autoDetachObserver = {

    AbstractObserver,
        -- superclass

    _observer = false,
        -- (Observer) managed Observer

    _managedDisposable = false,
        -- (Disposable) managed by self lifetime

}

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

local function noOp()
end

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

function autoDetachObserver:__init(observer)

    if not Observer:isClassOf(observer) then
        error(string.format('Rx.AutoDetachObserver: param (%s) is not a valid Observer',
                            tostring(observer)), 3)
    end

    self._observer = observer
    self._managedDisposable = SerialDisposable()

end

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

function autoDetachObserver:setStopped()
    self._isStopped = true
    rawset(self, 'next', noOp)
    rawset(self, 'onNext', noOp)
end

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

function autoDetachObserver:next(...)

    local observer = self._observer
    local status, errorMsg = pcall(observer.onNext, observer, ...)

    if not status then
        self:dispose()
        error(errorMsg)
    end

end

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

autoDetachObserver.onNext = autoDetachObserver.next

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

function autoDetachObserver:error(...)

    local status, errorMsg = pcall(self._observer.onError, self._observer, ...)

    self:dispose()

    if not status then
        error(errorMsg)
    end

end

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

function autoDetachObserver:completed()

    local status, errorMsg = pcall(self._observer.onCompleted, self._observer)

    self:dispose()

    if not status then
        error(errorMsg)
    end

end

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

function autoDetachObserver:getDisposable()

    return self._managedDisposable:getDisposable()

end

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

function autoDetachObserver:setDisposable(disposable)

    self._managedDisposable:setDisposable(disposable)

end

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

function autoDetachObserver:dispose()

    self:Rx_AbstractObserver_dispose()

    if self._managedDisposable then
        self._managedDisposable:dispose()
    end

    self._observer = nil

end

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

return Rx.Class('Rx.AutoDetachObserver', autoDetachObserver)
