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

NmbAcrMockWFCrContext.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2020 Adobe
All Rights Reserved.

NOTICE: All information contained herein is, and remains
the property of Adobe and its suppliers, if any. The intellectual
and technical concepts contained herein are proprietary to Adobe
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.

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

	-- RxLua
local Rx = require 'Rx'

	-- wf.core
local KSData = require 'KSData'
local KSPathUtils = require 'KSPathUtils'

	-- WF.core.rxlua
local WFRxScheduler = require 'WFRxScheduler'

	-- WF.imaging
local WFXmp = require 'WFXmp'

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

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

local mockReadMetadataResults = {}

local extensionToFormatMap = {
	dng = 'image/dng',
	jpg = 'image/jpeg',
	tif = 'image/tiff',
}

local function setMockReadMetadataResults( _, extension, speedRatings, pixelXDimension, pixelYDimension )

	local format = extension and extensionToFormatMap[ extension ] or "?"

	local metadata = WFXmp.WFXmp()

	metadata:set( WFXMLNS.dc, 'format', format )

	metadata:set( WFXMLNS.dc, 'rights', false )

	if speedRatings then
		metadata:setStringList( WFXMLNS.exif, "ISOSpeedRatings", { "50" } )
	end

	metadata:set( WFXMLNS.exif, 'PixelXDimension', pixelXDimension )
	metadata:set( WFXMLNS.exif, 'PixelYDimension', pixelYDimension )

	local xmp = tostring( metadata:serialize() )

	mockReadMetadataResults[ #mockReadMetadataResults + 1 ] = xmp

end

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

local WFCrContext = {

	_filePath = false,
		-- (string) path to the CR negative we're reading

	-- (string) path to the CR negative we're reading
	_xmpSidecarData = false,

	class = {
		setMockReadMetadataResults = setMockReadMetadataResults
	}

}

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

function WFCrContext:__init( filePath )

	self._filePath = filePath

end

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

function WFCrContext:readMetadata()

	local xmp

	if #mockReadMetadataResults > 0 then

		xmp = mockReadMetadataResults [ 1 ]
		table.remove( mockReadMetadataResults, 1 )

	else

		local extension = self._filePath:match( "%.([^%.]+)$" ):lower()

		local format = extension and extensionToFormatMap[ extension ] or "?"

		local metadata = WFXmp.WFXmp()

		metadata:set( WFXMLNS.dc, 'format', format )

		metadata:set( WFXMLNS.dc, 'rights', false )

		if extension == 'dng' then
			metadata:setStringList( WFXMLNS.exif, "ISOSpeedRatings", { "50" } )
			metadata:set( WFXMLNS.exif, 'PixelXDimension', 500 )
			metadata:set( WFXMLNS.exif, 'PixelYDimension', 334 )
		else
			metadata:set( WFXMLNS.exif, 'PixelXDimension', 200 )
			metadata:set( WFXMLNS.exif, 'PixelYDimension', 200 )
		end

		metadata:set( WFXMLNS.exif, 'GPSAltitude', '1153/64' )
		metadata:set( WFXMLNS.exif, 'GPSAltitudeRef', '0' )
		metadata:set( WFXMLNS.exif, 'GPSLatitude', '47,36.7028333N' )
		metadata:set( WFXMLNS.exif, 'GPSLongitude', '122,24.1805W' )

		metadata:set( WFXMLNS.xap, 'ModifyDate',  '2015-06-08T08:19:58' )

		xmp = tostring( metadata:serialize() )

	end

	return Rx.Observable.just( { 
		metadata = xmp,
		isRawFile = false,
		additionalInfo = {
			embeddedXmp = true,
			fileHeight = 2448,
			fileWidth = 3264,
			ExifDateTimeValue = {
				day = 8,
				hour = 8,
				minute = 19,
				month = 6,
				second = 58,
				year = 2015,
			}
		}
		} )
		:delay( .01, WFRxScheduler.sharedScheduler() )

end

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

function WFCrContext:render( settings, userOrientation, longSide, quality )

	if type( settings ) ~= "string" or settings == "" then
		return Rx.Observable.throw( "Invalid settings passed to WFCrContext:render()" )
	end

	if type( userOrientation ) ~= "number" or userOrientation ~= math.floor( userOrientation ) then
		return Rx.Observable.throw( "Invalid userOrientation passed to WFCrContext:render()" )
	end

	if type( longSide ) ~= "number" or longSide ~= math.floor( longSide ) then
		return Rx.Observable.throw( "Invalid longSide passed to WFCrContext:render()" )
	end

	if type( quality ) ~= "number" then
		return Rx.Observable.throw( "Invalid quality passed to WFCrContext:render()" )
	end

	-- return a userdata blob larger than 1000 to satisfy some tests, also add
	-- a delay so a test that aborts the render has a chance to discard the
	-- mocked render.

	local testData = string.rep('x', 4096 )
	return Rx.Observable.just( KSData.make( testData ) )
		:delay( .3, WFRxScheduler.sharedScheduler() )

end

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

function WFCrContext:renderFinalImageAndEncode( settings, outputParams, formatParams )

	if type( settings ) ~= "string" or settings == "" then
		return Rx.Observable.throw( "Invalid settings passed to WFCrContext:renderFinalImageAndEncode()" )
	end

	if type( outputParams ) ~= "table" then
		return Rx.Observable.throw( "Invalid outputParams passed to %s:renderFinalImageAndEncode()" )
	end

	if type( formatParams ) ~= "table" then
		return Rx.Observable.throw( "Invalid formatParams passed to %s:renderFinalImageAndEncode()" )
	end

	local testData = string.rep('y', 4096 )
	return Rx.Observable.just( KSData.make( testData ) ):delay( .3, WFRxScheduler.sharedScheduler() )
		:delay( .01, WFRxScheduler.sharedScheduler() )

end

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

local updateMetadata_xmpSidecarData

function WFCrContext:updateMetadata( settings )

	if type( settings ) ~= "string" or settings == "" then
		return Rx.Observable.throw( "Invalid settings passed to WFCrContext:updateMetadata()" )
	end

	
	local resultData
	
	if KSPathUtils.leafName( self._filePath ) == "IMG_9876.CR2" then

		updateMetadata_xmpSidecarData = updateMetadata_xmpSidecarData or string.rep( 'z', 256 )

		resultData = {
			isEmbedded = false,
			sidecarBlob = updateMetadata_xmpSidecarData and KSData.make( updateMetadata_xmpSidecarData ),
		}

		updateMetadata_xmpSidecarData = nil

	else

		resultData = { isEmbedded = true }

	end

	return Rx.Observable.just( resultData )
		:delay( .01, WFRxScheduler.sharedScheduler() )

end

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

function WFCrContext:mergeMetadata( settings, xmpSidecarData )

	if type( settings ) ~= "string" then
		return Rx.Observable.throw( "Invalid settings passed to WFCrContext:mergeMetadata()" )
	end

	-- Have the next call to updateMetadata return this sidecar data if present
	updateMetadata_xmpSidecarData = xmpSidecarData

	return Rx.Observable.just( { metadata = settings } )

end

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

function WFCrContext:close()

end

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

return Rx.Class 'WFCrContext'( WFCrContext )
