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

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 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 )

	return Rx.Observable.merge(
			removeRequestStreamImp(
				pixelProviderProcessor, 
				getHighResVideoThumbPixStreamId( pixStreamIdPrefix ), 
				assetId ),
			removeRequestStreamImp(
				pixelProviderProcessor, 
				getVideoProxyPixStreamId( pixStreamIdPrefix ), 
				assetId ) )

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 )

	if not pixelProviderProcessor then

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

	end

	return Rx.Observable.merge(
			makePixelProcessorVideoLoupeRequestStreamImp(
				pixelProviderProcessor, "getHighResVideoThumb",
				getHighResVideoThumbPixStreamId( pixStreamIdPrefix ), 
				assetId, priorityName ),
			makePixelProcessorVideoLoupeRequestStreamImp(
				pixelProviderProcessor, "getProxy",
				getVideoProxyPixStreamId( pixStreamIdPrefix ), 
				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 = {

			highPriorityRequest = function( _, assetId )

				videoAssetIdStream
					:onNext( assetId, 
								PixelPathProviderRequestTypes.names.active_high_res_loupe_rendition )


			end,

			request = function( _, assetId )

				videoAssetIdStream
					:onNext( assetId, 
								PixelPathProviderRequestTypes.names.prefetch_high_res_loupe_rendition )

			end,

			removeRequest = function( _, assetId )

				removeVideoAssetIdStream
					:onNext( assetId )

			end,

		},

		close = function()

			valueStreamSubscription:dispose()

		end,

	}

end

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

return {

	make = make,

}
