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

PixelProviderSharedTaskUtils.lua

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

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

------------------------------------------------------------------------------]]
	
	-- wf.core
local KSTableUtils = require 'KSTableUtils'
local WFFunctionUtils = require 'WFFunctionUtils'

	-- wf.oz_client
local WFCatUser = require 'WFCatUser'
local WFCatSpec = require 'WFCatSpec'
local WFCatalog = require 'WFCatalog'
	
	-- pixel provider
local PixelProviderTaskCache = require 'PixelProviderTaskCache'
local PixelPathProviderStateMachine = require 'PixelPathProviderStateMachine'

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

local WFFunctionUtils_reduce = assert( WFFunctionUtils.reduce,
			"WFFunctionUtils.reduce does not exist" )

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

local KSTableUtils_derefOpt = assert( KSTableUtils.derefOpt, 
										"KSTableUtils.derefOpt not defined" )

--------------------------------------------------------------------------------
-- key:
--
-- 	localAssetId
--
-- value:
-- 
-- { ozAssetId = assetId,
-- 		changeCounter = newChangeCounter,
-- 		revId = newRevId,
-- 		digest = newDigest,
-- 		croppedLongSide = newCroppedLongSide,
-- 		originalPath = newOriginalPath,
-- 		proxyPath = newProxyPath, 
-- 		renditions = newRenditions }
--
-- lifetime:
--
--  stays in cache as long as there is at least one localAssetId request in
--  scheduler queue
--------------------------------------------------------------------------------
	
local function makeBaseRenderInfoCache()

	return PixelProviderTaskCache.makeLocalAssetSimpleDataCache()

end

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

local NmbLocalRenditionDigest_isUniqueEmptySettingsForDownloadOnlyAsset =
		assert( require "NmbLocalRenditionDigest".isUniqueEmptySettingsForDownloadOnlyAsset,
				"NmbLocalRenditionDigest.isUniqueEmptySettingsForDownloadOnlyAsset is missing!" )

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

local function mustUseOzForRendersForCachedBaseRenderInfo( baseRenderInfo )
	
	if NmbLocalRenditionDigest_isUniqueEmptySettingsForDownloadOnlyAsset(
				baseRenderInfo.xmpCameraRaw ) then

		-- download only assets have unique but empty xmpCameraRaw values so
		-- that we can properly generate a rendition digest for them.
		-- 
		-- However, we should never render using that xmpCameraRaw, so we
		-- return true 

		return true

	end

	-- At this point, we have renderable xmpCameraRaw

	if not( baseRenderInfo.master or 
					baseRenderInfo.originalPath or 
					baseRenderInfo.proxyPath or 
					( type( baseRenderInfo.proxies ) == "table" and
						#baseRenderInfo.proxies > 0 ) ) then

		-- if all of the above checks failed, the baseRenderInfo
		-- contains neither local renderable source files nor 
		-- downloadable source file urls.
		--
		-- Return true so we don't try to render.

		return true

	end

	-- At this point we have renderable xmpCameraRaw and either
	-- a local source path or a downloadable source path
	--
	-- return false to indicate rendering is possible

	return false

end

--------------------------------------------------------------------------------
-- key:
--
-- 	localAssetId
--
-- value:
--
-- 	current dev settings for localAssetId
--
-- lifetime:
--
--  stays in cache as long as there is at least one localAssetId request in
--  scheduler queue.
--
--  TODO: bkruse 2015.11.03 we should consider refining this lifetime
-- 
--------------------------------------------------------------------------------
local function makeCurrRenderSettingsCache()

	return PixelProviderTaskCache.makeLocalAssetSimpleDataCache()

end

--------------------------------------------------------------------------------
-- key:
--
-- 	pixStream, localAssetId
--
-- value:
--
-- 	{ renditionPath, digest, renderSize, croppedLongSide, 
-- 		maybeDevSettings }
--
-- lifetime:
--
--  stays in cache until we send the renditionPath or enter one of EndStates
--  for pixStreamId, localAssetId
-- 
--------------------------------------------------------------------------------
local function makeActiveRenditionInfoCache()

	return PixelProviderTaskCache.makePerClientLocalAssetSimpleDataCache()

end

--------------------------------------------------------------------------------
-- key:
--
-- 	pixStream, localAssetId
--
-- value:
--
-- 	{ binaryPath, binarySize }
--
-- lifetime:
--
--  stays in cache until we send the binaryPath or enter one of EndStates
--  for pixStreamId, localAssetId
-- 
--------------------------------------------------------------------------------
local function makeLocalBinaryPathCache()

	return PixelProviderTaskCache.makePerClientLocalAssetSimpleDataCache()

end

--------------------------------------------------------------------------------
--[[!
	\brief Returns the proxy sub-type matching the asset info provided.

	\param baseRenditionInfo (table)

	\return proxy sub-type (string) Can be any of the following
		"2560"
		"720p"

	Currently it doesn't return 'panorama' in any case. This logic
	will have to evolve to take into account 'panorama' and any
	other case which is not handled right now.
]]--

local function getBinarySubtypeForProxy( baseRenditionInfo )

	-- TODO bkruse 2016.03.14 
	--
	-- what about panoramas?
	local subtype = baseRenditionInfo and baseRenditionInfo.subtype
	local isVideo = subtype == 'video' or subtype == 'deleted_video'

	return isVideo and '720p' or '2560'

end

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

local function ozRenditionNameToRenderSize( renditionName ) 
	
	local renditionSizeInPixels = tonumber( renditionName ) 
	
	if renditionSizeInPixels then 

		return renditionSizeInPixels

	end
	
	if renditionName == 'thumbnail2x' then

		return 320

	end
	
	if renditionName == 'panorama' then

		return 8192

	end

	if renditionName == "fullsize" then

		return "full"

	end

	return renditionName

end

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

local function largerStandardDownloadableSize( currMaxRenderSize, renditionInfo )

	local ozRenditionSize = KSTableUtils_derefOpt( renditionInfo, 'size' )

	if not currMaxRenderSize and ozRenditionSize == "fullsize" then

		return currMaxRenderSize

	end

	local renderSizeInPixels = 
			tonumber( ozRenditionNameToRenderSize( ozRenditionSize ) )

	if not renderSizeInPixels then

		return currMaxRenderSize

	end

	local currMaxSizeInPixels = tonumber( currMaxRenderSize ) or 0

	return renderSizeInPixels > currMaxSizeInPixels and
			renderSizeInPixels or currMaxSizeInPixels

end

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

local function getMaxDownloadableStandardRenderSize( baseRenderInfo )

	local renditions = 
			KSTableUtils_derefOpt( baseRenderInfo, 'renditions' ) or {}

	return WFFunctionUtils_reduce( 
				nil, largerStandardDownloadableSize, renditions )

end

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

local requestStatesThatWantMaximumDownloadableRenditionSize =
	KSTableUtils.mapArrayToSet( {

		assert( PixelPathProviderStateMachine.SendDataStates.MaybeSendLoupeRenditionPathFromInMemoryCache ),
		assert( PixelPathProviderStateMachine.PixelCacheCheckStates.NeedCheckForLoupeRenditionInCache ),

	} )

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

local function maybeUpdateRequestLongSideForMaximumDownloadableSize( 
				scheduler, pixStreamId, localAssetId, requestState, 
				baseRenderInfoCache )

	local maybeBaseRenderInfo =
			baseRenderInfoCache:peekCacheItem( localAssetId )

	if not requestStatesThatWantMaximumDownloadableRenditionSize[ requestState ] then

		return maybeBaseRenderInfo

	end

	local maxDownloadableRenderSize =
			maybeBaseRenderInfo and 
			getMaxDownloadableStandardRenderSize( maybeBaseRenderInfo )

	if maxDownloadableRenderSize then

		scheduler
			:maybeUpdateLongSide( 
				pixStreamId, localAssetId, maxDownloadableRenderSize )

	end

	return maybeBaseRenderInfo, maxDownloadableRenderSize

end

--------------------------------------------------------------------------------
--[[!
	\brief Returns the sub-type matching the binary type
	and asset info provided.

	\param localAssetId (string)

	\param ozBinaryType (string) Can be any of the
	following types
		"original"
		"proxy"
		"xmp_develop"

	\param baseRenderInfoCache (table)

	\return binary sub-type (string) 

]]--

local function getBinarySubtypeForBinaryType( localAssetId, 
												ozBinaryType,
												baseRenderInfoCache )

	if ozBinaryType == 'xmp_develop' then

		return 'xmp_develop'

	end
	
	if ozBinaryType == 'xmp_sidecar' then

		return 'xmp_sidecar'

	end

	if ozBinaryType == 'original' then

		return 'master'

	end

	local baseRenditionInfo = baseRenderInfoCache:peekCacheItem( localAssetId )

	return getBinarySubtypeForProxy( baseRenditionInfo )

end

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

local function makeNonSparseStringArray( ... )

	local ret = {}

	for i = 1, select( '#', ... ) do

		local maybeStr = select( i, ... )


		if type( maybeStr ) ~= "string" then

			error( string.format( 
					"parameter at position %s is not a string", i ) )

		end

		ret[ #ret + 1 ] = maybeStr

	end

	return ret

end

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

local function makeWFCatalog( serverBaseUrl, userId, userInfoCachePath,
								managedCatalogIdOrDoc, rootCatalogDataDir,
								catalogOptions )

	local wfCatUser = WFCatUser( serverBaseUrl, userId, userInfoCachePath )

	local wfCatSpec = WFCatSpec( wfCatUser, managedCatalogIdOrDoc )

	return WFCatalog( wfCatSpec, rootCatalogDataDir, catalogOptions )

end

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

return {

	makeBaseRenderInfoCache = makeBaseRenderInfoCache,

	mustUseOzForRendersForCachedBaseRenderInfo = 
		mustUseOzForRendersForCachedBaseRenderInfo,

	makeCurrRenderSettingsCache = makeCurrRenderSettingsCache,

	makeActiveRenditionInfoCache = makeActiveRenditionInfoCache,

	makeLocalBinaryPathCache = makeLocalBinaryPathCache,

	ozRenditionNameToRenderSize = ozRenditionNameToRenderSize,

	maybeUpdateRequestLongSideForMaximumDownloadableSize =
		maybeUpdateRequestLongSideForMaximumDownloadableSize,

	getBinarySubtypeForBinaryType = getBinarySubtypeForBinaryType,

	getBinarySubtypeForProxy = getBinarySubtypeForProxy,

	makeNonSparseStringArray = makeNonSparseStringArray,
	
	makeWFCatalog = makeWFCatalog,
}

