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

WFCatTask.lua

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

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

NOTICE: All information contained herein is, and remains 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 are protected by all applicable
intellectual property laws, including trade secret and copyright laws.
Dissemination of this information or reproduction of this material is
strictly forbidden unless prior written permission is obtained from
Adobe Systems Incorporated.

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

local Rx = require 'Rx'

local WFProgressReporter = require 'WFProgressReporter'

local Disposable = Rx.Disposable

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

local WFCatTaskClass = {

	Disposable,
	
-- public --
	
	_taskObservable = false,			-- reports the progress to client, and receive the 'cancel' from client
	
-- private --
	
	_requestArgs = false,
	
	_requestAction = false,
	
	_actionResultSubscription = false,	-- notify the task manager when the action is completed
	
	_progressReporter = false,			-- report the task progress
		
	_cancelled = false,					-- cancel flag, returns true if the task is cancelled
	
	_cancelStream = false,				-- stop the task when the cancel is triggered via client
		
	_progressSubscription = false,		-- hold the subscription to prevent it from being garbage collected
	
	_readyToFireStream = false,			-- perform the task if the stream is emitted
	
}

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

function WFCatTaskClass:__init( request )

	self._requestArgs = request.args
	
	self._requestAction = request.action
	
	self._progressReporter = WFProgressReporter( "WFCatTask")
	
	self._cancelStream = Rx.Subject()
	
	self._readyToFireStream = Rx.ReplaySubject( 1 )

	self._taskObservable = Rx.Observable.create( function( observer )
		
		-- observe the task progress
		self._progressSubscription = self._progressReporter:status():subscribe(
			function( ... )
				observer:onNext( ... )
			end,
					
			function( ... )
				observer:onError( ... )
			end,
					
			function()
				observer:onCompleted()
			end )
			
		self._readyToFireStream:onNext( true )

   		return Rx.Disposable.create(function()
		
			-- Notify the cancelStream the cancel is sent from client
			if self._progressReporter and not self._progressReporter:isDone() then
				self:cancelTask()
			end
			
   		end)
		
	end)
end

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

function WFCatTaskClass:performAction()

	return self._readyToFireStream
	
		:take( 1 )
		
		:flatMapLatest( function()
			local resultStream = Rx.Subject()
			
			if self._requestAction and type( self._requestAction ) == "function" then
				self._actionResultSubscription = self._taskObservable:subscribe( nil, 
					function( err )
						resultStream:onNext( err )
					end, 
					function()
						resultStream:onNext( "completed" )
					end )
				
				-- perform the action
				self._requestAction( self._requestArgs, self._progressReporter, self._cancelStream )
			else
				resultStream:onNext( "completed" )
			end
			
			return resultStream
		end )
		
end

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

function WFCatTaskClass:taskObservable()
	return self._taskObservable
end

--------------------------------------------------------------------------------
 
function WFCatTaskClass:cancelTask()
	if self._cancelStream and not self._cancelled then
		self._cancelled = true
		self._cancelStream:onNext( true )
	end
end

--------------------------------------------------------------------------------
 
function WFCatTaskClass:cancelled()
	return self._cancelled 
end

--------------------------------------------------------------------------------
 
function WFCatTaskClass:close()
	
	if self._readyToFireStream then
		self._readyToFireStream:dispose()
		self._readyToFireStream = nil
	end
	
	if self._actionResultSubscription then
		self._actionResultSubscription:dispose()
		self._actionResultSubscription = false
	end
	
	if self._cancelStream then
		self._cancelStream:dispose()
		self._cancelStream = false
	end
	
	if self._progressSubscription then
		self._progressSubscription:dispose()
		self._progressSubscription = false
	end
	
	if self._progressReporter then
		self._progressReporter:reset()
		self._progressReporter = false
	end
end

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

return Rx.Class 'WFCatTask'( WFCatTaskClass )

