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

WFCatalogBase.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'

	-- WF.core.utils
local WFArguments = require 'WFArguments'
local _ = require 'WFArguments_uuid'
local WFCloseSupport = require 'WFCloseSupport'
local WFFileUtils = require "WFFileUtils"
local KSTableUtils = require "KSTableUtils"
local KSDate = require "KSDate"
local KSPathUtils = require "KSPathUtils"
local WFAnalytics = require "WFAnalytics"

-- WF.core.threading
local WFCurrentThread = require 'WFCurrentThread'

	-- WF.oz_client.managed_catalog
local WFCatFileSpec = require 'WFCatFileSpec'
local WFCatSimpleDocStoreUpdater = require 'WFCatSimpleDocStoreUpdater'
 
	-- WF.sqlite.doc_store
local WFRxDocStore = require 'WFRxDocStore'

	-- WF.sqlite.index_store
local WFRxIndexStore = require 'WFRxIndexStore'

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

local check = assert( WFArguments.check )

local derefOpt = assert( KSTableUtils.derefOpt )

local analyticsSent = false

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

local function reportDatabaseSizes( docStorePath )

	-- MEH [immisch 2021-05-06]: unfortunately, this isn't enough to avoid sending the Analytics twice.
	-- At least on iOS, there is a Lua universe started to check for necessary migrations and 
	-- then the real one - and analyticsSent is reset between those runs
	-- See below for a workaround

	-- SPAM [jandrew 2022-01-07]: On LrD, 6 threads are created that intialize WFCatalogBase.
	-- In order to prevent each thread from sending their own analytics, we now check the
	-- thread name and only send metrics for the sync client threads. LrD initializes two
	-- separate WFCatSyncClientMessageProcessor threads (one for the catalog doc store, one
	-- for the profile doc store), so we further distinguish between the threads using the
	-- doc store path.

	if analyticsSent then return end

	analyticsSent = true

	local threadName = WFCurrentThread.DEBUG_getThreadName()

	if ( threadName:find( "^WFCatSyncClientMessageProcessor\.lua" ) ~= nil
			or threadName:find( "^LrmSyncClientMessageProcessor\.lua" ) ~= nil )
			and docStorePath:find( "Managed\ Catalog\.mcat$" ) ~= nil
			and docStorePath ~= ':memory:'
			and docStorePath ~= ':temp:' then

		local success, docStoreAttr = pcall( WFFileUtils.fileAttributes, docStorePath )
		
		if success then 
		
			-- See above: we check that the docStore wasn't modified in the last 60 seconds to avoid sending the analytics twice
			local docStoreMTime = derefOpt( docStoreAttr, 'fileModificationDate' )
			if docStoreMTime and KSDate.timeNow() - docStoreMTime < 60 then return end

			local indexStorePath = docStorePath:gsub( '%.[^./\\]*$', '' ) .. '.wfindex'

			local indexStoreAttr
			success, indexStoreAttr = pcall( WFFileUtils.fileAttributes, indexStorePath )
			
			if success then
			
				local docStoreFileSize = derefOpt( docStoreAttr, 'fileSize' ) or 0
				local indexStoreFileSize = derefOpt( indexStoreAttr, 'fileSize' ) or 0
				local freeSpace, fileSystemSize = 0

				success, freeSpace, fileSystemSize = pcall( WFFileUtils.freeSpaceAtPath, KSPathUtils.parent( docStorePath ) ) 

				if success and docStoreFileSize > 0 then

					WFAnalytics.trackEvent {
						[ 'event.type' ] = 'info',
						[ 'event.subtype' ] = 'db-sizes',
						[ 'event.appWorkflow' ] = 'LAUNCH',
						[ 'event.docStoreSize' ] = docStoreFileSize,
						[ 'event.indexStoreSize' ] = indexStoreFileSize,
						[ 'event.freeSpace' ] = freeSpace,
						[ 'event.fileSystemSize' ] = fileSystemSize,						
					}

				end

			end
		
		end

	end

end

-- @mark WFCatalogBase class

local WFCatalogBase = {

	_wfCatSpec = false,
		-- (WFCatSpec) specification for the catalog user and catalog ID
	
	_wfCatFileSpec = false,
		-- (WFCatFileSpec) specification for where the catalog files should live on local storage

	_docStore = false,
		-- (WFRxDocStore)

	_indexStore = false,
		-- (WFRxIndexStore)

	_simpleDocStoreUpdater = false,
		-- (WFCatSimpleDocStoreUpdater) Allows for simple updating (format changes) of documents

	WFCloseSupport.addCloseSupportMethods,

}

--------------------------------------------------------------------------------
--[[!
	\brief Create the base object for a WFCatalog.

	\param ozCatalogSpec (WFCatSpec) specification for the catalog user and catalog ID
	\param rootCatalogPath (string) root directory under which to store catalog related files
	\param optArgs (table) optional args for doc store/index store creation
		- docStorePath	        		 -- path to doc store
		- docStoreInitProgressRequested  -- support for initialization progress (via broadcasts)
		- indexSpecScript  	    		 -- name of script to use for index store
		- indexStoreReadThreads 		 -- (number) the number of read-only threads to create to handle
											indexStore queries
]]--

function WFCatalogBase:__init( ozCatalogSpec, rootCatalogPath, optArgs )

	check( '_', 'WFCatSpec', 'string' )

	local optDocStorePath, optDocStoreInitProgressRequested, optIndexSpecScript, optIndexStoreReadThreads, optEnablePlatformIndexStore
	
	if optArgs then
		optDocStorePath = optArgs.docStorePath
		optDocStoreInitProgressRequested = optArgs.docStoreInitProgressRequested
		optIndexSpecScript = optArgs.indexSpecScript
		optIndexStoreReadThreads = optArgs.indexStoreReadThreads
		optEnablePlatformIndexStore = optArgs.enablePlatformIndexStore
	end

	local wfCatFileSpec = WFCatFileSpec( rootCatalogPath, ozCatalogSpec:catalogId(), optDocStorePath )
	self._wfCatFileSpec = wfCatFileSpec
		-- WFCatFileSpec is not a close target
	
	reportDatabaseSizes( wfCatFileSpec:docStorePath() )
	
	local docStoreOptArgs = {
		initProgressRequested = optDocStoreInitProgressRequested,
	}

	local docStore = WFRxDocStore( wfCatFileSpec:docStorePath(), docStoreOptArgs )

	local indexStore = WFRxIndexStore( docStore,
									   optIndexSpecScript or 'WFCatIndexDefinitions.lua',
									   optIndexStoreReadThreads,
									   optEnablePlatformIndexStore )
	
	self._wfCatSpec = ozCatalogSpec
		-- WFCatSpec is not a close target.

	local simpleDocStoreUpdater = WFCatSimpleDocStoreUpdater( docStore, indexStore, self )

	self:setOwned {
		_docStore = docStore,
		_indexStore = indexStore,
		_simpleDocStoreUpdater = simpleDocStoreUpdater,
	}

	WFCloseSupport.mustClose( self )

end

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

function WFCatalogBase:__tostring()

	return string.format( "WFCatalog( %s )", tostring( self._wfCatSpec ) )

end

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

function WFCatalogBase:ozCatalogSpec()

	return self._wfCatSpec

end

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

function WFCatalogBase:fileSpec()

	return self._wfCatFileSpec

end

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

function WFCatalogBase:ozCatalogId()

	return self._wfCatSpec:catalogId()

end

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

function WFCatalogBase:ozUser()

	return self._wfCatSpec:wfOzUser()

end

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

function WFCatalogBase:ozUserId()

	return self._wfCatSpec:wfOzUser():userId()

end

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

function WFCatalogBase:docStore()

	return self._docStore

end

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

function WFCatalogBase:indexStore()

	return self._indexStore

end

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

function WFCatalogBase:getSimpleDocStoreUpdater()

	return self._simpleDocStoreUpdater

end
--------------------------------------------------------------------------------

return Rx.Class 'WFCatalog'( WFCatalogBase )
