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

WFCatEditDefaults.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.

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

local KSTableUtils = require 'KSTableUtils'
local WFArguments = require 'WFArguments'
local WFTableMerge = require 'WFTableMerge'

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

local WFArguments_check = assert( WFArguments.check )

local derefOpt = assert( KSTableUtils.derefOpt )

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

local function waitForOngoingCatalogDocumentToBeAvailable( catalog )

	-- Catalog document will either already be available
	-- or will eventually become available when the metadata
	-- puller is able to get and save it. Wait till
	-- its done.
	return catalog:docStore():ongoingDocValue( catalog:ozCatalogId() )

		:filter( function( docValue )
			return docValue and not docValue._empty
		end )
end


local function waitForCatalogDocumentToBeAvailable( catalog )

	-- Catalog document will either already be available
	-- or will eventually become available when the metadata
	-- puller is able to get and save it. Wait till
	-- its done.
	return waitForOngoingCatalogDocumentToBeAvailable( catalog )

		:take( 1 )

end

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

local function createCamerasSectionOverlay( docValue, overlay )

	local deleteCamerasSection = false

	local cameras = derefOpt( docValue, "settings", "universal", "editDefaults", "cameras" ) or {}
	cameras = WFTableMerge.applyOverlay( cameras, overlay )
	if next( cameras ) == nil then
		deleteCamerasSection = true
	end

	if deleteCamerasSection then
		return {
			_delete = true
		}
	else
		return overlay
	end
end

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

-- @mark WFCatEditDefaults namespace

local WFCatEditDefaults = {}

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

--[[!
	\brief Get the EditDefaults enabled flag from the catalog doc.

	\return <code>Observable</code>. Resolves to either true or false.
	Will resolve to false if not available in catalog.

--]]

function WFCatEditDefaults.getEditDefaultsEnabled( catalog )

	WFArguments_check( "WFCatalog" )

	return waitForOngoingCatalogDocumentToBeAvailable( catalog )
		:map( function( docValue )

			local editDefaultsEnabled = derefOpt( docValue, "settings", "universal", "editDefaults", "enabled" )

			return not not editDefaultsEnabled

		end )

end

--[[!
	\brief Set the EditDefaults enabled flag in the catalog doc.

	\param enabled (boolean) true or false

	\return <code>Observable< string ></code> resolves with new catalog doc
		revision ID when the write completes. You may safely ignore this promise
--]]

function WFCatEditDefaults.setEditDefaultsEnabled( catalog, enabled )

	WFArguments_check( "WFCatalog", "boolean" )

	return waitForCatalogDocumentToBeAvailable( catalog )
		:flatMap( function( docValue )

			local id = docValue._id

			local camerasSectionOverlay = createCamerasSectionOverlay( docValue, {
					default = { _delete = true }
			} )

			local overlay = {
				_id = id,
				settings = {
					universal = {
						editDefaults = {
							cameras = camerasSectionOverlay,
							enabled = enabled,
						}
					}
				}
			}
			return catalog:docStore():applyOverlay( overlay )

		end )

end

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

--[[!
	\brief Get the default import preset from the catalog doc.

	\return <code>Observable</code>. Resolves to table containg the
	keys 'name' and 'digest' and the corresponding preset name and preset digest
	as values.

--]]

function WFCatEditDefaults.getDefaultImportPreset( catalog )

	WFArguments_check( "WFCatalog" )

	return waitForOngoingCatalogDocumentToBeAvailable( catalog )
		:map( function( docValue )

			local defaultImportPreset = derefOpt( docValue, "settings", "universal", "editDefaults", "cameras", "default" )

			return defaultImportPreset -- might be nil

		end )

end

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

--[[!
	\brief Set the the default import preset in the catalog doc.

	\param presetName (string) Name of preset.
	\param presetDigest (string) The corresponding digest of the preset.

	\return <code>Observable< string ></code> resolves with new catalog doc
		revision ID when the write completes. You may safely ignore this promise
--]]

function WFCatEditDefaults.setDefaultImportPreset( catalog, presetName, presetDigest )

	WFArguments_check( "WFCatalog", "+string", "+string" )

	return waitForCatalogDocumentToBeAvailable( catalog )
		:flatMap( function( docValue )

			local id = docValue._id

			local overlay = {
				_id = id,
				settings = {
					universal = {
						editDefaults = {
							cameras = {
								default = {
									name = presetName,
									digest = presetDigest
								}
							},
							enabled = true
						}
					}
				}
			}

			return catalog:docStore():applyOverlay( overlay )

		end )

end

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

-- @mark convenience APIs

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


function WFCatEditDefaults.getEditDefaultsEnabledWithImportPreset( catalog )

	WFArguments_check( "WFCatalog" )

	return waitForOngoingCatalogDocumentToBeAvailable( catalog )
		:map( function( docValue )

			local editDefaultsEnabled = derefOpt( docValue, "settings", "universal", "editDefaults", "enabled" )

			local defaultImportPreset = derefOpt( docValue, "settings", "universal", "editDefaults", "cameras", "default" )

			return {
				editDefaultsEnabled = not not editDefaultsEnabled,
				defaultImportPreset = defaultImportPreset -- might be nil
			}

		end )

end

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

-- @mark WFCatEditDefaults support for future (post June 2020) relase

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

--[[!
	\brief Get the import preset for a specific camera model from the catalog doc.

	\param modelName (string) The canonical camera model name.

	\return <code>Observable</code>. Resolves to table containg the
	keys 'name' and 'digest' and the corresponding preset name and preset digest
	as values.

--]]

function WFCatEditDefaults.getPresetForCameraModel( catalog, modelName )

	WFArguments_check( "WFCatalog", "+string" )

	return waitForOngoingCatalogDocumentToBeAvailable( catalog )
		:map( function( docValue )

			local preset = derefOpt( docValue, "settings", "universal", "editDefaults", "cameras", modelName, "default" )

			return preset -- might be nil

		end )

end

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

--[[!
	\brief Set the import preset for a specific camera model in the catalog doc.

	\param modelName (string) The canonical camera model name.
	\param presetName (string) Name of preset.
	\param presetDigest (string) The corresponding dihest of the preset.

	\return <code>Observable< string ></code> resolves with new catalog doc
		revision ID when the write completes. You may safely ignore this promise
--]]

function WFCatEditDefaults.setPresetForCameraModel( catalog, modelName, presetName, presetDigest )

	WFArguments_check( "WFCatalog", "+string", "+string", "+string" )

	-- modelName is the canonical name of the camera model, as supplied by
	-- an ACR negative. Is there a reasonable way to ckeck this? For now,
	-- accept all non-zero strings here

	return waitForCatalogDocumentToBeAvailable( catalog )
		:flatMap( function( docValue )

			local id = docValue._id

			-- editDefaults.enabled is a required key in an editDefaults section, ensure
			-- that it exists but preserve the value
			local editDefaultsEnabled = not not derefOpt( docValue, "settings", "universal", "editDefaults", "enabled" )

			local overlay = {
				_id = id,
				settings = {
					universal = {
						editDefaults = {
							cameras = {
								[ modelName ] = {
									default = {
										name = presetName,
										digest = presetDigest
									}
								}
							},
							enabled = editDefaultsEnabled
						}
					}
				}
			}

			return catalog:docStore():applyOverlay( overlay )

		end )

end

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

--[[!
	\brief Removes the import preset for a specific camera model from the catalog doc.

	\param modelName (string) The canonical camera model name.

	\return <code>Observable< string ></code> resolves with new catalog doc
		revision ID when the write completes. You may safely ignore this promise
--]]

function WFCatEditDefaults.removePresetForCameraModel( catalog, modelName )

	WFArguments_check( "WFCatalog", "+string" )

	return waitForCatalogDocumentToBeAvailable( catalog )
		:flatMap( function( docValue )

			local id = docValue._id

			local camerasSectionOverlay = createCamerasSectionOverlay( docValue, {
				[ modelName ] = {
					_delete = true
				}
			} )

			local overlay = {
				_id = id,
				settings = {
					universal = {
						editDefaults = {
							cameras = camerasSectionOverlay
						}
					}
				}
			}

			return catalog:docStore():applyOverlay( overlay )

		end )

end

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

--[[!
	\brief Lists the import presets by camera model.

	\return <code>Observable</code>. Resolves to table containg the the camera model
	names as keys. The values are tables with keys 'name' and 'digest' and the
	corresponding preset name and preset digest as values.

--]]

function WFCatEditDefaults.listPresetsByCameraModel( catalog )

	WFArguments_check( "WFCatalog" )

	return waitForOngoingCatalogDocumentToBeAvailable( catalog )
		:map( function( docValue )

			local models = derefOpt( docValue, "settings", "universal", "editDefaults", "cameras" )

			local listByCameraModel = {}

			if models and type ( models ) == 'table' then
				for k, v in pairs( models ) do
					if k ~= "default" then
						local preset = derefOpt( v, "default" )
						listByCameraModel[ k ] = preset
					end
				end
			end

			return listByCameraModel -- might be empty

		end )

end

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

return WFCatEditDefaults
