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

LrmCatProxies.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
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 KSData = require "KSData"
local WFFileUtils = require "WFFileUtils"
local KSPathUtils = require "KSPathUtils"
local KSPromises = require "KSPromises"
local KSReactive = require "KSReactive"
local KSTableUtils = require 'KSTableUtils'
local OzCatalogUploadStatus = require "OzCatalogUploadStatus"

local OzCatHelperFns = require "OzCatHelperFns"
local OzEpoch = require "OzEpoch"

local WFOzRenditionServerUtils = require 'WFOzRenditionServerUtils'
local WFCapabilities = require 'WFCapabilities'

local WFArguments = require 'WFArguments'
local WFCatTrashUtils = require 'WFCatTrashUtils'

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

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

local kDefaultProxySize = 2048
	-- Read this from somewhere?
	-- NOTE: Lots of places in the code encode this as being 2048. Some of those
	-- are really just about the link name but we're way too fuzzy about this.

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

local OzCatHelperFns_nilP = assert( OzCatHelperFns.nilP )
local OzCatHelperFns_progressIncompleteB = assert( OzCatHelperFns.progressIncompleteB )
local OzCatHelperFns_DISABLE_MOST_FETCHES = OzCatHelperFns.DISABLE_MOST_FETCHES
local OzCatHelperFns_processHttpRequestResult = assert( OzCatHelperFns.processHttpRequestResult )
local WFOzRenditionServerUtils_touchRendition = assert( WFOzRenditionServerUtils.touchRendition )
local OzEpoch_cacheEpochB = OzEpoch.cacheEpochB

-- @mark LrmCatProxies class

local ProxyMethods = {}

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

local function downloadAndCacheProxyPathP( catalog, proxyUrl, photoId, imageInfo, proxySize, priority )
	
	local optArgs = {
		requestPriority = priority
	}
	
	local resultP = catalog:getBinaryP( proxyUrl, optArgs )
	
	resultP = resultP:observeP( function( status, data, headers )
	
		OzCatHelperFns_processHttpRequestResult( catalog, status, data, headers )
		
	end )
	
	local resultPP = KSPromises.callP( function( proxyData, originalsFolderDocuments )
		
			local captureDate = imageInfo.captureDate:sub( 1, 10 )
			
			-- FIXME [scouten 2012-02-07]: Should move instances of this folder path logic into one place
			local subPath = KSPathUtils.child( captureDate:sub( 1, 4 ), captureDate:sub( 1, 7 ) ) -- yyyy, yyyy-mm
			KSPathUtils.child( subPath, captureDate ) -- yyyy-mm-dd
						
			local folder
			
			local useDocumentsFolderForProxies = WFCapabilities.getCapability(
												'WFOzAppConfig.useDocumentsFolderForProxies' ) or false
				
			local parentFolder = originalsFolderDocuments
			
			folder = KSPathUtils.child( parentFolder, subPath )
							
			WFFileUtils.mkdir( folder )
			
			local leafName = OzCatHelperFns.importSourceFileName( imageInfo )
		
			if not leafName then
				leafName = imageInfo.captureDate:sub( 12 ):gsub( '[:Z]', '' ) .. "_proxy.dng"
			else
				leafName = leafName:gsub( '\.[^.]*$' , '_proxy.dng' )
			end
			
			--debug.print( folder, leafName )
			
			local destPath = KSPathUtils.child( folder, leafName )

			destPath = KSData.saveToUniquelyNamedFile( proxyData, destPath )
			
			if useDocumentsFolderForProxies then
				WFFileUtils.setDoNotBackUpFlag( destPath )
			end

			local dataSize = KSData.length( proxyData )
			
			local cacheEpochB = OzEpoch_cacheEpochB( catalog )
			local epochNow = cacheEpochB:valueNow()
			cacheEpochB:close()
			
			local ozUrl = KSTableUtils.derefOpt( imageInfo, "_serverProvidedMetadata", "links",
							string.format( "/rels/proxy_type/%i", proxySize ), "href" )
			
			local proxy = {
				filePath = destPath,
				ozUrl = ozUrl,
				size = dataSize,
				epoch = epochNow,
			}
			
			local overlay = {
				_localOnly = {
					proxy = proxy,
				},
			}
			
			proxyData:close()
			
			return catalog:docStore():applyOverlayToDocumentP( {
				docType = 'asset',
				docId = photoId,
				overlay = overlay,
			} )
			
			:mapDataP( function()
			
				return 'data', destPath
				
			end )
			
		end, resultP, catalog:getOriginalsDocumentsFolderP() )
	
	return resultPP
	
end

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

--[[!
	\brief Retrieves the local path of a proxy photo document,
	and optionally downloads the asset itself.
 
	\param photoId (string) The asset's unique ID.
	\param doNotFetch (optional, boolean) When true, do not retrieve the asset.
	
	\return <code>P < string ></code>, <code>B < number ></code>
		A Promise object that resolves on completion to the
		path of the downloaded asset, or to nil if the asset has not been
		previously downloaded and has not been fetched by this call.
]]--

function ProxyMethods.proxyDataPathP( catalog, photoId, doNotFetch, proxySize, priority )
	
	WFArguments.check( 'OzCatalogService', 'string', 'boolean', 'number', 'number' )
	
	return ProxyMethods.proxyDataPathP_v2(
		catalog,
		photoId,
		doNotFetch and 'no_fetch' or 'fetch',
		proxySize, priority )
end

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

--[[!
	\brief Retrieves the local path of a proxy photo document,
	and optionally downloads the asset itself.
 
	\param photoId (string) The asset's unique ID.
	\param fetchPolicy (string) no_fetch, fetch, or generate.
	
	\return <code>P < string ></code>, <code>B < number ></code>
		A Promise object that resolves on completion to the
		path of the downloaded asset, or to nil if the asset has not been
		previously downloaded and has not been fetched by this call.
]]--

function ProxyMethods.proxyDataPathP_v2( catalog, photoId, fetchPolicy, proxySize, priority )

	if fetchPolicy ~= 'fetch' and fetchPolicy ~= 'generate' and fetchPolicy ~= 'no_fetch' then
		return KSPromises.resolvedPromiseP( 'error', "Unknown fetch policy" )
	end

	proxySize = proxySize or kDefaultProxySize
	
	if OzCatHelperFns_DISABLE_MOST_FETCHES or not photoId then
		return OzCatHelperFns_nilP
	end
	
	local docValueOnceP = catalog:docStore():docValueOnceP( 'asset', photoId )

	local currentProgressB = KSReactive.variableB( nil )
	
	local progressB = currentProgressB:mapSwitchB( function( progressB )
		if progressB then
			return progressB
		else
			return OzCatHelperFns_progressIncompleteB
		end
	end )

	local resultP = docValueOnceP:mapDataP( function( status, docValue )
	
		if not docValue then
			return 'data', nil -- or is this an error state, too?
		end
		
		if not OzCatalogUploadStatus.assetProxyIsValid( docValue, proxySize ) then
			-- FIXME [sdaniel 2012-02-07]: Request Oz to generate a proxy
		end
		
		-- First preference: Use proxy that's already stored locally.
		
		local localPath
		
		
		localPath = docValue
					and docValue._localOnly
					and docValue._localOnly.proxy
					and docValue._localOnly.proxy.filePath

		localPath = OzCatalogUploadStatus.checkAndCorrectLocalPath( localPath )
		
		if localPath and WFFileUtils.exists( localPath ) then
			WFOzRenditionServerUtils_touchRendition( catalog:docStore(), OzEpoch_cacheEpochB( catalog ),
													 photoId, 'proxy', docValue )
			return 'data', localPath
		end

		if fetchPolicy == 'no_fetch' then
			return 'data', nil
		end
		
		local function getProxyForUrlP( ozUrl )
		
			return downloadAndCacheProxyPathP( catalog, ozUrl, photoId, docValue, proxySize, priority )
		
		end
		
		-- Second preference: Download from Oz.
		
		local ozUrl = KSTableUtils.derefOpt( docValue, "_serverProvidedMetadata", "links", string.format( "/rels/proxy_type/%i", proxySize ), "href" )

		-- another preference: Fetch url from trash section of localOnly
		if not ozUrl then

			-- If OzUrl is not present in spm/links, It can happen for restored assets in expired account state or paused sync state, then fetch it from localOnly section

			local proxyLinkKey = '/rels/proxy_type/' .. proxySize
			local WFCatTrashUtils_getOriginalAssetUrlForLinkKey = assert( WFCatTrashUtils.getOriginalAssetUrlForLinkKey )
			local proxyLink = WFCatTrashUtils_getOriginalAssetUrlForLinkKey( docValue, proxyLinkKey )

			ozUrl = proxyLink

		end

		if ozUrl then
			return getProxyForUrlP( ozUrl )
		end
		
		-- Now try searching through the links for an appropriate proxy.
		
		local links = KSTableUtils.derefOpt( docValue, "_serverProvidedMetadata", "links" )
		
		if links then
		
			local bestUrl
			local bestBadness = 1000000
			
			for key, entry in pairs( links ) do
			
				local thisUrl = entry.href
				
				if thisUrl then
			
					local size = string.match( key, "^/rels/proxy_type/(%d+)$" )
					
					local thisBadness
					
					if size then
						size = tonumber( size )
						if size <= 0 then
							-- do nothing
						elseif size <= proxySize then
							thisBadness = math.pow( proxySize / size, 2 )
						else
							thisBadness = size / proxySize
						end
					end
					
					if thisBadness and thisBadness < bestBadness then
						bestBadness = thisBadness
						bestUrl = thisUrl
					end
					
				end
			
			end
			
			if bestUrl then
				return getProxyForUrlP( bestUrl )
			end
		
		end
		
		return 'error', "Proxy can not be found"
			-- FIXME [scouten 2011-07-25]: Does this need to be localized?
	
	end )
	
	return resultP, progressB

end

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

return ProxyMethods
