--[[----------------------------------------------------------------------------

WFRxEventBridge.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2015 Adobe Systems Incorporated
All Rights Reserved.

NOTICE: All information contained herein is, and remain the property of
Adobe Systems Incorporated and its suppliers, if any. The intellectual and
technical concepts contained herein are proprietary to Adobe Systems
Incorporated and its suppliers and may be covered by U.S. and Foreign
Patents, patents in process, and are protected by trade secret or copyright
law.  Dissemination of this information or reproduction of this material is
strictly forbidden unless prior written permission is obtained from
Adobe Systems Incorporated.

------------------------------------------------------------------------------]]

	-- RxLua
local Rx = require 'Rx'

	-- WF.core.reactive
local KSReactive = require 'KSReactive'

	-- WF.core.utils
local WFCloseSupport = require 'WFCloseSupport'


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

local isClosed = assert( WFCloseSupport.hasBeenOrWillBeClosed )


--============================================================================--

local WFRxEventBridge = {

	_unsubscribeHandle = false,

	_disposed = false,

	_weakValueE = false,

	WFCloseSupport.addCloseSupportMethods,

}

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

local function dispose( self )

	self._disposed = true

	if self._unsubscribeHandle then
		self._unsubscribeHandle:dispose()
		self._unsubscribeHandle = nil
	end

end

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

local function wireUpSubscribe( self, observable )

	local weakValueE = self._weakValueE

	self._unsubscribeHandle:setDisposable(
		observable:subscribe(

			function( ... )

				local valueE = next( weakValueE )

				if valueE and not isClosed( valueE ) then
					valueE:post( ... )
				else
					dispose( self )
				end

			end,

			function( ... )

				local valueE = next( weakValueE )

				if valueE and not isClosed( valueE ) then
					valueE:postError( ... )
						-- NOTE: KSReactive only supports a single message for
						-- errors!	So although we pass in the tuple here it
						-- will be trimmed to a single value.
					valueE:postDone()
				end

				dispose( self )

			end,

			function()

				local valueE = next( weakValueE )

				if valueE and not isClosed( valueE ) then
					valueE:postDone()
				end

				dispose( self )

			end ) )

end

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

function WFRxEventBridge:__init( valueE, observable, optScheduler )

	local scheduler = optScheduler or require 'WFRxScheduler'.sharedScheduler()

	self._unsubscribeHandle = Rx.SerialDisposable()

	self._weakValueE = setmetatable( {}, { __mode = 'kv' } )
	self._weakValueE[ valueE ] = valueE

	valueE:weakOnDoneE( function()
		dispose( self )
	end )

	rawset( valueE, 'private:WFRxEventBridge_handler', self )
	valueE:addCloseTarget( self )

	local weakSelf = setmetatable( {}, { __mode = 'kv' } )
	weakSelf[ self ] = self

	local disposable = Rx.Observable.timer( -1, nil, scheduler )
		:subscribe( function()
			local self = next( weakSelf )
			if not self or self._disposed then
				return
			end
			wireUpSubscribe( self, observable )
		end )

	self._unsubscribeHandle:setDisposable( disposable )

	WFCloseSupport.mustCloseAtThreadTermination( self )

end

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

function WFRxEventBridge:close()

	dispose( self )

end

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

WFRxEventBridge = Rx.Class 'WFRxEventBridge'( WFRxEventBridge )

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

-- RxLua tests the argument to :call for type function, so we wrap this in an
-- actual function to satisfy that test.

return function( ... )

	-- the WFRxEventBridge instance does not hold the valueE strongly, so we
	-- need to anchor it here or it could get collected before we return. The
	-- valueE does hold a strong ref to the WFRxEventBridge, so we do not need
	-- to capture the object the constructor returns.
	local valueE = KSReactive.sourceE()
	WFRxEventBridge( valueE, ... )

	return valueE

end
