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

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

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

local Rx = require 'Rx'

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

-- WF Trash
local WFCatTrash = require 'WFCatTrash'

	-- Lrmobile_models
local LrmAllPhotosQueryBuilder = require 'LrmAllPhotosQueryBuilder'

local WFPlatformInfo = require 'WFPlatformInfo'

local LrmAlbumUtils = require 'LrmAlbumUtils'

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

local derefOpt = assert( KSTableUtils.derefOpt )

local LrmAllPhotosAlbumModel = {}
local Model = {}

LrmAllPhotosAlbumModel.kTrashAlbumId = '10002000300040005000600070008004'

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

function Model:cacheSizeModel()
	
	local cacheSize = self.wfCatalog:indexStore():query {
			sql = [[SELECT SUM(size) FROM cacheReferences]],
			calm = 3,
		}
		:map( function( rows )		
			local cacheSize = derefOpt( rows, 1, 1 ) or 0
			
			return cacheSize
		end )
		
	return {
		value = cacheSize,
	}
end

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

function Model:isSharedModel()

	return {
		value = LrmAlbumUtils.isAlbumShared( self.wfCatalog.indexStore(), self.albumId )
	}
	
end

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

function Model:unsynchronizedAssets()


	local tricker = self.wfCatalog.indexStore():query( {
			sql = [[SELECT count( distinct assetId ) FROM renditionRevisions]]
		 } )
		 :pluck( 1, 1 )
		
	return {
		value = tricker
	}
	
end

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

local function makeCollectionInfo( name, originalPhotoRows, displayDate, eventName, startDate, endDate, eventNameFirst )

	debug.print(name .. " " .. #originalPhotoRows)
	if not originalPhotoRows or #originalPhotoRows == 0 then
		local photosUnknown = originalPhotoRows == nil or nil
		return { name = name, displayDate = displayDate, photos = { }, eventName = eventName, startDate = startDate, endDate = endDate, assetCount = 0,
				 photosUnknown = photosUnknown }
	end
				
	local nPhotos = #originalPhotoRows
	
	local collectionInfo = {
		name = name,
		photos = {},
		displayDate = displayDate,
		eventName = eventName,
		startDate = startDate,
		endDate = endDate,
		eventNameFirst = eventNameFirst,
		assetCount = nPhotos,
	}
	
	local photos = collectionInfo.photos
		
	for i = 1, nPhotos do
		
		local originalPhotoRow = originalPhotoRows[ i ]
		
		photos[ i ] = {
			id = originalPhotoRow[ 1 ], -- coreInfo.docId
			croppedWidth = originalPhotoRow[ 2 ],
			croppedHeight = originalPhotoRow[ 3 ],
			captureDate = originalPhotoRow[ 4 ], --captureDate
			fileName = originalPhotoRow[ 5 ],
			modifiedDate = originalPhotoRow[ 6 ], -- modifiedDate
			thumbnailMD5 = originalPhotoRow[ 7 ], -- thumbnailMD5
			importDate = originalPhotoRow[ 8 ], -- importDate
			importedByUser = originalPhotoRow[11] or "",
			isVideo = originalPhotoRow[ 12 ] == 1, -- isVideo
			duration = originalPhotoRow[ 13 ], -- duration
			isPopulated = true,
			originalFileSize = originalPhotoRow[ 14 ],
			purgeDate = originalPhotoRow[ LrmAllPhotosQueryBuilder.purgeDateColumnId ], -- purge Date, specific to Trash album only
		}

	end

	return collectionInfo

end

local function globalGridCollectionInfo( wfCatalog, activeAlbum, ascending, assetTypeFilter, assetFilter, keyword, activeFilterEdited, sortCriteria, ratingFilter, ratingComparisonOperator, isSearch, personId, limit )

	local sql, queryParams = LrmAllPhotosQueryBuilder.buildCoreInfoQuery( activeAlbum, ascending,
		assetTypeFilter, assetFilter, keyword, activeFilterEdited, sortCriteria,
		ratingFilter, ratingComparisonOperator, isSearch, personId, limit
	)

	local result = wfCatalog:indexStore():query {
		sql = sql,
		calm = 3,
		unpack( queryParams )
	}

	return result:map( function( originalPhotoRows )

		return makeCollectionInfo(
			'grid', -- collection id for grid mode, not used by UI
			originalPhotoRows,
			true )

	end)

end

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

local function oldAssetListModel(collectionInfo)
	
	local prevCollectionInfo = {}
	prevCollectionInfo.photos = {}
	return collectionInfo:map( function( collectionInfo )
		
		if type( collectionInfo ) == 'userdata' then
			return collectionInfo, false
		end
		
		local newPhotos = collectionInfo and collectionInfo.photos

		if type( newPhotos ) == 'userdata' then
			return newPhotos, false
		end
		
		if collectionInfo ~= nil then
			newPhotos = collectionInfo and collectionInfo.photos
		
			if collectionInfo and collectionInfo.photosUnknown then
				collectionInfo = nil
				newPhotos = nil
			end
			
			local prevPhotos = nil
			if prevCollectionInfo and prevCollectionInfo.photos and prevCollectionInfo.closeEnough then
				prevPhotos = prevCollectionInfo.photos
			end
			
			local closeEnough = LrmAlbumUtils.photoListsCloseEnough( newPhotos, prevPhotos )
			
			if collectionInfo then
				collectionInfo.closeEnough = closeEnough
			end
			
			if closeEnough then
				return prevCollectionInfo
			else
				prevCollectionInfo = collectionInfo
				return prevCollectionInfo
			end
		end
	end )
	:map( function( collectionInfo )
		
		local albumInfo = nil
		local photos = nil
		if collectionInfo ~= nil then
			albumInfo = {}
			albumInfo.photos = collectionInfo.photos
			albumInfo.assetCount = collectionInfo.assetCount
			albumInfo.closeEnough = collectionInfo.closeEnough
			photos = collectionInfo.photos
		end
		return {
			albumInfo = albumInfo,
			assetListHash = LrmAlbumUtils.calculateAssetListHash( photos )
		}
	end )
end

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

function Model:assetListModel( sortCriteria, ascending, assetFilter, assetTypeFilter, keyword, edited, ratingFilter, ratingComparisonOperator, isSearch, personId, limit )

	local activeFilter = {}
	
	for i = 1, #assetFilter do
		local filter = assetFilter[ i ]
		activeFilter[ filter ] = true
	end
	
	if assetTypeFilter then
		for i = 1, #assetTypeFilter do
			local assetType = assetTypeFilter[ i ]
			activeFilter[ assetType ] = true
		end
	end

	if edited then
		for i = 1, #edited do
			activeFilter.edited = edited[ i ]
		end
	end
	
	local saveFilters = self.wfCatalog:docStore():applyOverlay {
		_id 	= self.albumId,
		_localOnly = 
		{
			filter = 
			{
				image						= activeFilter.image,
				video						= activeFilter.video,
				pick 						= activeFilter.pick,
				reject 						= activeFilter.reject,
				unflagged					= activeFilter.unflagged,
				favorite 					= activeFilter.favorite,
				comment 					= activeFilter.comment,
				keyword						= keyword,
				edited						= activeFilter.edited,
				rating 						= ratingFilter,
				ratingComparisonOperator	= ratingComparisonOperator,
				sortCriteria 				= sortCriteria,
				ascending 					= ascending
			},
		},
	}
	
	local result

	if WFPlatformInfo.isAndroid then

		result = oldAssetListModel( globalGridCollectionInfo( self.wfCatalog,
					self.albumId, ascending, assetFilter, assetTypeFilter, keyword, activeFilter.edited, sortCriteria,
					ratingFilter, ratingComparisonOperator, isSearch, personId, limit )
				)
	else
		local sql, queryParams	= LrmAllPhotosQueryBuilder.buildCoreInfoQuery (self.albumId, ascending, assetFilter, assetTypeFilter, keyword, activeFilter.edited, sortCriteria, ratingFilter, ratingComparisonOperator, isSearch, limit)

		local encoder = 'LrmOzAssetCoreInfo.encodeSql'

		result = self.wfCatalog:indexStore():query{
				sql 	= sql,
				encoder	= encoder,
				calm 	= .125,
				unpack( queryParams )
			}
	end

	return 
	{
		value = saveFilters
				:flatMap( result )
				:replay( nil, 1 )
				:refCount()
	}
	
end

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

function Model:trashAssetListModel()

	local isSearch = false
	local isTrash = true
	local fieldsToReturn = LrmAllPhotosQueryBuilder.getCollectionInfoFields( isSearch, isTrash )

	local getMostImmediatePurgeDateFunction = function( assetCoreInfoList )

		local mostImmediatePurgeDate, count

		if WFPlatformInfo.isAndroid then

			count = assetCoreInfoList and #assetCoreInfoList
			if count and count > 0 then

				local asset = assetCoreInfoList [ 1 ]
				mostImmediatePurgeDate = asset [ LrmAllPhotosQueryBuilder.purgeDateColumnId ]

			end

		else

			count = assetCoreInfoList:getCount()

			if count and count > 0 then

				local asset = assetCoreInfoList:getAsset( 1 )
				mostImmediatePurgeDate = asset.purgeDate

			end
		end

		return mostImmediatePurgeDate

	end

	local encoder
	if WFPlatformInfo.isiOS then
		encoder = 'LrmOzAssetCoreInfo.encodeSql'
	end

	local value = WFCatTrash.trashAssetList( self.wfCatalog, fieldsToReturn, getMostImmediatePurgeDateFunction, encoder )

	if WFPlatformInfo.isAndroid then

		value = value
			:map( function( rows )

				return Rx.Observable.just( makeCollectionInfo(
					'grid', -- collection id for grid mode, not used by UI
					rows,
					true ))

			end )
			:flatMap ( oldAssetListModel )
	end 

	return {

		value = value

	}

end

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

function Model:trashAssetCountModel()

	local value = WFCatTrash.countTrashAssets( self.wfCatalog )

	return {

		value = value

	}

end

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

function Model:trashAssetsFileSizeModel( assetIds )

	local value = WFCatTrash.trashAssetsFileSize( self.wfCatalog, assetIds )

	return {

		value = value
		:map( function( rows )

			return rows

		end )

	}

end

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

function Model:trashAssetsTotalFileSizeModel()

	local value = WFCatTrash.trashAssetsTotalFileSize( self.wfCatalog )

	return {

		value = value
		:map( function( rows )

			return rows

		end )

	}

end

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

local function makeFlagStatus( rows )

	local flags = {
		unflagged = 0,
		pick = 0,
		reject = 0,
	}
	
	for i=1, #rows do

		local row = rows[i]

		if row[1] == 'unflagged' then
		
			flags.unflagged = row[2]
		
		elseif row[1] == 'pick' then
		
			flags.pick = row[2]
			
		elseif row[1] == 'reject' then
			
			flags.reject = row[2]
			
		end
		
	end
	
	return flags
	
end

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

local function flags(wfCatalog, albumId )

	local sql = [[SELECT flag, COUNT(docId) FROM coreInfo WHERE spaceId is NULL GROUP BY flag]]

	return wfCatalog:indexStore()

	:query ( { sql = sql, calm = 3 } )

	:map (function( rows )

		return makeFlagStatus( rows )

	end )

end

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

function Model:assetListWithSearch()
		
	local sql, queryParams	= LrmAllPhotosQueryBuilder.buildCoreInfoQueryWithSearch ()
		
	local encoder = 'LrmOzAssetCoreInfo.encodeSql'
											
	local result = self.wfCatalog:indexStore():query { 
			sql	= sql, 
			nArgs = #queryParams,
			encoder	= encoder,
			unpack( queryParams )
		}

	return 
	{
		value = result,
	}
	
end

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

function Model:flagStatusCountModel()

	return {
		value = flags( self.wfCatalog, self.albumId )
	}
end

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

function Model:coverImageModel()

	local sql = [[
		SELECT coreInfo.docId 
		FROM coreInfo 
		ORDER BY captureDate DESC 
		LIMIT 1]]

	local result = self.wfCatalog:indexStore():query { 
			sql = sql,
			calm = 30
		}
		:pluck( 1, 1 )

	return {
		value = result
	}
end

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

function Model:alternativeCoverAssetId()

	local sql = [[SELECT coreInfo.docId FROM coreInfo WHERE coreInfo.docId NOT IN (SELECT assetId FROM ozUploadStatus WHERE docType == 'asset') ORDER BY captureDate DESC LIMIT 1]]
					
	local coverImageAssetId = self.wfCatalog:indexStore():query{
			sql = sql,
			singleColumnQuery = true
		}
		:pluck( 1 )
			

	return {
		value = coverImageAssetId,
	}
	
end

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

function LrmAllPhotosAlbumModel.makeModel( wfCatalog, albumId )

	WFArguments.check( 'WFCatalog', 'string' )
		
	local result = wfCatalog:docStore():docValue( albumId )
		:map( function( albumDocValue )
			local filter = KSTableUtils.derefOpt( albumDocValue, "_localOnly", "filter" )
			
			if filter then
								
				return {
					image = derefOpt( filter, "image" ),
					video = derefOpt( filter, "video" ),
					pick = derefOpt( filter, "pick" ),
					reject = derefOpt( filter, "reject" ),
					unflagged = derefOpt( filter, "unflagged" ),
					favorite = derefOpt( filter, "favorite" ),
					comment = derefOpt( filter, "comment" ),
					rating = derefOpt( filter, "rating" ),
					ratingComparisonOperator = derefOpt( filter, "ratingComparisonOperator" ),
					sortCriteria = derefOpt( filter, "sortCriteria" ),
					ascending = derefOpt( filter, "ascending" ),
				}
				
			end
			
			return nil
			
		end )
		:concat( Rx.Observable.never() )
		:replay( nil, 1 )
		:refCount()
		
	
	return {
		wfCatalog = wfCatalog,
		albumId = albumId,
		value = result,
		models = Model,
		
		events = {
		}
	}
end

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

return LrmAllPhotosAlbumModel
