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

NmbCatalogProfileCache.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2018 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.

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

local Rx = require 'Rx'
local Observable = Rx.Observable

local KSTableUtils = require 'KSTableUtils'

local WFCloseSupport = require 'WFCloseSupport'
local WFLogger = require 'WFLogger'

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

local logger = WFLogger( "NmbCatalogProfileCache" )
local QUERY_CALM_INTERVAL = 30 -- In secs. Arbitrary value.

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

local function getCameraProfileDigestModelKey( cameraProfileDigest, cameraModel )
	return string.lower( string.format( "%s_%s", cameraProfileDigest, cameraModel ) )
end

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

local function logErrorForStreamNamed( streamName )

	return function( err )
		logger:errorf( "Stream: %s ended with error: %s",
								streamName, err )
	end
	
end
--------------------------------------------------------------------------------

local function customCameraProfilesStream( self )

	local columnCount = 6
	local sql = [[ SELECT docId, cameraProfileUniqueID, cameraProfileDigest, 
		cameraModel, filename, href
		FROM 
			customCameraProfiles ]]

	return self._catalog:indexStore():query {
			sql = sql,
			quiesceUntilUpToDate = true,
			calm = 10,
		}
		:flatMap( function( results )
		
			-- Got new results
				
			local cameraProfileDigestModelToInfoMap = {}
			local cameraProfileUUIDToKeyMap = {}
			local hrefToInfoMap = {}
		
			return Observable.from( results )
			
				:map( function( result )
					
					local docId, cameraProfileUniqueID, cameraProfileDigest, 
						cameraModel, filename, href = unpack( result, 1, columnCount )
					
					local key = getCameraProfileDigestModelKey( cameraProfileDigest, 
						cameraModel )
					
					local info = {
						docId = docId,
						filename = filename,
						href = href,
					}
					
					cameraProfileDigestModelToInfoMap[ key ] = info
					
					cameraProfileUUIDToKeyMap[ string.lower( cameraProfileUniqueID ) ] = info
					
					if href then
						hrefToInfoMap[ href ] = info
					end

					return info
				end )
				
				:catch( function( err )
					logger:errorf( "Error while fetching custom camera profiles:%s", err )
					return Observable.just()
				end )
				
				:tapOnCompleted( function()
					self._customProfileInfoStream:onNext( 
						cameraProfileDigestModelToInfoMap, cameraProfileUUIDToKeyMap, hrefToInfoMap )
				end )
				
			end )
end

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

local function listenForCameraModels( self )

	local cameraModelsQuery = self._catalog:indexStore():query {
		sql = [[ SELECT DISTINCT( cameraModel ) FROM cameraModelsInUse ]],
		quiesceUntilUpToDate = true,
		calm = QUERY_CALM_INTERVAL,
	}

	return cameraModelsQuery
		
		:map( function( queryResult )
			
			local numItems = queryResult and #queryResult
			if numItems > 0 then
			
				return KSTableUtils.flatten( queryResult )
			end
			
			return {}
		end )
		
		:tap( function( modelList )
			
			self._cameraModelsInUseSubject:onNext( modelList )
		end )
		
end

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

local NmbCatalogProfileCache = {
	_catalog = false,
	_compositeSubscription = false,
	_customProfileInfoStream = false,
	_cameraModelsInUseSubject = false,
	
	WFCloseSupport.addCloseSupportMethods,
}

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

function NmbCatalogProfileCache:__init( catalog )
	self._catalog = catalog
	self._customProfileInfoStream = Rx.ReplaySubject( 1 )
	local customProfileInfoSubscription = customCameraProfilesStream( self )
		:subscribeOnError( logErrorForStreamNamed( "customCameraProfilesStream" ))
	
	self._cameraModelsInUseSubject = Rx.ReplaySubject( 1 )
	local modelsInUseSubscription = 
		listenForCameraModels( self )
			:subscribeOnError( logErrorForStreamNamed( "cameraModelStream" ))
	
	self._compositeSubscription = Rx.CompositeDisposable( customProfileInfoSubscription, modelsInUseSubscription )
end

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

function NmbCatalogProfileCache:close()
	if self._customProfileInfoStream then
		self._customProfileInfoStream:onCompleted()
		self._customProfileInfoStream = nil
	end
	
	if self._cameraModelsInUseSubject then
		self._cameraModelsInUseSubject:onCompleted()
		self._cameraModelsInUseSubject = nil
	end
	
	if self._compositeSubscription then
		self._compositeSubscription:dispose()
		self._compositeSubscription = nil
	end
end

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

function NmbCatalogProfileCache:getHrefAndFileNameForProfileUUID( cameraProfileUUID )
	
	return self._customProfileInfoStream
		:take( 1 )
		:map( function( cameraProfileDigestModelToInfoMap, cameraProfileUUIDToKeyMap )
			local info = cameraProfileUUIDToKeyMap[ cameraProfileUUID ]
			if info then
				return info.filename, info.href
			end
		end )
end

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

function NmbCatalogProfileCache:getHrefAndFileNameForProfileDigestModel( cameraProfileDigest, cameraModel )
	
	return self._customProfileInfoStream
		:take( 1 )
		:map( function( cameraProfileDigestModelToInfoMap, cameraProfileUUIDToKeyMap )
			local key = getCameraProfileDigestModelKey( cameraProfileDigest, 
						cameraModel )
			local info = cameraProfileDigestModelToInfoMap[ key ]
			if info then
				return info.filename, info.href
			end
		end )
end

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

function NmbCatalogProfileCache:getInfoForHref( href )
	
	return self._customProfileInfoStream
		:take( 1 )
		:map( function( _, _, hrefInfoMap )
			return hrefInfoMap[ href ]
		end )
end

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

function NmbCatalogProfileCache:getCameraModelsInUseStream()

	return self._cameraModelsInUseSubject
	
end

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

return Rx.Class 'NmbCatalogProfileCache'( NmbCatalogProfileCache )
