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

WFModelsTest_Server.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2011 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 WFModelsTest_Server = {}

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

local Rx = require 'Rx'

local KSReactive = require 'KSReactive'

local WFRequestDispatcher = require 'WFRequestDispatcher'

local WFIdle = require 'WFIdle'
local KSPromises = require 'KSPromises'
local WFLogger = require 'WFLogger'

local logger = WFLogger 'WFModelsTest_Server'

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

WFRequestDispatcher.onMessage( 'not_this-message', function() end )

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

function WFModelsTest_Server.rxFromTest( inputArray )

	local values = Rx.Observable.from( inputArray )

	return { value = values, }

end

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

function WFModelsTest_Server.rxObserveDisposal( )

	local singleObserver
	local wasDisposed = Rx.BehaviorSubject( 'not disposed' )
	
	local value = Rx.Observable.create( function( observer )

		singleObserver = observer

		return function()
			wasDisposed:onNext( 'is disposed' )
			wasDisposed:onCompleted()
		end

	end )

	return {
		value = value,
		models = {
			isParentModelDisposed = function()
				return {
					value = wasDisposed,
				}
			end,
		}
	}

end

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

function WFModelsTest_Server.rxErrorTester( )

	local subscriptionCount = Rx.BehaviorSubject( 0 )
	local disposeCount = Rx.BehaviorSubject( 0 )
	local nS, nD = 0, 0
	local isClosed = Rx.BehaviorSubject( false )
	local value = Rx.Observable.create( function( observer )
		observer:onError( "Testing Model Errors" )
		nS = nS + 1
		subscriptionCount:onNext( nS )
		return function()
			nD = nD + 1
			disposeCount:onNext( nD )
		end
	end )

	return {
		value = value,
		models = {
			countSubscriptions = function()
				return {
					value = {
						isClosed = isClosed,
						subscriptionCount = subscriptionCount,
						disposeCount = disposeCount,
					},
				}
			end,
		},
		close = function()
			isClosed:onNext( true )
		end,
	}

end

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

function WFModelsTest_Server.rxErrorTester( )

	local subscriptionCount = Rx.BehaviorSubject( 0 )
	local disposeCount = Rx.BehaviorSubject( 0 )
	local nS, nD = 0, 0
	local isClosed = Rx.BehaviorSubject( false )
	local value = Rx.Observable.create( function( observer )
		observer:onError( "Testing Model Errors" )
		nS = nS + 1
		subscriptionCount:onNext( nS )
		return function()
			nD = nD + 1
			disposeCount:onNext( nD )
		end
	end )

	return {
		value = value,
		models = {
			countSubscriptions = function()
				return {
					value = {
						isClosed = isClosed,
						subscriptionCount = subscriptionCount,
						disposeCount = disposeCount,
					},
				}
			end,
		},
		close = function()
			isClosed:onNext( true )
		end,
	}

end

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

function WFModelsTest_Server.rxObserveClose( )

	local wasClosed = Rx.BehaviorSubject( 'not closed' )
	local parentValue = Rx.BehaviorSubject( 'original value' )
	local closed = false

	return {
		value = parentValue,
		models = {
			isParentModelClosed = function()
				return {
					value = wasClosed,
				}
			end,
			parentModelChanger = function()
				return {
					value = 'not interesting',
					models = {
						changeGrandParentValue = function( model, newValue )
							if not closed then
								if newValue == '< special unit test value: completed >' then
									parentValue:onCompleted()
								else
									parentValue:onNext( newValue )
								end
							end
							return {
								value = Rx.Observable.just( closed ),
							}
						end
					},
				}
			end,
		},
		close = function()
			closed = true

			wasClosed:onNext( 'now it is closed' )
			wasClosed:onCompleted()
		end
	}

end

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

function WFModelsTest_Server.simpleValueBStringTest()

	logger:debugf( "WFModelsTest_Server.simpleIntegerTest")

	local var1B = KSReactive.variableB( "foo" )

	return { valueB = var1B, }
	
end

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

function WFModelsTest_Server.simpleValueBIntegerTest()

	logger:debugf( "WFModelsTest_Server.simpleIntegerTest")

	local var1B = KSReactive.variableB( 1 )

	return { valueB = var1B, }
	
end

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

function WFModelsTest_Server.simpleValueBTableTest()

	logger:debugf( "WFModelsTest_Server.simpleIntegerTest")

	return {
		value = { foo = "bar", }
	}
	
end

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

function WFModelsTest_Server.simpleModelParamsTest( x, y, z )

	logger:debugf( "WFModelsTest_Server.simpleModelParamsTest")

	local var1B = KSReactive.variableB( x + y + z )

	return { valueB = var1B, }
	
end

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

function WFModelsTest_Server.simpleTest( x )

	logger:debugf( "WFModelsTest_Server.simpleTest, %s", x )

	return {
	
		valueB = KSReactive.variableB( x ),
		
		events = {
			echoUpper = function( self, y )
				self.valueB:set( y )
				WFIdle.onIdleDo( function()
					local valueB = self.valueB
					local x = valueB:valueNow()
					valueB:set( string.upper( x ) )
				end )
			end,
			echo = function( self, y )
				self.valueB:set( y )
			end,
			error = function( self, y )
				self.valueB:setError( y )
			end,
		},
		
		models = {
			toUpper = function( self )
				return self.valueB:mapB( string.upper )
			end
		}
	
	}
	
end

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

function WFModelsTest_Server.counter()

	local counter = 0
	
	local counterB = KSReactive.variableB( 0 )
	
	local resolvedLaterP, resolver = KSPromises.promiseP()
		-- FIXME [jandrew 2014-06-23 via scouten]: This doesn't necessarily
		-- get cleaned up and causes a close-target warning when running
		-- some of the WFModelsTest tests.
	
	resolvedLaterP = resolvedLaterP:runUntilDoneP()
	
	return {
	
		valueB = counterB:mapB( tostring ),
		
		models = {
			sub = function( self, x )

				counter = counter + 1
				counterB:set( counter )
				return {
					valueB = KSReactive.variableB( x ),
					events = {
						echo = function( self, y )
							self.valueB:set( y )
						end,
					},
					close = function()
						counter = counter - 1
						counterB:set( counter )
					end
				}
			end,
			
			subConstant = function( self, x )

				counter = counter + 1
				counterB:set( counter )
				return {
					valueB = KSReactive.constantB( x ),
					close = function()
						counter = counter - 1
						counterB:set( counter )
					end
				}
			end,
			
			rawPromise = function( self )
				return resolvedLaterP
			end,
			
			promise = function( self, x )
				return resolvedLaterP:mapDataP(
					function()
						return 'data', x
					end )
			end,
			
			resolvedPromise = function( self, x )
				return require 'KSPromises' . resolvedPromiseP( 'data', x )
			end,
			
			promiseError = function( self, x )
				return resolvedLaterP:mapDataP(
					function() return 'error', x end )
			end,
			
		},
		
		events = {
			resolvePromiseNow = function( self, x )
				resolver( 'data', x )
			end,
		},
		
		close = function()
			logger:debugf( "WFModelsTest_Server.counter closed" )
		end,
	}
	
end

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

function WFModelsTest_Server.adapter( m )

	m.valueB = m.valueB:mapB( tonumber ):mapB( function( x ) return x + 100 end ):mapB( tostring )

	m.events.resolvePromiseUpper = function( self, x )
		m.events.resolvePromiseNow( self, string.upper( x ) )
	end

end

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

function WFModelsTest_Server.rootModel( )
	return {
		_isClosed = Rx.BehaviorSubject( 'root is not closed' ),
		value = Rx.Observable.just( { root = true, } ),
		models = setmetatable(
			{
				rootClosedSubModel = function( rootModel )
					return {
						value = rootModel._isClosed,
					}
				end,
			}, {
				__index = function( self, k )
					return function( self, ... )
						return WFModelsTest_Server[ k ]( ... )
					end
				end
			}
		),
		close = function( rootModel )
			rootModel._isClosed:onNext( 'root was closed' )
			rootModel._isClosed:onCompleted()
		end,
	}
end

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

return WFModelsTest_Server

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