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

NmbCatalog.lua

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

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

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

	-- RxLua
local Rx = require 'Rx'

local KSTableUtils = require 'KSTableUtils'
local WFArguments = require 'WFArguments'
local WFCatalogBase = require 'WFCatalogBase'
local NmbDeletionBacklog = require 'NmbDeletionBacklog'
local WFObjectProxy = require 'WFObjectProxy'
local NmbFileMover = require 'NmbFileMover'
local WFCatStacksProcessor = require 'WFCatStacksProcessor'
local NmbAlbumsCache = require 'NmbAlbumsCache'
local NmbCatalogProfileCache = require 'NmbCatalogProfileCache'

local NmbSimpleDocStoreUpdater = require 'NmbSimpleDocStoreUpdater'
local NmbFileManagementSettings = require 'NmbFileManagementSettings'

local WFRxRunUntilDone = require 'WFRxRunUntilDone'

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

local check = assert( WFArguments.check )

local runUntilDone = assert( WFRxRunUntilDone )

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

local nmbCatalogPrototype = {
	
	WFCatalogBase,
		--superclass
	
	_initOptArgs = false,
		-- (table) optional args passed in at __init (needed for __inited)
		
	_deletionBacklog = false,
		-- (NmbDeletionBacklog)

	_volumeAgents = false,
		-- (table<WFCatVolumeAgent>) The Nimbus volume agents.
	
	_fileMover = false,
		-- (NmbFileMover) The file mover responsible for migrating assets
		-- when the original storage location changes.
	
	_docStoreUpdater = false,
		-- (NmbSimpleDocStoreUpdater) Allows for simple updating (format changes) of documents
		
	_stacksProcessor = false,
		-- (WFCatStacksProcessor) Processes incoming stacks to ensure they're formatted correctly
		-- for display
	
	_catalogProfileCache = false,
		-- (NmbCatalogProfileCache) Responsible for caching the profiles in a catalog
		-- in the catalog.
		
	_albumsCache = false,
		-- cache of albums data for this catalog. used by NmbAlbums to speed up 
		-- the user experience of albums based operations
	
	_connectorPublisher = false,
	
	class = {},
	
	_searchSchema = false,
	
}

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

--[[!
	\brief Creates a NmbCatalog.
	
	\param ozCatalogSpec (WFCatSpec) specification for the catalog user and catalogID
	\param rootCatalogPath (string) root directory under which to store catalog related files
	\param optArgs (table) optional args for doc store index store creation. These are in addition
			to any optional args allowed by WFCatalogBase
		- deletionBacklogPath -- path to deletion backlog db
]]--

function nmbCatalogPrototype:__init( ozCatalogSpec, rootCatalogPath, optArgs )
	
	check( 'NmbCatalog', 'WFCatSpec', 'string', '?table' )
	
	self._initOptArgs = optArgs or {}
	
	self._volumeAgents = {}
	
	-- these arguments are returned to be used in the superclass (WFCatalog) init
	return ozCatalogSpec, rootCatalogPath, optArgs
	
end

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

--[[ 
	\brief Completes initialization of the NmbCatalog after the superclass has been initialized
]]--
function nmbCatalogPrototype:__inited( )

	check( 'NmbCatalog' )
					
	local searchSchema = require 'WFCatSearchSchema'()
	
	require 'WFCatSearchHandler'.addSearchToSearchSchema( searchSchema ) 
	
	self._searchSchema = searchSchema

	require 'WFCatIdleDownloader'.addSearchToSearchSchema( self._searchSchema )

	if not self._initOptArgs.isSyncClientForProfileCatalog then

		-- Setup the Deletion Backlog: Note that it's safe to do this for every instance of
		-- NmbCatalog object, since the deletion backlog runs on a separate thread; it's the
		-- same as creating the doc store / index store for each NmbCatalog instance.

		local optDeletionBacklogPath = self._initOptArgs.deletionBacklogPath

		local deletionBacklog = NmbDeletionBacklog(
				self._wfCatFileSpec:docStorePath(),
				optDeletionBacklogPath or self._wfCatFileSpec:deletionBacklogPath(),
				self._initOptArgs )

		deletionBacklog:bringDeletionBacklogUpToDate():call( runUntilDone )

		self:setOwned {
			_deletionBacklog = deletionBacklog
		}

	
		if not self._initOptArgs.syncClientBaseInstance then
		
			-- Within LrD, the NmbCatalog object is created in two different places: Once in the user model,
			-- and once in the sync client thread. The following code should only be initialized when we
			-- create NmbCatalog object from the user model; it's not necessary for the following tasks
			-- to be set up more than once.
			
			local fileMover = NmbFileMover( self._docStore, self._indexStore, self._wfCatFileSpec, deletionBacklog, 
					NmbFileManagementSettings.keepAllOriginals(), NmbFileManagementSettings.keepAllProxies() )
			
			local docStoreUpdater = NmbSimpleDocStoreUpdater( self._docStore, self._indexStore, self._wfCatFileSpec )
			
			local stacksProcessor = WFCatStacksProcessor( self._docStore, self._indexStore )
			
			local catalogProfileCache = NmbCatalogProfileCache( self )
			
			self:setOwned {
				_docStoreUpdater = docStoreUpdater,
				_fileMover = fileMover,
				_stacksProcessor = stacksProcessor,
				_catalogProfileCache = catalogProfileCache
			}

		end

	end
	
end

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

function nmbCatalogPrototype:searchSchema()

	check( 'NmbCatalog' )
	return self._searchSchema

end

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

function nmbCatalogPrototype:getDeletionBacklog()

	check( 'NmbCatalog' )
	return self._deletionBacklog

end

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

function nmbCatalogPrototype:getVolumeAgentByVolumeGuid( volumeGuid )

	check( 'NmbCatalog', 'string' )
	return self._volumeAgents[ volumeGuid ]
	
end

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

function nmbCatalogPrototype:getFileMover()

	check( 'NmbCatalog' )
	return self._fileMover

end

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

function nmbCatalogPrototype:getDocStoreUpdater()

	check( 'NmbCatalog' )
	return self._docStoreUpdater

end

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

function nmbCatalogPrototype:addVolumeAgent( volumeAgent )

	check( 'NmbCatalog', 'WFCatVolumeAgent' )
	self._volumeAgents[ volumeAgent:getVolumeGuid() ] = volumeAgent

end

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

function nmbCatalogPrototype:getAllVolumeAgents()

	check( 'NmbCatalog' )
	return self._volumeAgents

end

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

function nmbCatalogPrototype:getAllVolumeAgentsAsArray()

	check( 'NmbCatalog' )

	local ret = {}

	for _, volumeAgent in pairs( self._volumeAgents ) do

		ret[ #ret + 1 ] = volumeAgent

	end

	return ret

end

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

function nmbCatalogPrototype:getCatalogProfileCache()

	check( 'NmbCatalog' )
	return self._catalogProfileCache

end

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

function nmbCatalogPrototype:albumsCache()

	check( 'NmbCatalog' )
	if not self._albumsCache then
		local albumsCache = NmbAlbumsCache( self )
		self:setOwned {
			_albumsCache = albumsCache
		}
	end
	return self._albumsCache

end

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

function nmbCatalogPrototype:overlayUniversalCatalogDocumentSetting( settingKey, settingValue )
	
	check( 'NmbCatalog', '+string' )
	local catalogId = self:ozCatalogSpec():catalogId()
	
	return self._docStore:docValue( catalogId )
		:map( function( maybeCatalogDoc )
			if maybeCatalogDoc._empty then
				error( "Catalog document missing from catalog" )
			end
			return maybeCatalogDoc
		end )
		:flatMap( function( catalogDoc )
	
			local overlay = {
				_id = catalogId,
				[ "settings" ] = {
					[ 'universal' ] = {
						[ settingKey ] = settingValue
					}
				},
			}
			--overlay = WFCatUtils.addUserUpdatedFields( overlay )
			
			return self._docStore:applyOverlay( overlay )
			
		end )
	
end

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

function nmbCatalogPrototype:getUniversalCatalogDocumentSetting( settingKey )
	
	check( 'NmbCatalog', '+string' )
	
	return self._docStore:ongoingDocValue( self:ozCatalogSpec():catalogId() )
		:map( function( maybeCatalogDoc )
			if maybeCatalogDoc._empty then
				return nil
			end
			return KSTableUtils.derefOpt( maybeCatalogDoc, 'settings', 'universal', settingKey )
		end )
		
end 

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

local NmbCatalog_class = Rx.Class( 'NmbCatalog', nmbCatalogPrototype )

return WFObjectProxy( 'WFCatalog', NmbCatalog_class, nil, true )
