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

WFCatExportTaskTest.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2015 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.

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

	-- If ACR is not supported, disable test before we attempt to
	-- require WFAcr. (That will fail.)
if not require 'WFPlatformInfo'.hasACR then return {} end

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

	-- WF.core.os
local KSPathUtils = require 'KSPathUtils'
local WFFileUtils = require 'WFFileUtils'

	-- WF.core.self_test
local WFRxTestCase = require 'WFRxTestCase'

	-- WF.core.util
local KSTableUtils = require 'KSTableUtils'

	-- WF.oz_client.managed_catalog
local WFCatImport = require 'WFCatImport'
local WFCatExportTask = require 'WFCatExportTask'
local WFCatMockCatalog = require 'WFCatMockCatalog'
local MockPixelProviderProcessor = require 'MockPixelProviderProcessor'

local createFakeWFCatalog = WFCatMockCatalog.createFakeWFCatalog
local createPixelProcessorStream = MockPixelProviderProcessor.createPixelProcessorStream

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

local testDataPath = KSPathUtils.child( KSPathUtils.getStandardFilePath( 'testdata' ),
										"import-samples" )

local testDataFolder1 = KSPathUtils.child( testDataPath, "folder-1" )


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

local WFCatExportTaskTest = {}

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

local function getDocInfos( docs )

	if type( docs ) ~= 'table' then return docs end
	
	local infos = {}
	for i, doc in ipairs( docs ) do
		infos[ i ] = {
			id = doc._localId,
			fileName = KSTableUtils.derefOpt( doc, 'importSource', 'fileName' )
		}
	end

	return infos

end

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

local function importMultipleFiles( rxTest, testFilePaths )

	local wfCatalog = createFakeWFCatalog( rxTest )

	local assetIds = {}

	local imageArray = {}
	
	for i = 1, #testFilePaths do
	
		local testFilePath = testFilePaths[ i ]
		
		imageArray[ i ] = {
			filePath = testFilePath,
			width = 2048,
			height = 1024,
			xmpCameraRaw = '<xmp />',
			fileName = KSPathUtils.leafName( testFilePath ),
			fileSize = WFFileUtils.fileAttributes( testFilePath ).fileSize,
		}
	
	end

	rxTest:waitFor(
		WFCatImport.addImageArrayToCatalog( wfCatalog, nil, imageArray )
			:tap( function( result )
				assetIds[ #assetIds + 1 ] = result.localId
			end ) )

	assert( #assetIds == #testFilePaths, "AssetIds count doesn't match filePaths count." )

	return wfCatalog, assetIds
end

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

local function importSingleFile( rxTest, testFilePath )

	local wfCatalog, assetIds = importMultipleFiles( rxTest, { testFilePath } )
	
	return wfCatalog, assetIds[ 1 ]
	
end

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

function WFCatExportTaskTest.rxTestExportOneAssetOriginal( rxTest )

	rxTest:setTimeLimit( 10 )
	
	local exportPath = KSPathUtils.child( KSPathUtils.getStandardFilePath( 'temp' ), 'TestExportOneAssetOriginal' )
	pcall ( WFFileUtils.mkdir, exportPath )

	rxTest:finally( function()
		WFFileUtils.delete( exportPath )
	end )

	local testFilePath = KSPathUtils.child( testDataFolder1, "IMG_7763.jpg" )
	local wfCatalog, assetId = importSingleFile( rxTest, testFilePath )

	local exportTask = WFCatExportTask( wfCatalog, createPixelProcessorStream( rxTest, wfCatalog ) )
				
	local size = rxTest:observe( exportTask:queueSize() )
	size:expectData( 0 )

	local isBusy = rxTest:observe( exportTask:isBusy() )
	isBusy:expectData( false )
	
	local request = {
		id = assetId,
		settings = {
			format = 'original',
			plainOriginal = true,
			destinationFolder = exportPath,
		},
	}
	
	exportTask:exportAssets({ request })
	
	isBusy:expectData( true )
	isBusy:expectData( false )
	
	local outFilePath = KSPathUtils.child( request.settings.destinationFolder, "IMG_7763.jpg" )
	
	
	rxTest:expectEqual( 'file', WFFileUtils.exists( outFilePath ) )
	local testFileSize = KSTableUtils.derefOpt( WFFileUtils.fileAttributes( testFilePath ),
											'fileSize' )

	local exportedfileSize = KSTableUtils.derefOpt( WFFileUtils.fileAttributes( outFilePath ),
											'fileSize' )

	rxTest:expectEqual( testFileSize, exportedfileSize )
	
	exportTask:dispose()
	

end
--------------------------------------------------------------------------------

function WFCatExportTaskTest.rxTestBasicExportJpeg( rxTest )

	rxTest:setTimeLimit( 10 )
	
	local exportPath = KSPathUtils.child( KSPathUtils.getStandardFilePath( 'temp' ), 'TestBasicExportJpeg' )
	pcall ( WFFileUtils.mkdir, exportPath )

	rxTest:finally( function()
		WFFileUtils.delete( exportPath )
	end )

	local testFilePath = KSPathUtils.child( testDataFolder1, "ir-trees.dng" )
	local wfCatalog, assetId = importSingleFile( rxTest, testFilePath )

	local exportTask = WFCatExportTask( wfCatalog, createPixelProcessorStream( rxTest, wfCatalog ) )
				
	local size = rxTest:observe( exportTask:queueSize() )
	size:expectData( 0 )

	local isBusy = rxTest:observe( exportTask:isBusy() )
	isBusy:expectData( false )
	
	local request = {
		id = assetId,
		settings = {
			format = 'jpeg',
			destinationFolder = exportPath,
		},
	}
	
	exportTask:exportAssets({ request })
	
	isBusy:expectData( true )
	isBusy:expectDataWithinTime( 3, false )
	
	local outFilePath = KSPathUtils.child( request.settings.destinationFolder, "ir-trees.jpg" )
	
	
	rxTest:expectEqual( 'file', WFFileUtils.exists( outFilePath ) )
	
	exportTask:dispose()
	

end

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

function WFCatExportTaskTest.rxTestBasicExportTiff( rxTest )

	rxTest:setTimeLimit( 10 )
	
	local exportPath = KSPathUtils.child( KSPathUtils.getStandardFilePath( 'temp' ), 'TestBasicExportTiff' )
	pcall ( WFFileUtils.mkdir, exportPath )

	rxTest:finally( function()
		WFFileUtils.delete( exportPath )
	end )

	local testFilePath = KSPathUtils.child( testDataFolder1, "ir-trees.dng" )
	local wfCatalog, assetId = importSingleFile( rxTest, testFilePath )

	local exportTask = WFCatExportTask( wfCatalog, createPixelProcessorStream( rxTest, wfCatalog ) )
				
	local size = rxTest:observe( exportTask:queueSize() )
	size:expectData( 0 )

	local isBusy = rxTest:observe( exportTask:isBusy() )
	isBusy:expectData( false )
	
	local request = {
		id = assetId,
		settings = {
			format = 'tiff',
			destinationFolder = exportPath,
		},
	}
	
	exportTask:exportAssets({ request })
	
	isBusy:expectData( true )
	isBusy:expectDataWithinTime( 3, false )
	
	local outFilePath = KSPathUtils.child( request.settings.destinationFolder, "ir-trees.tif" )
	
	
	rxTest:expectEqual( 'file', WFFileUtils.exists( outFilePath ) )
	
	exportTask:dispose()
	

end

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

function WFCatExportTaskTest.rxTestBasicExportDng( rxTest )

	rxTest:setTimeLimit( 10 )
	
	local exportPath = KSPathUtils.child( KSPathUtils.getStandardFilePath( 'temp' ), 'TestBasicExportDng' )
	pcall ( WFFileUtils.mkdir, exportPath )

	rxTest:finally( function()
		WFFileUtils.delete( exportPath )
	end )

	local testFilePath = KSPathUtils.child( testDataFolder1, "ir-trees.dng" )
	local wfCatalog, assetId = importSingleFile( rxTest, testFilePath )

	local exportTask = WFCatExportTask( wfCatalog, createPixelProcessorStream( rxTest, wfCatalog ) )
				
	local size = rxTest:observe( exportTask:queueSize() )
	size:expectData( 0 )

	local isBusy = rxTest:observe( exportTask:isBusy() )
	isBusy:expectData( false )
	
	local request = {
		id = assetId,
		settings = {
			format = 'dng',
			destinationFolder = exportPath,
		},
	}
	
	exportTask:exportAssets({ request })
	
	isBusy:expectData( true )
	isBusy:expectDataWithinTime( 3, false )
	
	local outFilePath = KSPathUtils.child( request.settings.destinationFolder, "ir-trees.dng" )
	
	rxTest:expectEqual( 'file', WFFileUtils.exists( outFilePath ) )
	
	exportTask:dispose()
	

end

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

-- We removed rxTestExportOneAfterAnotherAssetOriginal since we don't export another request with same exportTask
-- Instead test to export multiple assets under same request
function WFCatExportTaskTest.rxTestExportMultipleAssetsOriginal( rxTest )

	rxTest:setTimeLimit( 30 )
	
	local exportPath = KSPathUtils.child( KSPathUtils.getStandardFilePath( 'temp' ), 'TestExportOneAfterAnotherAssetOriginal' )
	pcall ( WFFileUtils.mkdir, exportPath )
	
	rxTest:finally( function()
		WFFileUtils.delete( exportPath )
	end )
	
	local filePaths = {
		KSPathUtils.child( testDataFolder1, "IMG_7763.jpg" ),
		KSPathUtils.child( testDataFolder1, "ir-trees.dng" )
	}
	
	local wfCatalog, _ = importMultipleFiles( rxTest, filePaths )
	local docStore = wfCatalog:docStore()
	
	local assetInfos
	
	rxTest:expectSingleValue(

		docStore:changedDocs { fromChangeCounter = 1 }
			:map( getDocInfos )
			:tap(function( infos )
				assetInfos = infos
			end),

		':ignore:')
	
	local exportTask = WFCatExportTask( wfCatalog, createPixelProcessorStream( rxTest, wfCatalog ) )
				
	local size = rxTest:observe( exportTask:queueSize() )
	size:expectData( 0 )

	local isBusy = rxTest:observe( exportTask:isBusy() )
	isBusy:expectData( false )
	
	local requests = {
		{
			id = assetInfos[1].id,
			settings = {
				format = 'original',
				destinationFolder = exportPath,
			},
		},
		{
			id = assetInfos[2].id,
			settings = {
				format = 'original',
				destinationFolder = exportPath,
			},
		}
	}
	
	exportTask:exportAssets( requests )
	local exportProgress = exportTask:status()
	local progress = rxTest:observe( exportProgress )
	
	progress:expectDataWithinTime( 1,
		{
			processedCount = 0,
			description = "Exporting files",
			errorCount = 0,
			percentComplete = 0,
			totalCount = 2,
		} )
	
	progress:expectDataWithinTime( 5,
		{
			processedCount = 1,
			description = "Exporting files",
			errorCount = 0,
			percentComplete = 0.5,
			totalCount = 2,
			extraInfo = {
				id = assetInfos[1].id,
				success = true,
				data = {
					path = KSPathUtils.child( exportPath, assetInfos[1].fileName ),
				}
			}
		} )
		
	progress:expectDataWithinTime( 5,
		{
			processedCount = 2,
			description = "Exporting files",
			errorCount = 0,
			percentComplete = 1,
			totalCount = 2,
			extraInfo = {
				id = assetInfos[2].id,
				success = true,
				data = {
					path = KSPathUtils.child( exportPath, assetInfos[2].fileName ),
				}
			}
		} )
	progress:expectCompleted()
	
	exportTask:dispose()
	
end

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

function WFCatExportTaskTest.rxTestExportOneAssetIdInvalid( rxTest )

	rxTest:setTimeLimit( 10 )
	
	local exportPath = KSPathUtils.child( KSPathUtils.getStandardFilePath( 'temp' ), 'TestExportOneAssetIdInvalid' )
	pcall ( WFFileUtils.mkdir, exportPath )

	rxTest:finally( function()
		WFFileUtils.delete( exportPath )
	end )

	local wfCatalog = createFakeWFCatalog( rxTest )
	
	local exportTask = WFCatExportTask( wfCatalog, createPixelProcessorStream( rxTest, wfCatalog ) )
				
	local size = rxTest:observe( exportTask:queueSize() )
	size:expectData( 0 )

	local isBusy = rxTest:observe( exportTask:isBusy() )
	isBusy:expectData( false )
	
	local assetId = 123
	local request = {
		id = assetId,
		settings = {
			format = 'original',
			destinationFolder = exportPath,
		},
	}
	
	exportTask:exportAssets({ request })
	local exportProgress = exportTask:status()
	local progress = rxTest:observe( exportProgress )
	
	-- TOFIX [ashj 2/17/2016] If asset id is invalid, pixel provider
	-- sends the error code "SendNoDownloadableRenderOrBinary". Hence handling 
	-- it as "original_unavailable"
	
	progress:expectDataWithinTime( 5,
		{
			processedCount = 1,
			description = "Exporting files",
			errorCount = 1,
			percentComplete = 1,
			totalCount = 1,
			extraInfo = {
				id = request.id,
				success = false,
				error = 'invalid_asset_id',
				desc = assetId,
			}
		} )
		
	progress:expectCompleted()
	
	exportTask:dispose()

end

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

function WFCatExportTaskTest.rxTestExportOneAssetIdMissing( rxTest )

	rxTest:setTimeLimit( 10 )
	
	local exportPath = KSPathUtils.child( KSPathUtils.getStandardFilePath( 'temp' ), 'TestExportOneAssetIdMissin' )
	pcall ( WFFileUtils.mkdir, exportPath )

	rxTest:finally( function()
		WFFileUtils.delete( exportPath )
	end )

	local wfCatalog = createFakeWFCatalog( rxTest )
	
	local exportTask = WFCatExportTask( wfCatalog, createPixelProcessorStream( rxTest, wfCatalog ) )
				
	local size = rxTest:observe( exportTask:queueSize() )
	size:expectData( 0 )

	local isBusy = rxTest:observe( exportTask:isBusy() )
	isBusy:expectData( false )
	
	local request = {
		settings = {
			format = 'original',
			destinationFolder = exportPath,
		},
	}
	
	exportTask:exportAssets({ request })
	local exportProgress = exportTask:status()
	local progress = rxTest:observe( exportProgress )
	
	progress:expectDataWithinTime( 5,
		{
			processedCount = 1,
			description = "Exporting files",
			errorCount = 1,
			percentComplete = 1,
			totalCount = 1,
			extraInfo = {
				id = request.id,
				success = false,
				error = 'invalid_asset_id',
			}
		} )
	
	progress:expectCompleted()
	
	exportTask:dispose()

end

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

function WFCatExportTaskTest.rxTestExportOneAssetInvalidDestination( rxTest )

	rxTest:setTimeLimit( 10 )

	local testFilePath = KSPathUtils.child( testDataFolder1, "IMG_7763.jpg" )
	local wfCatalog, assetId = importSingleFile( rxTest, testFilePath )

	local exportTask = WFCatExportTask( wfCatalog, createPixelProcessorStream( rxTest, wfCatalog ) )
				
	local size = rxTest:observe( exportTask:queueSize() )
	size:expectData( 0 )

	local isBusy = rxTest:observe( exportTask:isBusy() )
	isBusy:expectData( false )
	
	local request = {
		id = assetId,
		settings = {
			format = 'original',
		},
	}
	
	exportTask:exportAssets({ request })
	local exportProgress = exportTask:status()

	local progress = rxTest:observe( exportProgress )

	--ashj: Though the onNext of WFProgressReporter is
	-- being called two times, we get notification
	-- only once in most of the cases, only latest 
	-- value will be received.

	-- jandrew [ 01/08/2016]: The reason you only sometimes get both notifications is because you're
	-- subscribing to the export progress *after* progress events have already fired. By default,
	-- the progress reporter class elides values to late subscribers ( we don't replay the full history
	-- of the progress ). If you need to report events through the progress reporter that MUST be
	-- delivered and must not be elided, then use the reportSuccessMustDeliver and reportErrorMustDeliver
	-- APIs.

	--[[progress:expectDataWithinTime( 1,
		{
			processedCount = 0,
			description = "Exporting files",
			errorCount = 0,
			percentComplete = 0,
			totalCount = 1,
		} )]]--
	
	progress:expectDataWithinTime( 3,
		{
			processedCount = 1,
			description = "Exporting files",
			errorCount = 1,
			percentComplete = 1,
			totalCount = 1,
			extraInfo = {
				id = request.id,
				success = false,
				error = 'invalid_destination',
				desc = 'IMG_7763.jpg',
			}
		} )
		
	
	progress:expectCompleted()
	
	exportTask:dispose()

end

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

function WFCatExportTaskTest.rxTestExportOneAssetInvalidFormat( rxTest )

	rxTest:setTimeLimit( 10 )
	
	local exportPath = KSPathUtils.child( KSPathUtils.getStandardFilePath( 'temp' ), 'TestExportOneAssetInvalidFormat' )
	pcall ( WFFileUtils.mkdir, exportPath )

	rxTest:finally( function()
		WFFileUtils.delete( exportPath )
	end )

	local testFilePath = KSPathUtils.child( testDataFolder1, "IMG_7763.jpg" )
	local wfCatalog, assetId = importSingleFile( rxTest, testFilePath )

	local exportTask = WFCatExportTask( wfCatalog, createPixelProcessorStream( rxTest, wfCatalog ) )
				
	local size = rxTest:observe( exportTask:queueSize() )
	size:expectData( 0 )

	local isBusy = rxTest:observe( exportTask:isBusy() )
	isBusy:expectData( false )
	
	local request = {
		id = assetId,
		settings = {
			format = 'raw',
			destinationFolder = exportPath,
		},
	}
	
	exportTask:exportAssets({ request })
	local exportProgress = exportTask:status()
	local progress = rxTest:observe( exportProgress )
	
	progress:expectDataWithinTime( 3,
		{
			processedCount = 1,
			description = "Exporting files",
			errorCount = 1,
			percentComplete = 1,
			totalCount = 1,
			extraInfo = {
				id = assetId,
				success = false,
				error = 'invalid_format',
				desc = 'IMG_7763.jpg',
			}
		} )
	progress:expectCompleted()
	
	exportTask:dispose()

end

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

function WFCatExportTaskTest.rxTestExportAssetWithoutOriginal( rxTest )

	rxTest:setTimeLimit( 10 )
	
	local exportPath = KSPathUtils.child( KSPathUtils.getStandardFilePath( 'temp' ), 'TestExportAssetWithoutOriginal' )
	pcall ( WFFileUtils.mkdir, exportPath )

	rxTest:finally( function()
		WFFileUtils.delete( exportPath )
	end )
	local testFilePath = KSPathUtils.child( testDataFolder1, "IMG_7763.jpg" )
	local wfCatalog, assetId = importSingleFile( rxTest, testFilePath )

	rxTest:expectSingleValue( wfCatalog:docStore():applyOverlay {
			_id = assetId,
			importSource = {
				willNotUploadMaster = true,
			},
			_localOnly = {
				files = {
					original = { _delete = true }
				}
			},
		}
	
	, ':ignore:')

	assert( assetId, "Docstore didn't fire doc change. Maybe import didnt succeed " )

	local exportTask = WFCatExportTask( wfCatalog, createPixelProcessorStream( rxTest, wfCatalog ) )
				
	local size = rxTest:observe( exportTask:queueSize() )
	size:expectData( 0 )

	local isBusy = rxTest:observe( exportTask:isBusy() )
	isBusy:expectData( false )
	
	local request = {
		id = assetId,
		settings = {
			format = 'original',
			destinationFolder = exportPath,
		},
	}
	
	exportTask:exportAssets({ request })
	local exportProgress = exportTask:status()
	local progress = rxTest:observe( exportProgress )
	
	progress:expectDataWithinTime( 3,
		{
			processedCount = 1,
			description = "Exporting files",
			errorCount = 1,
			percentComplete = 1,
			totalCount = 1,
			extraInfo = {
				id = assetId,
				success = false,
				error = 'original_unavailable',
				desc = 'IMG_7763.jpg',
			}
		} )
	progress:expectCompleted()
	
	exportTask:dispose()

end

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

return WFRxTestCase.wrapSuite( WFCatExportTaskTest )
