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

LrmCoreInfoIndexDefinitions.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2016 Adobe Systems Incorporated
All Rights Reserved.

NOTICE: All information contained herein is, and remain 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 may be covered by U.S. and Foreign
Patents, patents in process, and are protected by trade secret or copyright
law.  Dissemination of this information or reproduction of this material is
strictly forbidden unless prior written permission is obtained from
Adobe Systems Incorporated.

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

	-- WF.core.utils
local KSTableUtils = require 'KSTableUtils'
local WFArguments = require 'WFArguments'
local WFPlatformInfo = require 'WFPlatformInfo'
local WFCapabilities = require 'WFCapabilities'

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

local LrmCoreInfoIndexHelper = require "LrmCoreInfoIndexHelper"
local LrmAssetUtils = require "LrmAssetUtils"

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

local derefOpt = assert( KSTableUtils.derefOpt )

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

local check = assert( WFArguments.check )

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

-- @mark LrmCoreInfoIndexDefinitions namespace

local LrmCoreInfoIndexDefinitions = {}

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

function LrmCoreInfoIndexDefinitions.assetIsDisplayable( docValue )

	local docType = docValue.type
	local subtype = docValue.subtype

	if WFPlatformInfo.isAndroid and WFCapabilities.getCapability( "LrmCoreInfoIndexDefinitions.disableVideoSupport" ) then
		local video = derefOpt( docValue, 'video' )
		if video or subtype == 'video' then return false end
	end

	if docType ~= 'asset' then return false end
	
	if not ( subtype == 'image' or subtype == 'video' ) then return false end

	-- Include if we can get a thumbnail from Oz.

	return LrmCoreInfoIndexHelper.assetHasMasterOrProxy( docValue )

end

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

function LrmCoreInfoIndexDefinitions.coreInfoFromDocValue( docValue )

	local importSource = derefOpt( docValue, 'importSource' )
	local width = importSource and importSource.originalWidth
	local height = importSource and importSource.originalHeight
	
	-- Cropped width and height win.
	
	local develop = docValue.develop
	
	if develop and develop.croppedWidth and develop.croppedHeight then
		width = develop.croppedWidth
		height = develop.croppedHeight
	end
	
	-- Local only thumbnail wins.
	-- No, because this causes a lot of extra computation as large
	-- grid view results are re-sent when one thumbnail is loaded
	-- arahn 05/25/2013
	local thumbnail = derefOpt( docValue, '_localOnly', 'thumbnail2x' )
	
	if width == nil and height == nil and thumbnail and thumbnail.referenceWidth and thumbnail.referenceHeight then
		width = thumbnail.referenceWidth
		height = thumbnail.referenceHeight
	end

	local aspectRatio

	if not docValue._deleted
		and type( width ) == 'number' and width > 0
		and type( height ) == 'number' and height > 0
	then
		aspectRatio = width / height
	end
	
	local thumbnailMD5 = thumbnail and thumbnail.md5
	
	return aspectRatio, thumbnailMD5

end

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

function LrmCoreInfoIndexDefinitions.getFavoritedCount( docValue )

	local favoritedCount = 0
	local favorites = docValue and docValue.favorites

	if favorites then
		for k, v in pairs( favorites ) do
			if v then
				favoritedCount = favoritedCount + 1
			end
		end
	end

	return favoritedCount

end

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

function LrmCoreInfoIndexDefinitions.generateIndexSchema( indexStoreSchema )

	check( 'WFRxIndexStoreSchema' )

	local fields, niceToHaveFields

	-- platform specfic fields

	if WFPlatformInfo.isiOS then
		-- iOS specific coreInfo fields
		fields = {
			"userOrientation",
			"hasEmbeddedDepthMap",
			"importSourceCameraName",
			"importSourceLensName",
			"flashFired",
			"lens",
			"isMergedPanorama",
			'tmp_hasImportSettings',
		}

		niceToHaveFields = nil
	else
		-- Android specific coreInfo fields
		fields = {
			"aspectRatio",
			"displayDate",
			"copyTimestamp",
			"thumbnailMD5",
			"wasDeveloped",
			"copyright",
		}

		niceToHaveFields = {
			"thumbnailMD5",
		}
	end

	-- fields common to LriOS and LrAndroid

	local fieldsCommonMobile = {
		"favoritedCount",
		"importedBy",
		"developUserUpdated",
		"sha256",
		"isCapturedWithAdobeCamera",
		"originalSHA256",
	}

	-- fields common with TrashAsset

	local fieldsCommonCoreInfo = LrmCoreInfoIndexHelper.getCoreInfoCommonFields()

	for _, field in pairs( fieldsCommonMobile ) do
		fields[ #fields+1 ] = field
	end

	for _, field in pairs( fieldsCommonCoreInfo ) do
		fields[ #fields+1 ] = field
	end

	indexStoreSchema:addTable {
	
		-- Instead of specifying CREATE TABLE SQL, in order to use
		-- niceToHave, you must specify the field names and let the index
		-- store generate the SQL

		tableName = "coreInfo",
		
		fields = fields,

		COLLATE = {
			eventName = 'i18n_collate',
		},
		
		relevantTypeSubtypeTuples = {
			{ 'asset', 'image' },
			{ 'asset', 'video' }
		},
		
		-- query won't send updates for changes that only affect niceToHave
		-- columns
		niceToHave = niceToHaveFields,

		map = function( docValue, emit )
		
			local emitFnVersion = 2
				-- Increment this version to trigger reindexing of this table when the implementation of 
				-- any of the fns called within change. This value is passed to assetIsDisplayable
				-- where it is ignored. We do this to remove any unused local warnings from Halide.

			if docValue._deleted then
				return
			end
			if not LrmCoreInfoIndexDefinitions.assetIsDisplayable( docValue, emitFnVersion ) then
				return
			end
			
			local favoritedCount = LrmCoreInfoIndexDefinitions.getFavoritedCount( docValue )
			
			local importedBy = derefOpt( docValue, 'importSource', 'importedBy' ) or ''
			local sha256 =  derefOpt( docValue, 'importSource', 'sha256' )
			local originalSHA256 = derefOpt( docValue, 'importSource', 'originalSHA256' )
			local developUserUpdated = derefOpt( docValue, 'develop', 'userUpdated' )

			local xmp = LrmAssetUtils.getXmp( docValue ) or {}
			
			local isCapturedWithAdobeCamera = LrmAssetUtils.getCapturedWithAdobeCamera( docValue )

			local nFieldsCommonCoreInfo, fieldsCommonCoreInfoValue = LrmCoreInfoIndexHelper.getCoreInfoCommonFieldsValue( docValue )

			if WFPlatformInfo.isiOS then
				-- iOS specfic fields

				local userOrientation  = derefOpt( docValue, 'develop', 'userOrientation' )
				local hasEmbeddedDepthMap = derefOpt( docValue, 'importSource', 'hasEmbeddedDepthMap' )
				local isMergedPanorama = derefOpt( docValue, 'xmp', 'aux', 'IsMergedPanorama' )

				local importSourceCameraName, importSourceLensName = LrmAssetUtils.getImportSourceCameraAndLensName( docValue )

				-- jrechtie, 2018/07/14 temporary field for migrating the importSettings.
				-- jrechtie, 2019/08/02 there is nothing temporary about this field: TODO rename to something more suitable
				local tmp_hasImportSettings = derefOpt( docValue, '_localOnly', 'lrm_customData', 'importSettings' )
				tmp_hasImportSettings = ( tmp_hasImportSettings and type( tmp_hasImportSettings ) == 'table' ) and 1 or 0

				emit(
					-- platform specific fields
					userOrientation,
					hasEmbeddedDepthMap,
					importSourceCameraName,
					importSourceLensName,
					xmp.flashFired,
					xmp.lens,
					isMergedPanorama,
					tmp_hasImportSettings,
					-- fieldsCommonMobile
					favoritedCount,
					importedBy,
					developUserUpdated,
					sha256,
					isCapturedWithAdobeCamera,
					originalSHA256,
					-- fieldsCommonTrashAsset
					unpack( fieldsCommonCoreInfoValue, 1, nFieldsCommonCoreInfo )
				)

			else
				-- Android specfic fields

				local aspectRatio, thumbnailMD5 = LrmCoreInfoIndexDefinitions.coreInfoFromDocValue( docValue )

				-- Capture date may have a "Z" appended to the end, signifying that the
				-- timestamp is in UTC (20 chars). Otherwise, the timestamp is treated as
				-- local time (19 chars). Either way, we just care about getting the
				-- YYYY-MM-DD from the beginning of the string.
				local displayDate

				if docValue.captureDate and string.len( docValue.captureDate ) > 10 then
					displayDate = string.replace( string.sub( docValue.captureDate, 1, 10 ), ":", "-" )
				end

				local copyTimestamp = derefOpt( docValue, 'importSource', 'copyTimestamp' )

				local wasDeveloped = LrmAssetUtils.isDeveloped( docValue )

				emit(
					-- platform specific fields
					aspectRatio,
					displayDate,
					copyTimestamp,
					thumbnailMD5,
					wasDeveloped,
					xmp.copyright,
					-- fieldsCommonMobile
					favoritedCount,
					importedBy,
					developUserUpdated,
					sha256,
					isCapturedWithAdobeCamera,
					originalSHA256,
					-- fieldsCommonTrashAsset
					unpack( fieldsCommonCoreInfoValue, 1, nFieldsCommonCoreInfo )
				)
			end
		end,

	}

	indexStoreSchema:addIndex [[CREATE INDEX coreInfo_importedBy ON coreInfo( importedBy, captureDate, docId )]]

	-- Grid sorting criteria which can benefit from from an index.
	indexStoreSchema:addIndex [[CREATE INDEX coreInfo_captureDate ON coreInfo( captureDate )]]
	indexStoreSchema:addIndex [[CREATE INDEX coreInfo_importTimestamp ON coreInfo( importTimestamp )]]
	indexStoreSchema:addIndex [[CREATE INDEX coreInfo_modifiedDate ON coreInfo( modifiedDate, captureDate, fileName COLLATE i18n_collate, docId )]]
	indexStoreSchema:addIndex [[CREATE INDEX coreInfo_fileName ON coreInfo( fileName COLLATE i18n_collate  )]]
	indexStoreSchema:addIndex [[CREATE INDEX coreInfo_developUserUpdated ON coreInfo( developUserUpdated  )]]
	indexStoreSchema:addIndex [[CREATE INDEX coreInfo_sha256 ON coreInfo( sha256  )]]
	indexStoreSchema:addIndex [[CREATE INDEX coreInfo_localUrl ON coreInfo( localUrl  )]]
	indexStoreSchema:addIndex [[CREATE INDEX coreInfo_isCapturedWithAdobeCamera ON coreInfo( isCapturedWithAdobeCamera )]]
	-- Note: an index on column 'rating' actually increases sorting time significantly.
	-- This is probably due to it being a "low quality index" - one with more than 10-20 rows having the same value in left most column.

	-- Note: an index on columns 'flag, docId' actually increases "filter for flag" in time in albums significantly.
	-- This is due to it being a "low quality index" - with only three possible values for flag, where one value is heavily
	-- dominating for typical catalogs: "unflagged".
	-- In a complex query with several filters, the query optimzer might choose the flag_docId index as first filter
	-- and then only the albumid in the album_asset table, leading to unneccessary long query times.

end

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

return LrmCoreInfoIndexDefinitions
