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

PixelProviderFetchXmpDevelopTask.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2016 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
local Foreign
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.

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

local Rx = require 'Rx'
local Observable = Rx.Observable

local PixelPathProviderStateMachine = require 'PixelPathProviderStateMachine'
local PixelPathProviderSchedulerPrivateMethods =
		require "PixelPathProviderSchedulerPrivateMethods"
local WFAsyncFileUtils = require 'WFAsyncFileUtils'

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

local logger = require 'WFLogger'( 'PixelProviderFetchXmpDevelopTask' )

--------------------------------------------------------------------------------
-- setupTask
--------------------------------------------------------------------------------

local function setupTask( maxConcurrentFetches )
	
	return { 
			 maxConcurrentFetches = maxConcurrentFetches,
			 pendingFetchSubscriptions = {}
		}

end
		
--------------------------------------------------------------------------------
-- processRequests
--------------------------------------------------------------------------------

local function maybeGetUnusedPendingFetchNumber( taskState )

	local pendingFetchNumber

	for i = 1, taskState.maxConcurrentFetches do

		pendingFetchNumber = 
			pendingFetchNumber or
			( not taskState.pendingFetchSubscriptions[ i ] and i ) or
			nil

	end

	return pendingFetchNumber

end

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

local function maybeGetExternalXmpData( baseRenderInfoCache, localBinaryPathCache, pixStreamId,
										localAssetId )

	local baseRenderInfo = baseRenderInfoCache:peekCacheItem( localAssetId )

	if not baseRenderInfo then

		logger:warnf( "missing cache data for %s.%s", pixStreamId, localAssetId )

		return

	end

	local xmpDevelopPath = 
			unpack( localBinaryPathCache
						:popCacheItem( pixStreamId, localAssetId ) or {} )

	if not xmpDevelopPath then

		logger:warnf( "missing xmpDevelopPath for %s.%s", pixStreamId, localAssetId )

		return

	end

	return xmpDevelopPath, baseRenderInfo.digest, baseRenderInfo.revId,
			baseRenderInfo.userOrientation
		
end

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

local function processRequests( scheduler, taskState, baseRenderInfoCache,
								localBinaryPathCache, currRenderSettingsCache )
	
	local pendingFetchNumber
	
	repeat
	
		pendingFetchNumber = pendingFetchNumber or maybeGetUnusedPendingFetchNumber( taskState )
		
		if not pendingFetchNumber then

			break

		end
		
		local request =
			{ PixelPathProviderSchedulerPrivateMethods.getNextRequestWithState( 
				scheduler,  PixelPathProviderStateMachine.LocalBinaryPathCheckStates.RenderFetchLocalExternalXmpDevelop ) }

		local pixStreamId, localAssetId = unpack( request )

		if not pixStreamId then

			-- nothing needs fetching
			break

		end
		
		local xmpDevelopPath, digest, revId, userOrientation =
				maybeGetExternalXmpData( 
					baseRenderInfoCache, localBinaryPathCache, pixStreamId, localAssetId )

		if not xmpDevelopPath then
		
			-- can't fetch
			scheduler:_applyTransitionToRequest( 
						request, 'missing_expected_external_xmp_develop_path' )

		else

			-- start a new fetch task
			local currPendingFetchNumber = pendingFetchNumber

			pendingFetchNumber = nil

			scheduler:_applyTransitionToRequest( 
					request, 'start_reading_external_xmp_develop_path' )
				
			taskState.pendingFetchSubscriptions[ currPendingFetchNumber ] = 
				WFAsyncFileUtils.readFile( xmpDevelopPath )
					:catch( 
						function( errorMessage ) 

							logger:errorf( "Error reading from %s for %s(%s): %s", 	
								xmpDevelopPath, pixStreamId, localAssetId, errorMessage )
							
							return Observable.just( nil )

						end )
					:subscribe( 
						function( externalSettings )
							
							taskState.pendingFetchSubscriptions[ currPendingFetchNumber ] = nil
						
							-- handle the fetch callback
							if not externalSettings then
								
								-- this is a thread callback, so must use _maybeSetNextState	
								scheduler
									:_maybeSetNextState( 
										pixStreamId, localAssetId, 
										'failed_reading_external_xmp_develop_path' )

								return

							end

							local externalSettingsAsStr = tostring( externalSettings )
							
							externalSettings:close()
							
							currRenderSettingsCache
								:pushCacheItem( 
									localAssetId, 
									{ digest, 
										revId,
										externalSettingsAsStr,
										nil, --videoAdjustmentsSettings
										userOrientation, 
										nil --temporal
									} ) 
							
							-- this is a thread callback, so must use _maybeSetNextState	
							scheduler
								:_maybeSetNextState( 
									pixStreamId, localAssetId,
									'finished_reading_external_xmp_develop_path' )
								
						end )
		end
		
	until false
	
end

--------------------------------------------------------------------------------
-- cleanup
--------------------------------------------------------------------------------

local function cleanup( taskState )

	for _, subscr in pairs( taskState.pendingFetchSubscriptions ) do

		subscr:dispose()

	end

	taskState.pendingFetchSubscriptions = {}

end

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

return {

	setupTask = setupTask,

	processRequests = processRequests,

	cleanup = cleanup,

}


