local Rx = require 'Rx'

local AbstractObserver = Rx.AbstractObserver
local CompositeDisposable = Rx.CompositeDisposable
local ObservableBase = Rx.ObservableBase

local validateNonNegativeInteger = Rx.internals.NumericArgument.validateNonNegativeInteger

local unpack = table.unpack or unpack

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

local SkipLastObserver = Rx.Class 'Rx.internals.SkipLastObserver' {

    AbstractObserver,
        -- superclass

    _observer = false,
        -- (Observer)

    _count = 0,
        -- (number)

    _q = {},
        -- (table)

    _qHead = 1,
        -- (number)

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

    __init = function(self, observer, count)

        self._observer = observer
        self._count = count
        self._q = {}
        self._qHead = 1

    end,

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

    next = function(self, ...)

        local count = self._count
        local q = self._q

        if count == 0 then

            self._observer:onNext(...)

        elseif #self._q == count then

            local qHead = self._qHead

            local values = q[qHead]
            self._observer:onNext(unpack(values, 1, values.n))

            q[qHead] = { n = select('#', ...), ... }

            qHead = qHead + 1
            if qHead > count then
                qHead = 1
            end

            self._qHead = qHead

        else

            q[#q + 1] = { n = select('#', ...), ... }

        end

    end,

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

    error = function(self, ...)

        self._observer:onError(...)

    end,

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

    completed = function(self)

        self._observer:onCompleted()

    end,

}

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

local SkipLastObservable = Rx.Class 'Rx.internals.SkipLastObservable' {

    ObservableBase,
        -- superclass

    _source = 0,
        -- (Observable)

    _count = 0,
        -- (number)

    __init = function(self, source, count)

        self._source = source
        self._count = count

    end,

    subscribeCore = function(self, observer)

        local skipLastObserver = SkipLastObserver(observer, self._count)

        return CompositeDisposable(self._source:subscribe(skipLastObserver),
            skipLastObserver)

    end,

}

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

return function(self, ...)

    local count = validateNonNegativeInteger('count', 1, 1, ...)

    return SkipLastObservable(self, count)

end
