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

PixelProviderVideoLoupeModel.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.

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

local KSFunctionUtils = require 'KSFunctionUtils'

	-- wf.core
local Rx = require "Rx"

	-- wf.oz_client.managed_catalog.pixel_provider
local PixelPathProviderRequestTypes = require 'PixelPathProviderRequestTypes'

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

local logger = require "WFLogger"( "PixelProviderVideoLoupeModel" )

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

local function logInfo( infoStr )

	logger:info( infoStr )

end

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

local function logError( errStr )

	logger:error( errStr )

end

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

local function describeResult( pixStreamIdPrefix, assetId, success,
								pixelPathOrError, _, renderSize,
								croppedLongSide )

	return string.format( "%s getting %s long side rendtion for %s which had long side %s (%s): %s",
							success and "SUCCESS" or "ERROR", 
							success and renderSize or "N/A",
							assetId, croppedLongSide, pixStreamIdPrefix,
							pixelPathOrError )

end

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

local function describeResultStream( pixelProviderProcessor, pixStreamIdPrefix )

	if not pixelProviderProcessor then

		return Rx.Observable.just( "missing pixel provider" )

	end

	return pixelProviderProcessor
				:containsPixStreamIdSubstrPixelPathStream( pixStreamIdPrefix )
				:map( describeResult )

end

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

local function makePixstreamIdFunc( pixStreamType )

	return function( pixStreamIdPrefix )

		return string.format( "%s-%s", pixStreamIdPrefix, pixStreamType )

	end

end

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

local getHighResVideoThumbPixStreamId =
		KSFunctionUtils.memoizeFn( makePixstreamIdFunc( "VideoHighResThumb" ) )

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

local getVideoRenditionPixStreamId =
		KSFunctionUtils.memoizeFn( makePixstreamIdFunc( "VideoRendition" ) )
		
--------------------------------------------------------------------------------

local getVideoProxyPixStreamId =
		KSFunctionUtils.memoizeFn( makePixstreamIdFunc( "VideoProxy" ) )

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

local function removeRequestStreamImp( pixelProviderProcessor, pixStreamId,
										assetId )

	return Rx.Observable.concat(
			pixelProviderProcessor
				:dispatch( "removeRequest",
							pixStreamId, assetId ),
			Rx.Observable.just(
				string.format( "Removed previous request %s ( %s )", 
								assetId, pixStreamId ) ) )

end

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

local function removeRequestStream( pixelProviderProcessor, pixStreamIdPrefix,
									assetId, videoType )
								
	local removeRequestedProcessor = videoType == "rendition" and
								removeRequestStreamImp(
									pixelProviderProcessor, 
									getVideoRenditionPixStreamId( pixStreamIdPrefix ), 
									assetId ) or
								removeRequestStreamImp(
									pixelProviderProcessor, 
									getVideoProxyPixStreamId( pixStreamIdPrefix ), 
									assetId ) 
	return Rx.Observable.merge(
			removeRequestStreamImp(
				pixelProviderProcessor, 
				getHighResVideoThumbPixStreamId( pixStreamIdPrefix ), 
				assetId ),
			removeRequestedProcessor	
			)

end

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

local function makePixelProcessorVideoLoupeRequestStreamImp( 
				pixelProviderProcessor, pixelProviderAPI, pixStreamId, assetId,
				priorityName )

	return Rx.Observable.concat(
				pixelProviderProcessor
					:dispatch( pixelProviderAPI,
									pixStreamId, assetId, priorityName ),
				Rx.Observable.just(
					string.format( "Added or updated request %s (%s) via '%s' priority is %s", 
									assetId, pixStreamId, pixelProviderAPI,
									priorityName ) ) )

end

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

local function makePixelProcessorVideoLoupeRequestsStream( 
				pixelProviderProcessor, pixStreamIdPrefix, assetId, priorityName, videoType, requestSpecialProxyOrRendition )

	if not pixelProviderProcessor then

		return Rx.Observable.just( 
				string.format( 
					"Cannot request %s: no pixel provider",
					assetId ) )

	end
	
	-- Requests either the mp4 proxy or rendition. We should not need to have both.
	-- Currently this style of rendition is only used for SWY albums with viewer role
	local videoRequestAPIName = ""
	local pixStreamID = videoType == "rendition" and getVideoRenditionPixStreamId( pixStreamIdPrefix ) 
						or getVideoProxyPixStreamId( pixStreamIdPrefix )
	
	if requestSpecialProxyOrRendition then
		videoRequestAPIName = videoType == "rendition" and "getHighResVideoSpecialRendition" or "getVideoSpecialProxy"
	else
		videoRequestAPIName = videoType == "rendition" and "getHighResVideoRendition" or "getVideoProxy"
	end

	return Rx.Observable.merge(
			makePixelProcessorVideoLoupeRequestStreamImp(
				pixelProviderProcessor, "getHighResVideoThumb",
				getHighResVideoThumbPixStreamId( pixStreamIdPrefix ), 
				assetId, priorityName ),
			makePixelProcessorVideoLoupeRequestStreamImp(
				pixelProviderProcessor, videoRequestAPIName,
				pixStreamID, 
				assetId, priorityName ) 
			)
end

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

local function make( pixelProviderProcessorStream, pixStreamIdPrefix )

	local videoAssetIdStream = Rx.Subject()

	local pixelProviderRequestStatusStream =
			Rx.Observable.combineLatest( 
					makePixelProcessorVideoLoupeRequestsStream,
						pixelProviderProcessorStream, 
						Rx.Observable.just( pixStreamIdPrefix ),
						videoAssetIdStream )
				:flatMergeAll()

	local removeVideoAssetIdStream = Rx.Subject()

	local pixelProviderRemoveRequestStatusStream =
			Rx.Observable.combineLatest( 
					removeRequestStream,
						pixelProviderProcessorStream, 
						Rx.Observable.just( pixStreamIdPrefix ),
						removeVideoAssetIdStream )
				:flatMergeAll()

	local pixelProviderResultStream =
			Rx.Observable.combineLatest( 
					describeResultStream,
						pixelProviderProcessorStream, 
						Rx.Observable.just( pixStreamIdPrefix ) )
				:switch()

	local valueStream =
				Rx.Observable.merge(
						pixelProviderRequestStatusStream,
						pixelProviderRemoveRequestStatusStream,
						pixelProviderResultStream )
					:share()

	local valueStreamSubscription =
			valueStream
				:subscribe( logInfo, logError )

	return {

		value = valueStream,

		events = {

			highPriorityRequestVideoProxy = function( _, assetId, requestSpecialProxyOrRendition )

				videoAssetIdStream
					:onNext( assetId, 
								PixelPathProviderRequestTypes.names.active_high_res_loupe_rendition, "proxy", requestSpecialProxyOrRendition )


			end,
			
			highPriorityRequestVideoRendition = function( _, assetId, requestSpecialProxyOrRendition )

				videoAssetIdStream
					:onNext( assetId, 
								PixelPathProviderRequestTypes.names.active_high_res_loupe_rendition, "rendition", requestSpecialProxyOrRendition )


			end,

			requestVideoProxy = function( _, assetId, requestSpecialProxyOrRendition )

				videoAssetIdStream
					:onNext( assetId, 
								PixelPathProviderRequestTypes.names.prefetch_high_res_loupe_rendition, "proxy", requestSpecialProxyOrRendition )

			end,
			
			requestVideoRendition = function( _, assetId, requestSpecialProxyOrRendition )

				videoAssetIdStream
					:onNext( assetId, 
								PixelPathProviderRequestTypes.names.prefetch_high_res_loupe_rendition, "rendition", requestSpecialProxyOrRendition )

			end,

			removeRequest = function( _, assetId )

				removeVideoAssetIdStream
					:onNext( assetId )

			end,

		},

		close = function()

			valueStreamSubscription:dispose()

		end,

	}

end

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

return {

	make = make,

}
