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

WFRxPersistentTimer.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2022 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'
local Observable = Rx.Observable

	-- WF.core.utils
local WFArguments = require 'WFArguments'
local KSDate = require 'KSDate'
local WFRxScheduler = require 'WFRxScheduler'

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

local check = assert( WFArguments.check )

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

--[[!

	\brief A function used to create a timer that persists across application
		sessions. The primary use case is for scheduling work that needs to happen
		every N hours/days within Lr, regardless of how many times Lr is launched.
		
		For instance, this code is used by the purge agent to schedule work that
		occurs once every 24 hours no matter how many times the application is quit
		and relaunched.

		Timers created using this function fire immediately, and then every N seconds
		afterwards (N is defined by the period parameter).
	
	\param docStore (docstore) A valid WFRxDocStore.
	\param identifier (string) A unique string used to identify the persistent timer.
	\param period (number) The delay between each value emitted.

	\return <code>Observable</code> An observable that emits true when the underlying
		timer emits.
		
--]]

return function( docStore, identifier, period )

	check( 'WFRxDocStore', '+string', 'number' )

	local localDocId = string.format( "WFRxPersistentTimer_%s", identifier )

	return docStore:localDocValue( localDocId )

		:map( function( localDocValue )

			local initialTimerDelay
		
			if localDocValue._empty or not localDocValue.fireTime then
			
				-- First time this identifier has been scheduled.
				
				initialTimerDelay = 0
				
			else
			
				-- We've previously scheduled this work, so adjust the timer.
			
				local scheduledFireTime = localDocValue.fireTime
			
				initialTimerDelay = math.max( 0, scheduledFireTime - KSDate.timeNow() )
				
			end
		
			return initialTimerDelay

		end )
		      
		:flatMap( function( initialTimerDelay )

			return Observable.timer( initialTimerDelay, period, WFRxScheduler.sharedScheduler() )
		
		end )
		
		:flatMap( function()

			-- Adjust the local doc to reflect the next scheduled emit.

			return docStore:setLocalDocValue( {
					_id = localDocId,
					fireTime = KSDate.timeNow() + period
				} )

		end )

end
