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

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

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

This file should be accessed only by WFPerformanceReport.lua.

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

	-- RxLua
local Rx = require 'Rx'
local Observable = Rx.Observable
local ReplaySubject = Rx.ReplaySubject

	-- WF.core.utils
local WFArguments = require 'WFArguments'
local WFCloseSupport = require 'WFCloseSupport'
local WFConfiguration = require 'WFConfiguration'
local KSJsonEncoder = require "KSJsonEncoder"
local KSJsonDecoder  = require "KSJsonDecoder"
local KSTableUtils = require "KSTableUtils"
local WFCapabilities = require 'WFCapabilities'

	-- WF.core.rxlua
local WFRxScheduler = require 'WFRxScheduler'

	-- WF.rtmfp.imp
local WFRtmfpClient = require 'WFRtmfpClient'

	-- WF.core.logging
local WFLogger = require 'WFLogger'

	-- WF.core.table
local WFTableArchiving = require 'WFTableArchiving'

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

local check = assert( WFArguments.check )

local logger = WFLogger 'WFPerformanceReport'
	--:setLevel 'debug'

local empEncoder = WFTableArchiving.tableToString
					
if WFConfiguration.Stamina.EMPEncoding == 'json' or 
	WFCapabilities.getCapability( 'WFPerformanceReportEncoding' ) == 'json' then
	
	empEncoder = KSJsonEncoder.encodeOzUploadJson
	
end

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

-- @mark WFPerformanceReportImp class

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

local WFPerformanceReportImp = {

	_perfReport = false,
	
	_isDaemonIdle = false,
		-- (Rx.ReplaySubject< boolean >) true if daemon is idle
	_rtmfpClient = false,
	
	_rtfmpFlow = false,
	
	WFCloseSupport.addCloseSupportMethods,

}

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

function WFPerformanceReportImp:__init()

	check( 'WFPerformanceReportImp' )

	self._perfReport = {}
	self._isDaemonIdle = ReplaySubject( 1 )
	self._isDaemonIdle:onNext( false )
	
end

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

function WFPerformanceReportImp:recordSingleValue( key, value )

	check( 'WFPerformanceReportImp', '+string', 'table' )

	self._perfReport[ #self._perfReport + 1 ] = { key = key, value = value }

	return Observable.empty()

end

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

function WFPerformanceReportImp:retrieve( optClear )

	check( 'WFPerformanceReportImp', '?boolean' )

	local result = self._perfReport or {}

	if optClear then
		self._perfReport = {}
	end

	return Observable.just( result )

end

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

function WFPerformanceReportImp:setDaemonIdle( daemonIdle )

	check( 'WFPerformanceReportImp', 'boolean' )
	self._isDaemonIdle:onNext( daemonIdle )

end

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

function WFPerformanceReportImp:isDaemonIdle()

	check( 'WFPerformanceReportImp' )
	return self._isDaemonIdle

end

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

function WFPerformanceReportImp:clearPerfReport()

	check( 'WFPerformanceReportImp' )
	self._perfReport = {}

	return Observable.empty()

end

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

function WFPerformanceReportImp:newPerformanceReport( reportName )

	check( 'WFPerformanceReportImp', '?string' )
	
	return Rx.Observable.empty()
	
end

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

function WFPerformanceReportImp:sendFormattedMessage( optClear )

	local tempCopyReport = { messages = KSTableUtils.shallowcopy( self._perfReport ), kind = "WFMessage" }
	
	if optClear then
		self._perfReport = {}
	end
	
	if next( tempCopyReport.messages ) == nil then --don't transmit table if it is "empty"
		return Observable.empty()
	else
		return self._rtfmpFlow:send( KSJsonEncoder.encodeWebSafeJson(
			{
				"message",
				empEncoder( tempCopyReport )
			} ) )
	end

end

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

function WFPerformanceReportImp:sendPerfData( interval )

	check( 'WFPerformanceReportImp', 'number' )
	
	local serverAddress
	local serverPort
	local usingEchoServer = false
	local debugSentData
	
	if WFConfiguration.Stamina.EMPPort then
		serverAddress = WFConfiguration.Stamina.EMPServerAddress or "127.0.0.1"
		serverPort = WFConfiguration.Stamina.EMPPort or 2356
	else 
		-- using WF Rtmfp echo server for testing
		serverAddress = "sj1010122073213.corp.adobe.com" -- echo server
		serverPort = 1979
		usingEchoServer = true
		debugSentData = 0
	end 
	
	logger:debugf( "Sending performance metrics to server %s and port %s", serverAddress, serverPort )

	if not self._rtmfpClient then 
		self._rtmfpClient = WFRtmfpClient()
		self._rtfmpFlow = self._rtmfpClient:openFlow( serverAddress, serverPort )
	end
			
	return Observable.timer( 0, interval, WFRxScheduler.sharedScheduler() )
		-- send the data only until Rtmfp flow is closed
		:takeUntil( self._rtfmpFlow:flowOpenStatus()
						:filter( function( status ) return status == false end ) )
		:flatMapLatest( function()
			
			if usingEchoServer then 
				if debugSentData == 1 then 
					-- for testing purpose, sending data twice and then closing the flow
					return self._rtfmpFlow:send( 'KILL_FLOW'):catch( Observable.empty() )
				elseif  debugSentData < 1 then 
					logger:debugf( "Sending performance metrics " .. debugSentData )
					debugSentData = debugSentData + 1
					return self:sendFormattedMessage( false )
				end 
			else
				return self:sendFormattedMessage( true )
			end

		end )

end

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

function WFPerformanceReportImp:DEBUG_getEchoedStream()
	
	check( 'WFPerformanceReportImp' )
	return self._rtmfpClient:listen()
		:flatMapLatest( 
			function( rtmfpRequest )
				local echoedStream  =  KSJsonDecoder.decodeWebSafeJson( rtmfpRequest:getData() )
				return Observable.just( echoedStream )
			end )

end

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

return Rx.Class 'WFPerformanceReportImp'( WFPerformanceReportImp )
