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

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.

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

	-- wichitafoundation.core.utils
local KSTableUtils = require 'KSTableUtils'

local WFCrypto = require "WFCrypto"

	-- Lrmobile_models
local LrmWFCapabilities = require 'LrmWFCapabilities'

local derefOpt = assert( KSTableUtils.derefOpt )

local ozLinkNameForOzRenditionName =
	assert( LrmWFCapabilities.ozLinkNameForRenditionNameTable )
	
--==============================================================================

local LriOzRenditionServerUtils = {}

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

local function isAssetMetadataUploadedToOz( docValue )

	local spm = docValue._serverProvidedMetadata
	
	if spm then
	
		local revId = docValue._revId
		
		local revIds = spm.revision_ids
		
		if revIds then
		
			local cnt = #revIds
			
			for i = cnt, 1, -1 do
				
				local ozRevId = revIds[ i ]
				if revId == ozRevId then
					return true
				end
				
			end
			
		end
		
	end
	
	return false
	
end

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

local function isValidXmpCameraRaw( xmpCameraRaw )
	-- SPAM [matthewj 2016-08-08]: This isn't a rigorous check of the xmpCameraRaw, but it should catch
	-- the most egregious incorrect xmpCameraRaw. xmpCameraRaw can be either a string with the xmp in it
	-- or a table containing the sha256 of the xmp string for external xmp handling
	local xmpCameraRawType = type( xmpCameraRaw )

	if xmpCameraRawType == 'table' then

		return xmpCameraRaw.sha256 ~= nil

	end

	return xmpCameraRawType == 'string'

end

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

function LriOzRenditionServerUtils.renditionContentId( docValue )

	local xmpCameraRaw = derefOpt( docValue, "develop", "xmpCameraRaw" )

	local userOrientation = derefOpt( docValue, "develop", "userOrientation" )

	-- SPAM [matthewj 2015-12-21]: Ran into issues where the xmpCameraRaw
	-- contained an invalid, non-string value (the image's width value, in
	-- fact) and the md5 calculation would then blow up. So if it's nil or not
	-- a string, then use the default <xmp />

	local defaultXmp = "<xmp />"
		
	if docValue._spaceId then

		-- For all shared-with-you assets, we must uniqify the default xmp string
		-- by embedding the revision ID as a comment. This allows the pixel provider
		-- to correctly invalidate stale renditions when Oz updates the rendition links.

		local uniqueId = docValue._revId or docValue._newRevId
		
		defaultXmp = string.format( "<xmp><--%s--></xmp>", uniqueId )
		
	end

	xmpCameraRaw = isValidXmpCameraRaw( xmpCameraRaw ) and xmpCameraRaw or defaultXmp

	local xmpCameraRawForDigest = type( xmpCameraRaw ) == 'table'
								and xmpCameraRaw.sha256
								or xmpCameraRaw

	-- Include SHA256 of the parent binary used to create the renders so that we will
	-- generate new renders when the binary's SHA256 changes due to destructive edits.

	local assetSha256 = derefOpt( docValue, 'importSource', 'sha256' )

	if not assetSha256 then
		-- importSource.sha256 may be missing in rare cases, fall back
		-- to importSource.importTimestamp.
		-- LriOS: see THAssetUtils::GetRenditionContentId()
		assetSha256 = derefOpt( docValue, 'importSource', 'importTimestamp' )
	end

	-- Include the orientation in the digest so changes to it will kick off new renders.

	local compositeDevSettingsForDigest =
			string.format( "%s%s%s",
					xmpCameraRawForDigest,
					userOrientation or 1,
					assetSha256 or '' )

	return WFCrypto.MD5.digest( compositeDevSettingsForDigest )

end

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

function LriOzRenditionServerUtils.shouldDownloadOzRendition( docValue, ozRenditionName )


	-- If we're still waiting for docValue, punt for now.

	if not docValue then
		return false
	end

	-- Is local version current? If so, nothing else matters.
	
	local localDescription = derefOpt( docValue, '_localOnly', 'files', ozRenditionName )
	
	-- Extract the revision ID from the server link for this rendition.
	
	local ozLinkName = ozLinkNameForOzRenditionName[ ozRenditionName ]

	local serverRevisionId = derefOpt( docValue,
									'_serverProvidedMetadata',
									'links',
									ozLinkName,
									'href' )

	local serverRevisionInvalid = derefOpt( docValue,
										'_serverProvidedMetadata',
										'links',
										ozLinkName,
										'invalid' )
			
	if not serverRevisionId then
		return false
	end
	
	if serverRevisionId then
		-- TODO [arahn 2013-05-29]: WHY are we splitting apart the URL like this?
		-- we could just use the renditionUrl in its entirety to decide
		-- if the local rendition matches.  see StopTheRenditionInsanity elsewhere
		-- in this file.
		serverRevisionId = serverRevisionId:match( '([0-9a-f]+)%/renditions%/([0-9a-f]+)$' )
	end

	-- new style - use contentId
	if localDescription	and localDescription.contentId then

		if ( localDescription.contentId ~= LriOzRenditionServerUtils.renditionContentId( docValue )
			and isAssetMetadataUploadedToOz( docValue ) )
			and ( not serverRevisionInvalid )
		then
			return true
		end

		return false
	end

	-- Local isn't current: Download version from Oz unless Oz thinks it's invalid.
	
	local serverLinks = derefOpt( docValue, '_serverProvidedMetadata', 'links' )
	local serverDescription = derefOpt( serverLinks, ozLinkName )
	
	local result = serverDescription and not serverDescription.invalid

	return result

end

return LriOzRenditionServerUtils
