local Rx = require 'Rx'

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

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

local GenerateRelativeObservable = Rx.Class 'Rx.AbstractObserver' {

    ObservableBase,
        -- superclass

    _initialState = false,
        -- (any)

    _conditionFn = false,
        -- (function)

    _iterateFn = false,
        -- (function)

    _resultFn = false,
        -- (function)

    _timeFn = false,
        -- (function)

    _scheduler = false,
        -- (Scheduler)

    __init = function(self, initialState, conditionFn, iterateFn, resultFn, timeFn, scheduler)

        self._initialState = initialState
        self._conditionFn = conditionFn
        self._iterateFn = iterateFn
        self._resultFn = resultFn
        self._timeFn = timeFn
        self._scheduler = scheduler

    end,

    subscribeCore = function(self, observer)

        local function scheduleRecursive(state, recurseFn)

            if state.hasResult then
                state.observer:onNext(state.iterState)
            end

            if state.first then

                state.first = false

            else

                local success, newStateOrError = pcall(self._iterateFn, state.iterState)

                if not success then
                    return state.observer:onError(newStateOrError)
                end

                state.iterState = newStateOrError

            end

            local conditionFnSuccess, hasResultOrError = pcall(self._conditionFn, state.iterState)

            if not conditionFnSuccess then
                return state.observer:onError(hasResultOrError)
            end

            state.hasResult = hasResultOrError

            if hasResultOrError then

                local resultFnSuccess, resultOrError = pcall(self._resultFn, state.iterState)

                if not resultFnSuccess then
                    return state.observer:onError(resultOrError)
                end

                local timeFnSuccess, timeOrError = pcall(self._timeFn, state.iterState)

                if not timeFnSuccess then
                    return state.observer:onError(timeOrError)
                end

                recurseFn(state, timeOrError)

            else

                state.observer:onCompleted()

            end

        end

        local state = {
            observer = observer,
            first = true,
            hasResult = false,
            iterState = self._initialState,
        }

        return self._scheduler:scheduleRecursiveFuture(state, 0, scheduleRecursive)

    end,

}

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

return function(initialState, condition, iterate, resultSelector, timeSelector, scheduler)

    scheduler = SchedulerArgument.validateWithoutDefault(
        'Rx.Observable.generateWithRelativeTime', scheduler)

    return GenerateRelativeObservable(initialState, condition, iterate,
        resultSelector, timeSelector, scheduler)

end
