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

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.

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

local Rx = require 'Rx'

local KSTableUtils = require "KSTableUtils"

local WFPlatformInfo = require 'WFPlatformInfo'
local LrmAssetUtils = require 'LrmAssetUtils'

local LrmCoreInfoIndexDefinitions = require "LrmCoreInfoIndexDefinitions"

local LrmOzRenditionServerUtils
if WFPlatformInfo.isiOS then
	LrmOzRenditionServerUtils = require "LriOzRenditionServerUtils"
else
	LrmOzRenditionServerUtils = require "LrmOzRenditionServerUtils"
end

local WFRxIndexStoreSchema = require 'WFRxIndexStoreSchema'

local WFOzContentTypes = require 'WFOzContentTypes'

local WFFileUtils = require 'WFFileUtils'

local OzFilePaths = require 'OzFilePaths'

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

local derefOpt = assert( KSTableUtils.derefOpt )

local assetIsDisplayable = assert( LrmCoreInfoIndexDefinitions.assetIsDisplayable )

local getContentTypeNumberForContentType = WFOzContentTypes.getContentTypeNumberForContentType

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

local LrmCatalogIndexDefinitions = {}

--------------------------------------------------------------------------------
-- @mark assetProfileLinks
--------------------------------------------------------------------------------

local kAssetProfileLinks = {

	sql = [[CREATE TABLE assetProfileLinks( subtype, fileName, masterUrl, uniqueId )]],

	updateLazily = WFPlatformInfo.isAndroid and false or nil, -- don't wait for the table in Android to be used. Do indexing ASAP

	relevantTypeSubtypeTuples = {
		{ 'asset', 'image' },
		{ 'asset', 'video' },
	},

	map = function( docValue, emit )
		
		if docValue._deleted then
			return
		end
		if not assetIsDisplayable( docValue ) then
			return
		end
		
		local cameraProfileInfo = LrmAssetUtils.getCameraProfileInfo( docValue)
		if cameraProfileInfo then
			emit( "camera", cameraProfileInfo.filename, cameraProfileInfo.href, cameraProfileInfo.uniqueId )
		end
		
		local lensProfileInfo = LrmAssetUtils.getLensProfileInfo( docValue )
		if lensProfileInfo then
			emit( "lens", lensProfileInfo.filename, lensProfileInfo.href, lensProfileInfo.uniqueId )
		end
	end,
}

local kAssetProfileLinks_uniqueId = [[CREATE INDEX assetProfilesLink_uniqueId ON assetProfileLinks( uniqueId )]]

--------------------------------------------------------------------------------
-- @mark profileRegistration
--------------------------------------------------------------------------------

local kProfileRegistration = {

	sql = [[CREATE TABLE profileRegistration( subtype, fileName, uniqueId )]],

	updateLazily = WFPlatformInfo.isAndroid and false or nil, -- don't wait for the table in Android to be used. Do indexing ASAP

	relevantTypeSubtypeTuples = {
		{ 'asset', 'camera_profile' },
		{ 'profile', 'NULL' },
	},

	hasOneRowPerDocument = true,

	map = function( docValue, emit )

		if (docValue.type == 'asset' and docValue.subtype == 'camera_profile') or docValue.type == 'profile'
			and not docValue._deleted then

			local fileName
			local uniqueId
			local subtype

			if docValue.type == 'asset' and not WFPlatformInfo.isAndroid then
				-- Custom DCPs

				subtype = 'camera'
				fileName = docValue.fileName
				uniqueId = derefOpt( docValue, '_serverProvidedMetadata', 'links', '/rels/master', 'href' )

			else
				-- Adobe standard camera matching profiles

				if WFPlatformInfo.isAndroid and docValue.type ~= 'profile' then
					return
				end

				local localOnly = docValue._localOnly

				subtype = localOnly.subtype
				fileName = localOnly.fileName
				uniqueId = localOnly.uniqueId

			end

			if uniqueId then
				emit( subtype, fileName, uniqueId )
			end
		end
	end,
}

local kProfileRegistration_uniqueId = [[CREATE INDEX profileRegistration_uniqueId ON profileRegistration( uniqueId )]]
local kProfileRegistration_fileName = [[CREATE INDEX profileRegistration_fileName ON profileRegistration( fileName COLLATE NOCASE )]]

--------------------------------------------------------------------------------
-- @mark TEMP_searchFilterCount
--------------------------------------------------------------------------------

local kTEMP_searchFilterCount =  {

	sql = [[CREATE TEMPORARY TABLE TEMP_searchFilterCount( filterType, filterCount )]],
	
	isManualTable = true
	
}

--------------------------------------------------------------------------------
-- @mark renditionRevisions
--------------------------------------------------------------------------------

local function isVideo( docValue )

	if docValue and docValue.video then
		
		return true
		
	end
	
	local contentType = derefOpt( docValue, 'importSource', 'contentType' )
								or derefOpt( docValue, '_serverProvidedMetadata', 'links', 
												'/rels/master', 'content_type' )
				
	if contentType then
	
		local contentTypeNumber = getContentTypeNumberForContentType( contentType )
		
		if LrmAssetUtils.isVideoContentTypeNumber( contentTypeNumber ) then
	
			return true
			
		end
		
	end
	
	return false
		
end

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

local function emitExternalDevelopXmpRendition( assetId, docValue, emit )

	local timestamp = docValue
		and docValue.importSource
		and docValue.importSource.importTimestamp

	local hasExternalXmpDevelop = LrmAssetUtils.hasDownloadableExternalXmpDevelop( docValue )
	local hasExternalXmpDevelopLocally =  LrmAssetUtils.hasExternalXmpDevelopLocally( docValue )

	-- Android: xmpCameraRawFiles might be in the docValue but is missing (user accessible storage)
	local externalXmpDevelopMissing
	if WFPlatformInfo.isAndroid then
		externalXmpDevelopMissing = hasExternalXmpDevelop and not ( hasExternalXmpDevelopLocally
			and WFFileUtils.exists( OzFilePaths.getAbsoluteXmpDevelopPath( docValue ) ) )
	else
		externalXmpDevelopMissing = hasExternalXmpDevelop and not hasExternalXmpDevelopLocally
	end

	if externalXmpDevelopMissing then

		local invalid = derefOpt( docValue, '_serverProvidedMetadata', 'links', '/rels/xmp/develop', 'invalid' )

		if not invalid then

			local fileSize = derefOpt( docValue, '_serverProvidedMetadata', 'links', '/rels/xmp/develop', 'fileSize' )
				or 16384

			emit( assetId, 'xmp_develop', timestamp, fileSize )
		end
	end
		
end

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

local function emitVersionRenditions( docValue, emit )
	
	local assetId = derefOpt( docValue, 'asset', 'id' )
	
	emitExternalDevelopXmpRendition( assetId, docValue, emit )
	
end

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

local kRenditionRevisionsDefinition = {

	sql = [[CREATE TABLE renditionRevisions( assetId, renditionName, timestamp, size )]],
	
	relevantTypeSubtypeTuples = {
		{ 'asset', 'image' },
		{ 'asset', 'video' },
		{ 'version', 'edit' },
	},

	map = function( docValue, emit )

		if docValue._deleted then
			return
		end
		
		if docValue.type == 'version' and docValue.subtype == 'edit' then
			emitVersionRenditions( docValue, emit )
			return
		end
		
		if not assetIsDisplayable( docValue ) then return end
		
		local timestamp = docValue
			and docValue.importSource
			and docValue.importSource.importTimestamp
		
		if LrmOzRenditionServerUtils.shouldDownloadOzRendition( docValue, "thumbnail2x" ) then
		
			local fileSize = derefOpt( docValue, '_serverProvidedMetadata', 'links', '/rels/rendition_type/thumbnail2x', 'fileSize' )
				or 48000
		
			emit( docValue._id, 'thumbnail2x', timestamp, fileSize )
		end
		
		if LrmOzRenditionServerUtils.shouldDownloadOzRendition( docValue, "preview" ) then
		
			local fileSize = derefOpt( docValue, '_serverProvidedMetadata', 'links', '/rels/rendition_type/2048', 'fileSize' )
				or 461824
	
			emit( docValue._id, 'preview', timestamp, fileSize )
		end
		
		local hasProxyOnOz = LrmAssetUtils.hasProxyOnOz( docValue )
		local hasProxyLocally = LrmAssetUtils.hasProxyLocally( docValue )
		local hasMasterOnOz = WFPlatformInfo.isiOS and LrmAssetUtils.hasDownloadableMasterOnOz( docValue ) or LrmAssetUtils.hasMasterOnOz( docValue )
		local hasMasterLocally = LrmAssetUtils.hasMasterLocally( docValue )
		
		local isVideo = isVideo( docValue )
		
		if not isVideo then
		
			if hasMasterOnOz and not hasMasterLocally then

				local fileSize = derefOpt( docValue, 'importSource', 'fileSize' )
				if not fileSize or fileSize <= 0 then
					fileSize = 20971520
				end

				emit( docValue._id, 'master', timestamp, fileSize )

			end
			
			if hasProxyOnOz and not hasProxyLocally then
			
				local fileSize = derefOpt( docValue, '_serverProvidedMetadata', 'links', '/rels/proxy_type/2560', 'fileSize' ) 				
				if not fileSize then 
					fileSize = derefOpt( docValue, '_localOnly', 'proxy', 'fileSize' ) or 1331692
				end
			
				emit( docValue._id, 'proxy', timestamp, fileSize )
			end
			
			if WFPlatformInfo.isiOS then
				if not hasMasterOnOz and not hasMasterLocally and not hasProxyLocally and not docValue._spaceId then
					emit( docValue._id, 'proxyWithoutMaster', timestamp, 1331692 )
				end
			else
				if not hasMasterOnOz and not hasMasterLocally and not hasProxyLocally then
					emit( docValue._id, 'proxyWithoutMaster', timestamp, 1331692 )
				end
			end

			emitExternalDevelopXmpRendition( docValue._id, docValue, emit )

		end
						
	end
}

local kRenditionRevisions_assetId = [[CREATE INDEX renditionRevisions_assetId ON renditionRevisions( assetId )]]



function LrmCatalogIndexDefinitions.tableDefinitions( tableDefinitions )
	
	tableDefinitions.renditionRevisions = kRenditionRevisionsDefinition
	tableDefinitions.assetProfileLinks = kAssetProfileLinks
	tableDefinitions.profileRegistration = kProfileRegistration
	tableDefinitions.TEMP_searchFilterCount = kTEMP_searchFilterCount
	
	tableDefinitions.new_asset_activity = nil
	tableDefinitions.tags = nil
	tableDefinitions.favorite_activity = nil
	tableDefinitions.selectedPhotos = nil
	tableDefinitions.space_user = nil
	
	return tableDefinitions
end

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

function LrmCatalogIndexDefinitions.indexDefinitions( indexDefinitions )

	indexDefinitions.profileRegistration_uniqueId = kProfileRegistration_uniqueId
	indexDefinitions.profileRegistration_fileName = kProfileRegistration_fileName
	indexDefinitions.assetProfileLinks_uniqueId = kAssetProfileLinks_uniqueId
	indexDefinitions.renditionRevisions_assetId = kRenditionRevisions_assetId
	
	return indexDefinitions
	
end

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

local tableDefinitions = {}
local indexDefinitions = {}

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

local LrmIndexStoreSchema = {
	
	WFRxIndexStoreSchema,
		--superclass
}

function LrmIndexStoreSchema:addTable( args )

	if args.updateLazily ~= true and not args.isManualTable then
		args.updateLazily = false
	end
	
	self:WFRxIndexStoreSchema_addTable( args )
	
end


local LrmIndexStoreSchemaClass = Rx.Class( 'WFRxIndexStoreSchema', LrmIndexStoreSchema )

local indexStoreSchema = LrmIndexStoreSchemaClass( )

indexStoreSchema:addDatabaseInitRoutine( require 'WFSQLiteSetLogicImp'.registerSetModule )

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

LrmCatalogIndexDefinitions.tableDefinitions( tableDefinitions )
LrmCatalogIndexDefinitions.indexDefinitions( indexDefinitions )

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

for k, definition in pairs( tableDefinitions ) do
	indexStoreSchema:addTable( definition )
end

for k, definition in pairs( indexDefinitions ) do
	indexStoreSchema:addIndex( definition )
end

local function getIndexSchemaGenerators( )
	local indexDefinitions = {
		'LrmCoreInfoIndexDefinitions',
		'LrmAlbumsIndexDefinitions',
		'LrmCacheIndexDefinitions',
		'LrFavoritesIndexDefinitions',
		'LrCommentsIndexDefinitions',
		'LrmKeywordsIndexDefinitions',
		'LrmPresetsProfilesIndexDefinitions',
		'LrmPeopleIndexDefinitions',
		'LrmTrashIndexDefinitions',
		'LrWatermarkIndexDefinitions'
	}

	return indexDefinitions
end

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

function LrmCatalogIndexDefinitions.generateIndexSchema( indexStoreSchema )

	local indexSchemaGenerators = getIndexSchemaGenerators()
	
	for k, generator in pairs( indexSchemaGenerators ) do
		require ( generator ).generateIndexSchema( indexStoreSchema )
	end
	
end

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

LrmCatalogIndexDefinitions.generateIndexSchema ( indexStoreSchema )

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

require 'WFCatConflictResolver'.generateIndexSchema( indexStoreSchema )
require 'WFCatErrorHandler'.generateIndexSchema( indexStoreSchema )
require 'WFCatStorage'.generateIndexSchema( indexStoreSchema )
require 'WFCatCollaboration'.generateIndexSchema( indexStoreSchema )
require 'WFCatCollaborator'.generateIndexSchema( indexStoreSchema )
require 'WFCatBinaryUploader'.generateIndexSchema( indexStoreSchema )
require 'WFCatImportDuplicateFiles'.generateIndexSchema( indexStoreSchema )
require 'WFCatVersions'.generateIndexSchema( indexStoreSchema )

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

LrmCatalogIndexDefinitions.indexStoreSchema = indexStoreSchema

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

return LrmCatalogIndexDefinitions
