--[=[
	Catches an error, and allows another observable to be subscribed
	in terms of handling the error.

	:::warning
	This method is not yet tested
	:::

	@param callback (error: TError) -> Observable<TErrorResult>
	@return (source: Observable<T>) -> Observable<T | TErrorResult>
]=]

function Rx.catchError(callback)
	assert(type(callback) == "function", "Bad callback")

	return function(source)
		assert(Observable.isObservable(source), "Bad observable")

		return Observable.new(function(sub)
			local maid = Maid.new()

			-- Yikes, let's hope event ordering is good
			local alive = true
			maid:GiveTask(function()
				alive = false
			end)

			maid:GiveTask(source:Subscribe(
				function(...)
					sub:Fire(...)
				end,
				function(...)
					if not alive then
						-- if we failed because maid was cancelled, then we'll get called here?
						-- I think.
						return
					end

					-- at this point, we can only have one error, so we need to subscribe to the result
					-- and continue the observiable
					local observable = callback(...)
					assert(Observable.isObservable(observable), "Bad observable")

					maid:GiveTask(observable:Subscribe(sub:GetFireFailComplete()))
				end,
				function()
					sub:Complete()
				end));

			return maid
		end)
	end
end
