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

NmbDeletionBacklogUpdater.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2017 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'
local Observable = Rx.Observable

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

	-- WF.oz_client.managed_catalog
local WFCatFileSpec = require 'WFCatFileSpec'
local WFCatIndexUtils = require 'WFCatIndexUtils'

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

local check = assert( WFArguments.check )

local isValidAssetDocument = assert( WFCatIndexUtils.isValidAssetDocument )

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

local function didLocalNegativeStatusChange( assetInfo, docValue )

	local previousLocalOriginalGuid = assetInfo.localOriginalVolumeGuid
	local previousLocalProxyGuid = assetInfo.localProxyVolumeGuid
	
	local localNegativeInfo = {

		originalVolumeGuid = WFCatFileSpec.getOriginalVolumeGuidFromDocValue( docValue ),
		originalRelativePath = WFCatFileSpec.getOriginalRelativePathFromDocValue( docValue ),
		proxyVolumeGuid = WFCatFileSpec.getProxyVolumeGuidFromDocValue( docValue ),
		proxyRelativePath = WFCatFileSpec.getProxyRelativePathFromDocValue( docValue )
		
	}

	assetInfo.localOriginalVolumeGuid = localNegativeInfo.originalVolumeGuid
	assetInfo.localProxyVolumeGuid = localNegativeInfo.proxyVolumeGuid
	
	local hasLocalOriginalUpdate = localNegativeInfo.originalVolumeGuid ~= previousLocalOriginalGuid 
	local hasLocalProxyUpdate = localNegativeInfo.proxyVolumeGuid ~= previousLocalProxyGuid
	
	return assetInfo, ( hasLocalOriginalUpdate or hasLocalProxyUpdate ) and localNegativeInfo

end

--============================================================================--
--[[!

	\namespace NmbDeletionBacklogUpdater
	
	\brief This namespace is used to monitor the doc store and update the
		Deletion Backlog database.
	
--]]

-- @mark NmbDeletionBacklogUpdater namespace

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

local NmbDeletionBacklogUpdater = {}

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

function NmbDeletionBacklogUpdater.scanForAssetUpdates( assetInfoCache, docValue )
	
	local docId = docValue._id
	local changeCounter = docValue._changeCounter
	
	if not isValidAssetDocument( docValue ) then
		return assetInfoCache, docId, changeCounter
	end
	
	local assetInfo = assetInfoCache[ docId ] or {
		localOriginalVolumeGuid = false,
		localProxyVolumeGuid  = false,
			-- `nil` is a valid value for these fields. Init'ing to false ensures the fields update on
			-- the first value change.
	}
	
	-- Check to see if there have been any changes to the local negative status.
	
	local maybeLocalNegativeInfo

	assetInfo, maybeLocalNegativeInfo = didLocalNegativeStatusChange( assetInfo, docValue )

	assetInfoCache[ docId ] = assetInfo

	return assetInfoCache, docId, changeCounter, maybeLocalNegativeInfo

end

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

function NmbDeletionBacklogUpdater.trackAssetUpdates( docStore, deletionBacklog, optBufferTime )

	check( 'WFRxDocStore', 'NmbDeletionBacklogImp', '?number' )

	local assetInfoCache = {}

	local localDocKey = 'deletionBacklogContinueFrom'

	local changeCounterStream = docStore
			:localDocValue( localDocKey )
			:pluck( 'continueFrom' )
		
	local updateDbSubscription = changeCounterStream
	
		:take( 1 )
	
		:flatMapLatest( function( changeCounter )
		
			changeCounter = changeCounter or 0
		
			return docStore
				:scannedFilteredMappedChangesFeedSince( 
						'NmbDeletionBacklogUpdater', 
						'scanForAssetUpdates', 
						assetInfoCache,
						changeCounter )
			
		end )
		
		:map( function( docId, changeCounter, maybeLocalNegativeInfo )
			
			return {
				docId = docId,
				changeCounter = changeCounter,
				maybeLocalNegativeInfo = maybeLocalNegativeInfo,
			}
			
		end )
		
		:bufferWithTimeOrCount( optBufferTime or 5, 100, require 'WFRxScheduler'.sharedScheduler() )
		
		:flatMap( function( bufferedResults ) 
			
			if WFCloseSupport.hasBeenOrWillBeClosed( deletionBacklog ) then
				return
			end
			
			local latestChangeCounter
			
			for _, row in ipairs( bufferedResults ) do
				
				local changeCounter = row.changeCounter
				local maybeLocalNegativeInfo = row.maybeLocalNegativeInfo

				if maybeLocalNegativeInfo then
				
					if maybeLocalNegativeInfo.originalVolumeGuid and maybeLocalNegativeInfo.originalRelativePath then
						
						deletionBacklog:removeFromDeletionBacklog( maybeLocalNegativeInfo.originalVolumeGuid, maybeLocalNegativeInfo.originalRelativePath )
								-- If the original has been previously added to the deletion backlog, clear it out
								-- so we don't delete it.
								
					end
					
					if maybeLocalNegativeInfo.proxyVolumeGuid and maybeLocalNegativeInfo.proxyRelativePath then
					
						deletionBacklog:removeFromDeletionBacklog( maybeLocalNegativeInfo.proxyVolumeGuid, maybeLocalNegativeInfo.proxyRelativePath )
								-- If the proxy has been previously added to the deletion backlog, clear it out
								-- so we don't delete it.

					end
				
				end
				
				if changeCounter then
				
					latestChangeCounter = changeCounter
					
				end
				
			end
			
			if latestChangeCounter then
			
				return docStore:setLocalDocValue {
						_id = localDocKey,
						continueFrom = latestChangeCounter,
					}
				
			else
			
				return Observable.just( true )
			
			end
			
		end )
		
		:subscribe()
		
	docStore:addCloseAction( function()
	
		updateDbSubscription:dispose()
		updateDbSubscription = nil
		
	end )
	
end

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

return NmbDeletionBacklogUpdater
