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

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 NmbMRUDatabase = require 'NmbMRUDatabase'
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 check = assert( WFArguments.check )

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

local nmbCatalogPrototype = {
	
	WFCatalogBase,
		--superclass
	
	_initOptArgs = false,
		-- (table) optional args passed in at __init (needed for __inited)
		
	_mruDatabase = false,
		-- (NmbMRUDatabase) Keep track of recently accessed files and assets that 
		-- need to be deleted from disk.

	_volumeAgents = false,
		-- (table<NmbVolumeAgent>) 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
		- fileAccessDbPath -- path to files access 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 )
	
	local optFileAccessDbPath = self._initOptArgs.fileAccessDbPath
	local optIndexSpecScript = self._initOptArgs.indexSpecScript
	
	local mruDatabase = NmbMRUDatabase( self._wfCatFileSpec:docStorePath(),
										optIndexSpecScript or 'WFCatIndexDefinitions.lua',
										optFileAccessDbPath or self._wfCatFileSpec:fileAccessDbPath(),
										self._initOptArgs)
	
	self:setOwned {
		_mruDatabase = mruDatabase,
	}
	
	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. Note that mruDatabase is initialized more than once which
		-- is okay because it runs in a separate thread (and therefore constructing an instance
		-- of the mru DB will reuse the existing thread, similar to the doc and index stores).
	
		local fileMover = NmbFileMover( self._docStore, self._indexStore, self._wfCatFileSpec, mruDatabase, 
				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

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

function nmbCatalogPrototype:searchSchema()

	check( 'NmbCatalog' )
	return self._searchSchema

end

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

function nmbCatalogPrototype:fileAccessDb()

	check( 'NmbCatalog' )
	return self._mruDatabase

end

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

function nmbCatalogPrototype:mruDatabase()

	check( 'NmbCatalog' )
	return self._mruDatabase

end

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

function nmbCatalogPrototype:getDeletionBacklog()

	check( 'NmbCatalog' )
	return self._mruDatabase

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', 'NmbVolumeAgent' )
	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 )
