local Rx = require 'Rx'

local ObservableBase = Rx.ObservableBase
local SchedulerArgument = Rx.internals.SchedulerArgument

local unpack = table.unpack or unpack

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

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

    _observer = false,
        -- (Observer)

    _parent = false,
        -- (Observable)

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

    __init = function(self, observer, parent)

        self._observer = observer
        self._parent = parent

    end,

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

    run = function(self)

        local observer = self._observer
        local value = self._parent._value

        local function loopRecursive(i, recurseFn)

            if i > 0 or i == -1 then

                observer:onNext(unpack(value, 1, value.n))

                if i > 0 then
                    i = i - 1
                end

            end

            if i == 0 then
                observer:onCompleted()
            else
                recurseFn(i)
            end

        end

        return self._parent._scheduler:scheduleRecursive(self._parent._repeatCount,
                                                                  loopRecursive)

    end,

}

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

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

    ObservableBase,
        -- superclass

    _scheduler = false,
        -- (Scheduler)

    _value = false,
        -- (tuple with size in 'n')

    _repeatCount = false,
        -- (number)

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

    __init = function(self, value, repeatCount, scheduler)

        self._value = value
        self._repeatCount = repeatCount or -1
        self._scheduler = scheduler

    end,

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

    subscribeCore = function(self, observer)

        local sink = RepeatSink(observer, self)
        return sink:run()

    end,

}

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

return function(repeatCount, ...)

    local stripLastArg, scheduler = SchedulerArgument.fromVarArgs('Rx.Observable.rep',
                                                                  'immediate', ...)
    local value
    if stripLastArg then
        value = { n = select('#', ...) - 1, ... }
    else
        value = { n = select('#', ...), ... }
    end

    return RepeatObservable(value, repeatCount, scheduler)

end
