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

WFCatImportManifestCopiesProcessor.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.

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

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

	-- WF.oz_client.managed_catalog
local WFCatCopies = require 'WFCatCopies'

	-- WF.oz_client.managed_catalog.import
local WFCatImportManifestConstants = require 'WFCatImportManifestConstants'
local WFCatImportManifestProcessorBase = require 'WFCatImportManifestProcessorBase'

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

local WFCatImportManifestCopiesProcessor = {
	
	WFCatImportManifestProcessorBase,
}

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

function WFCatImportManifestCopiesProcessor:__init()

	self._stageName = WFCatImportManifestConstants.stageNames.copies

	self._messageCodeCompleted = WFCatImportManifestConstants.messages.copiesProcessingComplete.code
	self._messageCodeErrorCount = WFCatImportManifestConstants.messages.copiesProcessingErrorCount.code
	self._messageCodeGenericError = WFCatImportManifestConstants.messages.copiesProcessingError.code
end

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

function WFCatImportManifestCopiesProcessor:_reportSkippedEntries( messageHandler, masterImage, copies )
	
	local errData = {}
	
	for _, copy in ipairs( copies ) do	
		table.insert( errData, { masterImage, copy } )
	end
	
	self:_sendMessage( messageHandler, WFCatImportManifestConstants.messages.skippedCopies.code, errData )
	self:_updateError( messageHandler, #copies )
end

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

function WFCatImportManifestCopiesProcessor:_reportErrorEntries( messageHandler, masterImage, copies )

	local errData = {}
	
	for _, copy in ipairs( copies ) do	
		table.insert( errData, { masterImage, copy } )
	end
	
	self:_sendMessage( messageHandler, WFCatImportManifestConstants.messages.copiesImportError.code, errData )
	self:_updateError( messageHandler, #copies )
end

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

function WFCatImportManifestCopiesProcessor:_addStatus( manifestStatusDatabase, copies, status )
	
	local statusData = {}
	
	for _, copy in ipairs( copies ) do
		table.insert( statusData, {
			local_id = copy,
			status = status,
		} )
	end
	
	return manifestStatusDatabase:writeData( 'addCopyStatus', statusData )
		:ignoreElements()
	
end

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

function WFCatImportManifestCopiesProcessor:setup( catalog, manifestDatabase, manifestStatusDatabase, idCache, messageHandler )

	return self:WFCatImportManifestProcessorBase_setup( catalog, 
		manifestStatusDatabase, idCache, messageHandler, 'selectCopiesStatus' )

end

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

function WFCatImportManifestCopiesProcessor:processImpObservable( catalog, profileCatalog, wfCatSynchronizer, 
		manifestDatabase, manifestStatusDatabase, idCache, messageHandler )

	return self:_maybeSetCount( manifestDatabase, 'countCopies' )
	
		:flatMap( function ()
			return Observable.create( function( observer )
		
			local readSubscription = manifestDatabase:readData( 'selectCopies' )
				
				:subscribe( 
					
					-- OnNext
					function( results )
						-- Since this query returns all the results at once (not batched), we can set the copies in a loop...
						-- Otherwise, we may have to wait for one set to complete before starting the next if images in two
						-- batches have the same master image.
						
						-- Group the copies by the master asset, so we can process in bulk
						local copyGroups = {}
						local alreadyProcessedCount = 0
						
						for _, copyInfo in ipairs( results ) do
						
							if self:_isAlreadyProcessed( copyInfo.local_id ) then
								alreadyProcessedCount = alreadyProcessedCount + 1
							else
								local masterImage = copyInfo.masterImage
								
								copyGroups[ masterImage ] = copyGroups[ masterImage ] or {}
								table.insert( copyGroups[ masterImage ], copyInfo.local_id )
							end
						end
						
						-- Report progress of rows that have already been processed
						if alreadyProcessedCount > 0 then
							self:_updateAlreadyProcessed( messageHandler, alreadyProcessedCount )
						end

						for masterImage, group in pairs( copyGroups ) do
							observer:onNext( masterImage, group )
						end
						
					end, 
					
					--OnError
					function( err )
						observer:onError( err )
					end,
					
					--OnCompleted
					
					function( )
						observer:onCompleted( )
					end )

				return Rx.Disposable( function()
					
					if readSubscription then
						readSubscription:dispose()
						readSubscription = nil
					end
				end )
			end )
		end )
		
		:flatMap( function( masterImage, copyGroup )				
			
			local masterOzId = idCache:getOzIdForLocalId( WFCatImportManifestConstants.idCacheSets.assets, masterImage )
			if not masterOzId then
				self:_reportSkippedEntries( messageHandler, masterImage, copyGroup )
				return self:_addStatus( manifestStatusDatabase, copyGroup, WFCatImportManifestConstants.status.failure )
			end
			
			local copiesArray = {}
			local inProcessCopies = {}
			local skippedCopies = {}
			
			-- Add the master image, since Oz doesn't distinguish between master and copies
			table.insert( copiesArray, masterOzId )
			
			-- Add the copies
			for _, copyAssetId in ipairs( copyGroup ) do
				local copyOzId = idCache:getOzIdForLocalId( WFCatImportManifestConstants.idCacheSets.assets, copyAssetId )
				
				if copyOzId then
					table.insert( copiesArray, copyOzId )
					table.insert( inProcessCopies, copyAssetId )
				else
					skippedCopies[ #skippedCopies + 1 ] = copyAssetId
					self:_reportSkippedEntries( messageHandler, masterImage, { copyAssetId } )
				end
			end
			
			local updateStatusObservable
			if #skippedCopies > 0 then
				updateStatusObservable = self:_addStatus( manifestStatusDatabase, skippedCopies, WFCatImportManifestConstants.status.failure )
			else
				updateStatusObservable = Observable.just( {} )
			end
			
			return updateStatusObservable
				:defaultIfEmpty( nil )
				:flatMap( function()
					
					return WFCatCopies.setAssetsAsCopies( catalog, copiesArray )

						:flatMap( function()
						
							self:_updateSuccess( messageHandler, #inProcessCopies )
							return self:_addStatus( manifestStatusDatabase, inProcessCopies, WFCatImportManifestConstants.status.success )
							
						end )
						
						:catch( function( err )
							self:_reportErrorEntries( messageHandler, masterImage, inProcessCopies )
							return self:_addStatus( manifestStatusDatabase, inProcessCopies, WFCatImportManifestConstants.status.failure )
						end )
				end )
			
		end )
		:ignoreElements()
		:defaultIfEmpty( nil )
		:flatMap( function()
		
			local queryId = "countCopiesStatus"
			local dataType = WFCatImportManifestConstants.dataTypes.copies
			return self:_sendSummary( messageHandler, manifestStatusDatabase, queryId, dataType )
			
		end )
		:ignoreElements()
			-- Adding summary step to the chain and then explicitely
			-- ignoring elements to denote that we are not interested
			-- in the return values.
end

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

return Rx.Class 'WFCatImportManifestCopiesProcessor'( WFCatImportManifestCopiesProcessor )
