local Rx = require 'Rx'

local Subject = Rx.Subject
local InnerSubscription = Rx.internals.InnerSubscription

local checkDisposed = Rx.Disposable.checkDisposed

local disposableEmpty = Rx.Disposable.empty

local unpack = table.unpack or unpack

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

local behaviorSubjectPrototype = {

    Subject,
        -- superclass

    _value = false,
        -- (any)

}

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

local function tableShallowCopy(orig)

    local copy = {}

    for orig_key, orig_value in pairs(orig) do
        copy[orig_key] = orig_value
    end

    return copy

end

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

function behaviorSubjectPrototype:__init(...)

    self._value = { ... }
    self._value.n = select('#', ...)

end

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

function behaviorSubjectPrototype:_subscribe(observer)

    checkDisposed(self)

    if not self._isStopped then

        if self._ohoObservers and #self._observers == 0 then
            for _, ohoObserver in ipairs(self._ohoObservers) do
                ohoObserver:onNext(true)
            end
        end

        table.insert(self._observers, observer)

        observer:onNext(unpack(self._value, 1, self._value.n))

        return InnerSubscription(self, observer)

    end

    if self._hasError then
        observer:onError(unpack(self._error, 1, self._error.n))
    else
        observer:onCompleted()
    end

    return disposableEmpty()

end

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

function behaviorSubjectPrototype:onNext(...)

    checkDisposed(self)

    if self._isStopped then
        return
    end

    self._value = { ... }
    self._value.n = select('#', ...)

    local os = tableShallowCopy(self._observers)

    for i = 1, #os do
        os[i]:onNext(...)
    end

end

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

function behaviorSubjectPrototype:value()

    if self._value then
        return unpack(self._value, 1, self._value.n)
    else
        return nil
    end

end

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

function behaviorSubjectPrototype:getValue()

    checkDisposed(self)

    if self._hasError then
        error(self._error[1])
    end

    return self:value()

end

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

function behaviorSubjectPrototype:dispose()

    self._value = nil

    self:Rx_Subject_dispose()

end

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

return Rx.Class('Rx.BehaviorSubject', behaviorSubjectPrototype)
