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

NmbDocValueToRenderInfoStreamTest.lua

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

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.

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

	-- Rx
local Rx = require 'Rx'
local Subject = Rx.Subject

	-- WF.core
local KSTableUtils = require 'KSTableUtils'
local WFFunctionUtils_map = require 'WFFunctionUtils'.map
local WFFileUtils = require 'WFFileUtils'
local KSPathUtils = require 'KSPathUtils'
local WFRxDocValueWatcher = require "WFRxDocValueWatcher"

	-- WF.core.self_test
local WFRxTestCase = require 'WFRxTestCase'

	-- WF.oz_client.managed_catalog
local WFCatMockCatalog = require 'WFCatMockCatalog'
local NmbDocValueToRenderInfoStream = require 'NmbDocValueToRenderInfoStream'
local NmbDocValueToRenderInfo = require 'NmbDocValueToRenderInfo'

local testPath = KSPathUtils.getStandardFilePath( 'carouselDocuments' )
local volumeName = WFFileUtils.volumeForPath( testPath ) 
local volumeGuid = WFFileUtils.getVolumeGuidForPath( testPath )

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

local NmbDocValueToRenderInfoStreamTest = {}

--------------------------------------------------------------------------------
-- map the _changeCounter to a constant value if it is set. This allows us
-- to test that it exists without having to bind the expected value to an
-- opaque identifier's value
--------------------------------------------------------------------------------

local function mapVolatileFieldsToConstantsForDocValue( docValue )

	local modifiedDocValue = KSTableUtils.deepCopy( docValue )

	modifiedDocValue._changeCounter = docValue._changeCounter ~= nil and
											"changeCounter" or nil

	modifiedDocValue._revId = docValue._revId ~= nil and "revId" or nil

	return modifiedDocValue

end

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

local function mapVolatileFieldsToConstants( docValues)

	return WFFunctionUtils_map( mapVolatileFieldsToConstantsForDocValue, 
									docValues )

end

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

function NmbDocValueToRenderInfoStreamTest.rxTestRenderInfoStream( rxTest )

	local catalog = WFCatMockCatalog.createFakeWFCatalog( rxTest )

	local docStore = catalog:docStore()

	local localAssetIdsStream = Subject()

	local volatileRenderInfoStreamForDocIds =
			Rx.Observable.combineLatest( 
				NmbDocValueToRenderInfoStream.renderInfoStream,
					Rx.Observable.just( docStore ),
					localAssetIdsStream )

	local renderInfoStreamForDocIds =
			volatileRenderInfoStreamForDocIds
					:switch()
					:map( mapVolatileFieldsToConstants )

	local watcher = rxTest:observe( renderInfoStreamForDocIds )

	local proxyTable = {}
	proxyTable[ '2560' ] = {
		relativePath = 'local path 2',
		volumeGuid = volumeGuid
	}
	
	local videoProxyLinks = {}
	videoProxyLinks[ '/rels/rendition_type/720p' ] = {
		href = 'server path 2'
	}

	local serverProvidedMetadataWithValidRenditions = {
			links = {
				[ '/rels/rendition_type/640' ] = {
					href = "http://fakeyVonFakenste.in/notreal.jpg"
				}
			}
		}

	local serverProvidedMetadataWithInvalidRenditions = {
			links = {
				[ '/rels/rendition_type/320' ] = {
					href = "http://fakeyVonFakenste.in/Invalidnotreal.jpg",
					invalid = true
				}
			}
		}

	rxTest:expectSingleValue(

		docStore:bulkSetDocValue {
			{
				_id = 'doc_1',
				type = 'asset',
				subtype = 'image',
				_localOnly = {
					files = {
						original = {
							master = {
								relativePath = 'local path 1',
								volumeGuid = volumeGuid
							},
						},
						proxy = proxyTable
					},
				},
				develop = {
					croppedHeight = 150,
					croppedWidth = 150,
					xmpCameraRaw = '<xmp />',
					userOrientation = 4,
				},
				rating = 3,
			},
			{
				_id = 'doc_2',
				type = 'asset',
				subtype = 'image',
				_serverProvidedMetadata = serverProvidedMetadataWithValidRenditions,
				develop = {
					croppedHeight = 250,
					croppedWidth = 252,
					xmpCameraRaw = '<xmp-2 />',
					userOrientation = 3,
				},
				rating = 1,
			},
			{
				_id = 'doc_3',
				type = 'asset',
				subtype = 'image',
				_serverProvidedMetadata = serverProvidedMetadataWithInvalidRenditions,
				develop = {
					croppedHeight = 350,
					croppedWidth = 353,
					xmpCameraRaw = '<xmp-3 />',
					userOrientation = 2,
				},
				rating = 2,
			},
			{
				_id = 'doc_4',
				type = 'asset',
				subtype = 'image',
				develop = {
					croppedHeight = 450,
					croppedWidth = 454,
					xmpCameraRaw = '<xmp />',
					userOrientation = 1,
				},
				rating = 5,
			},
			{
				_id = 'doc_5',
				type = 'asset',
				subtype = 'video',
				_localOnly = {
					files = {
						original = {
							master = {
								relativePath = 'local path 1',
								volumeGuid = volumeGuid
							},
						},
					},
				},
				_serverProvidedMetadata = {
					links = videoProxyLinks,
				},
				develop = {
					croppedHeight = 150,
					croppedWidth = 150,
					xmpCameraRaw = '<xmp />',
					userOrientation = 4,
				},
				rating = 3,
			},
			{
				_id = 'non_asset_doc',
				_localId = 'doc_6',
				wut = 'nuffin',
			},

		},

		':ignore:' )

	-- fix up the rev id on the valid rendition
	local docVal2RevId

	rxTest:expectSingleValue(
		catalog
			:docStore()
			:docValue( 'doc_2' )
			:map( 
				function( docVal2 )
					docVal2RevId = docVal2._revId
					return "got docVal2 revId"
				end ),
		"got docVal2 revId" )

	rxTest:expectSingleValue(
		docStore:bulkApplyOverlay(
			{
				{
					_id = 'doc_2',
					_serverProvidedMetadata = {
						revision_ids = { docVal2RevId }
					}
				} 
			} ),
		':ignore:' )

	-- Put some documents into the watched set. Their values should immediately
	-- be reported by the watcher, in order of appearance in the array.

	localAssetIdsStream:onNext { 'non_asset_doc', 4, 2 }

	watcher:expectData( 
		{
			{
				_changeCounter = "changeCounter",
				_id = "doc_4",
				_localId = 4,
				_revId = "revId",
				isVideo = false,
				develop = {
					croppedHeight = 450,
					croppedWidth = 454,
					xmpCameraRaw = '<xmp />',
					userOrientation = 1,
				},
				originalCannotBeRendered = false,
				hasEmbeddedXmpDevelop = true,
				hasExternalXmpDevelop = false,
				hasDevelopAuxFiles = false,
				ozProxySize = "2560",
				invalid_renditions = {},
				renditions = {},
				proxies = {},
				subtype = "image",
			},
			{
				_changeCounter = "changeCounter",
				_id = "doc_2",
				_localId = 2,
				_revId = "revId",
				isVideo = false,
				develop = {
					croppedHeight = 250,
					croppedWidth = 252,
					xmpCameraRaw = '<xmp-2 />',
					userOrientation = 3,
				},
				originalCannotBeRendered = false,
				hasEmbeddedXmpDevelop = true,
				hasExternalXmpDevelop = false,
				hasDevelopAuxFiles = false,
				ozProxySize = "2560",
				invalid_renditions = {},
				renditions = {
					{
						href = "http://fakeyVonFakenste.in/notreal.jpg",
						size = "640",
					} },
				proxies = {},
				subtype = "image",
			}
		} )

	-- Now change the watched set. Should see doc values for only the newly-
	-- included documents, in order of appearance.

	localAssetIdsStream:onNext { 1, 4, 3 }

	watcher:expectData( 
		{
			{
				_changeCounter = "changeCounter",
				_id = "doc_1",
				_localId = 1,
				_revId = "revId",
				originalPath = KSPathUtils.child( volumeName, 'local path 1' ),
				proxyPath = KSPathUtils.child( volumeName, 'local path 2' ),
				proxyPathOzBinarySubtype = '2560',
				isVideo = false,
				develop = {
					croppedHeight = 150,
					croppedWidth = 150,
					xmpCameraRaw = '<xmp />',
					userOrientation = 4,
				},
				originalCannotBeRendered = false,
				hasEmbeddedXmpDevelop = true,
				hasExternalXmpDevelop = false,
				hasDevelopAuxFiles = false,
				ozProxySize = "2560",
				renditions = {},
				invalid_renditions = {},
				proxies = {},
				subtype = "image",
			},
			{
				_changeCounter = "changeCounter",
				_id = "doc_4",
				_localId = 4,
				_revId = "revId",
				isVideo = false,
				develop = {
					croppedHeight = 450,
					croppedWidth = 454,
					xmpCameraRaw = '<xmp />',
					userOrientation = 1,
				},
				originalCannotBeRendered = false,
				hasEmbeddedXmpDevelop = true,
				hasExternalXmpDevelop = false,
				hasDevelopAuxFiles = false,
				ozProxySize = "2560",
				renditions = {},
				invalid_renditions = {},
				proxies = {},
				subtype = "image",
			},
			{
				_changeCounter = "changeCounter",
				_id = "doc_3",
				_localId = 3,
				_revId = "revId",
				isVideo = false,
				develop = {
					croppedHeight = 350,
					croppedWidth = 353,
					xmpCameraRaw = '<xmp-3 />',
					userOrientation = 2,
				},
				originalCannotBeRendered = false,
				hasEmbeddedXmpDevelop = true,
				hasExternalXmpDevelop = false,
				hasDevelopAuxFiles = false,
				ozProxySize = "2560",
				renditions = {},
				invalid_renditions = {
					{
						href = "http://fakeyVonFakenste.in/Invalidnotreal.jpg",
						size = "320",
					} },
				proxies = {},
				subtype = "image",
			}
		} )
		
	localAssetIdsStream:onNext { 5 }

	watcher:expectData( 
		{
			{
				_changeCounter = "changeCounter",
				_id = "doc_5",
				_localId = 5,
				_revId = "revId",
				isVideo = true,
				develop = {
					croppedHeight = 150,
					croppedWidth = 150,
					xmpCameraRaw = "<xmp />",
					userOrientation = 4,
				},
				originalCannotBeRendered = false,
				hasEmbeddedXmpDevelop = true,
				hasExternalXmpDevelop = false,
				hasDevelopAuxFiles = false,
				ozProxySize = "720p",
				ozProxyLink = "server path 2",
				originalPath = KSPathUtils.child( volumeName, "local path 1" ),
				proxyPathOzBinarySubtype = "720p",
				renditions = {
					{
						href = "server path 2",
						size = "720p",
					},
				},
				invalid_renditions = {},
				proxies = {
					{
						href = "server path 2",
						size = "720p",
					},
				},
				subtype = "video",
				videoDevelopVersion = {},
			},
			
		} )


end

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

function NmbDocValueToRenderInfoStreamTest.rxTestChangedRenderInfoStream( rxTest )

	local catalog = WFCatMockCatalog.createFakeWFCatalog( rxTest )

	local docStore = catalog:docStore()

	local localAssetIdsStream = Subject()

	local renderInfoStreamForDocIds =
			localAssetIdsStream
			:call( WFRxDocValueWatcher.make, docStore, "changedRenderInfoStream", true )
			:map( function( docValue )
				local renderInfo = NmbDocValueToRenderInfo.maybeExtractRenderInfoFromDocValue( docValue )
				if renderInfo then
					return { renderInfo }
				else
					return nil
				end
			end )
			:filter( function( renderInfos ) return renderInfos end )
			:map( mapVolatileFieldsToConstants )

	local watcher = rxTest:observe( renderInfoStreamForDocIds )

	local proxyTable = {}
	proxyTable[ '2560' ] = {
		relativePath = 'local path 2',
		volumeGuid = volumeGuid
	}

	rxTest:expectSingleValue(

		docStore:bulkSetDocValue {
			{
				_id = 'doc_1',
				subtype = 'image',
				_localOnly = {
					files = {
						original = {
							master = {
								relativePath = 'local path 1',
								volumeGuid = volumeGuid
							},
						},
						proxy = proxyTable
					},
				},
				develop = {
					croppedHeight = 150,
					croppedWidth = 150,
					xmpCameraRaw = '<xmp />',
					userOrientation = 4,
				},
				rating = 3,
			},
			{
				_id = 'doc_2',
				subtype = 'image',
				develop = {
					croppedHeight = 250,
					croppedWidth = 252,
					xmpCameraRaw = '<xmp-2 />',
					userOrientation = 3,
				},
				rating = 1,
			},
			{
				_id = 'doc_3',
				subtype = 'image',
				develop = {
					croppedHeight = 350,
					croppedWidth = 353,
					xmpCameraRaw = '<xmp-3 />',
					userOrientation = 2,
				},
				rating = 2,
			},
			{
				_id = 'doc_4',
				subtype = 'image',
				develop = {
					croppedHeight = 450,
					croppedWidth = 454,
					xmpCameraRaw = '<xmp />',
					userOrientation = 1,
				},
				rating = 5,
			},
			{
				_id = 'doc_6',
				wut = 'nuffin',
			},

		},

		':ignore:' )

	-- Put some documents into the watched set. Their values should immediately
	-- be reported by the watcher, in order of appearance in the array.

	localAssetIdsStream:onNext { 6, 4, 2 }

	-- Change two documents, one in the watched set, one not in the watched set.
	-- Should only see a notif for the watched doc.

	rxTest:expectSingleValue(

		docStore:bulkApplyOverlay {
			{
				_id = 'doc_1',
				flag = 'pick',
			},
			{
				_id = 'doc_2',
				flag = 'pick',
			},
		},

		':ignore:' )

	-- For now, we duplicate this notification even though nothing of interest
	-- here has changed. In future, we might try to squelch this notification.

	watcher:expectData( 
		{ 
			{
				_changeCounter = "changeCounter",
				_id = "doc_2",
				_localId = 2,
				_revId = "revId",
				isVideo = false,
				develop = {
					croppedHeight = 250,
					croppedWidth = 252,
					xmpCameraRaw = '<xmp-2 />',
					userOrientation = 3,
				},
				originalCannotBeRendered = false,
				hasEmbeddedXmpDevelop = true,
				hasExternalXmpDevelop = false,
				hasDevelopAuxFiles = false,
				ozProxySize = "2560",
				renditions = {},
				invalid_renditions = {},
				proxies = {},
				subtype = "image",
			} 
		} )

	-- Now change the watched set. 

	localAssetIdsStream:onNext { 1, 4, 3 }

	-- Now change some more doc values. Again, only those in the watched set
	-- should be relayed.

	rxTest:expectSingleValue(

		docStore:bulkApplyOverlay {
			{
				_id = 'doc_2',
				flag = 'reject',
			},
			{
				_id = 'doc_1',
				develop = {
					croppedHeight = 100,
					croppedWidth = 100,
					xmpCameraRaw = '<xmp-1a />',
				},
				flag = 'reject',
			},
		},

		':ignore:' )

	watcher:expectData( { {
		_changeCounter = "changeCounter",
		_id = "doc_1",
		_localId = 1,
		_revId = "revId",
		originalPath = KSPathUtils.child( volumeName, 'local path 1' ),
		proxyPath = KSPathUtils.child( volumeName, 'local path 2' ),
		proxyPathOzBinarySubtype = '2560',
		isVideo = false,
		develop = {
			croppedHeight = 100,
			croppedWidth = 100,
			xmpCameraRaw = '<xmp-1a />',
			userOrientation = 4,
		},
		originalCannotBeRendered = false,
		hasEmbeddedXmpDevelop = true,
		hasExternalXmpDevelop = false,
		hasDevelopAuxFiles = false,
		ozProxySize = "2560",
		renditions = {},
		invalid_renditions = {},
		proxies = {},
		subtype = "image",
	} } )

	-- Change a doc again, just to be sure we aren't taking only the first
	-- matching change for a doc.

	rxTest:expectSingleValue(

		docStore:bulkApplyOverlay {
			{
				_id = 'doc_2',
				flag = 'pick',
			},
			{
				_id = 'doc_1',
				_localOnly = {
					files = {
						original = {
							master = {
								relativePath = 'local path 1a',
								volumeGuid = volumeGuid
							},
						},
					},
				},
				flag = 'pick',
			},
		},

		':ignore:' )

	watcher:expectData( 
	 	{
			{
				_changeCounter = "changeCounter",
				_id = "doc_1",
				_localId = 1,
				_revId = "revId",
				isVideo = false,
				originalPath = KSPathUtils.child( volumeName, 'local path 1a' ),
				proxyPath = KSPathUtils.child( volumeName, 'local path 2' ),
				proxyPathOzBinarySubtype = '2560',
				develop = {
					croppedHeight = 100,
					croppedWidth = 100,
					xmpCameraRaw = '<xmp-1a />',
					userOrientation = 4,
				},
				originalCannotBeRendered = false,
				hasEmbeddedXmpDevelop = true,
				hasExternalXmpDevelop = false,
				hasDevelopAuxFiles = false,
				ozProxySize = "2560",
				renditions = {},
				invalid_renditions = {},
				proxies = {},
				subtype = "image",
			} 
		} )

end

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

return WFRxTestCase.wrapSuite( 'NmbDocValueToRenderInfoStreamTest', NmbDocValueToRenderInfoStreamTest )
