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

WFBonjour.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2014 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 WFRxNativeObservable = require 'WFRxNativeObservable'
local WFArguments = require 'WFArguments'
local WFBonjourImpRx_native = require 'WFBonjourImpRx_native'


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

--[[!

  \class	WFBonjour

  \brief	This namespace provides service discovery functions based on the
  			Bonjour protocol.

	You use this class to:

	- Publish sevices or update published services
	- Browse the LAN to discover published services and
	- Resolve discovered services.

	The API operates asynchronously. Each call to one of
	the API functions returns to the caller immediately, returning
	an RxLua observable. See: \ref resultValue.
	
	In most if not all cases, the observables will complete very quickly.
	Some API calls trigger long running operations in the Bonjour
	engine, for example publishing or resolving services. For those
	operations, the completion only indicates, if the respective
	operation has been successfully initiated. The API function \c observable()
	returns an event stream observable that notifies its observers about 
	operation events, progress, errors and Bonjour engine state changes.
	See: \ref events.

	When starting a potentially long running operation, like publishing 
	a service, browse for services or resolve a service, the returned
	observable includes in its notification a transparent numeric id,
	representing the respective operation as a result. This handle can be 
	stored by the observer and later be used to stop the respective operation 
	or to identify the particular operation in the event stream observer.

	To publish a service or discover and resolve services published by
	others on the network, the Bonjour engine needs to be started first.
	You start the Bonjour engine by calling the \c start() API function. Once you
	finished your Bonjour activities, the Bonjour engine should be stopped
	by calling the \c stop() API function. This call automatically stops
	all running publish, browse and resolve operations.

	To publish a service, you call the \c publishService() API function,
	providing the necessary details like port number and service type.
	This instructs the Bonjour engine to start publishing this service. 
	The event stream observer receives further notifications about the 
	progress and outcome of the operation.
	To update data for the published service, you may use the 
	\c updatePublishedService() API function. In particular, this function
	allows you to modify the key-value table (TXT record) that 
	accompanies each published service. 
	Publishing may be stopped  with a call to the \c stopPublishService() API 
	function.

	To browse for services of a particular type, published by other network nodes,
	you call the \c browseForServices() API function, providing the
	necessary arguments about the type of service to look for.
	The event stream observers receive further notifications about the
	details of discovered services, like the fully qualified service name (FQName). 
	Likewise, if a service gets unpublished,  the event stream observer gets 
	a notification about that as well. To stop a running discover operation, 
	you call the \c stopBrowseForServices()  API function.

	Before you can connect to a discovered service endpoint, the FQName needs to be 
	resolved to get the actual IP and port number for the service endpoint. 
	To resolve a FQName, you call the \c resolveService() API function,
	providing the FQName of the previously discovered service. After this call succeeds,
	the event stream observers will be notified with the details of the resolved
	endpoint, like IP and port number. To stop a running resolve operation, you call
	the \c stopResolveService() API function.

]]--

-- @mark WFBonjour namespace

local WFBonjour = {

	--[[!

		\page serviceTypes Some well-known service types

		The WFBonjour namespace defines some well-known Bonjour service
		types that can be used for publishing services as well as for
		service browsing:
		
		\see publishService()
		\see browseForServices()
		
		<table>
			<tr><th>Constant</th><th>Description</th></tr>
			<tr><td> \c kServiceTypeHttp</td><td>HTTP</td></tr>
			<tr><td> \c kServiceTypeHttpS</td><td>Secure HTTP</td></tr>
			<tr><td> \c kServiceTypeWebDAV</td><td>WebDAV</td></tr>
			<tr><td> \c kServiceTypeWebDAVS</td><td>Secure WebDAV</td></tr>
			<tr><td> \c kServiceTypeAdobePhotoshop</td><td>Adobe Photoshop</td></tr>
			<tr><td> \c kServiceTypeAdobeAcrobat</td><td>Adobe Acrobat</td></tr>
			<tr><td> \c kServiceTypeIPP</td><td>Internet Printing Protocol</td></tr>
			<tr><td> \c kServiceTypePrinter</td><td>Printer</td></tr>
			<tr><td> \c kServiceTypePDLPrinter</td><td>PDL Printer</td></tr>
			<tr><td> \c kServiceTypeDigitalPhotoSharing</td><td>Digital Photo Sharing</td></tr>
			<tr><td> \c kServiceTypeWorkstation</td><td>Workstation</td></tr>
			<tr><td> \c kServiceTypeRSS</td><td>RSS Feed</td></tr>
			<tr><td> \c kServiceTypeDNS</td><td>Domain Name Service</td></tr>
			<tr><td> \c kServiceTypeNTP</td><td>Network Time Protocol</td></tr>
			<tr><td> \c kServiceTypeSMB</td><td>SMB</td></tr>
			<tr><td> \c kServiceTypeAppleAirport</td><td>Apple Airport</td></tr>
			<tr><td> \c kServiceTypeAppleTimeMachine</td><td>Apple TimeMachine</td></tr>
			<tr><td> \c kServiceTypeAppleAFP</td><td>Apple Filing Protocol</td></tr>
			<tr><td> \c kServiceTypeAppleHomeSharing</td><td>Apple Home Sharing</td></tr>
			<tr><td> \c kServiceTypeAppleNetAssistant</td><td>Apple Network Assistant</td></tr>
			<tr><td> \c kServiceTypeAppleITunesAudioAccess</td><td>Apple Digital Audio Access Protocol (DAAP)</td></tr>
			<tr><td> \c kServiceTypeAppleITunesRemoteControl</td><td>Apple Digital Audio Control Protocol (DACP)</td></tr>
			<tr><td> \c kServiceTypeAppleAirTunesRemoteAudio</td><td>Apple Remote Audio Output Protocol (RAOP)</td></tr>
			<tr><td> \c kServiceTypeAppleIPodTouchMusicLibrary</td><td>Apple iPod Touch Music Library (DAAP share)</td></tr>
			<tr><td> \c kServiceTypeFTP</td><td>File Transfer Protocol</td></tr>
			<tr><td> \c kServiceTypeNFS</td><td>Network File System</td></tr>
			<tr><td> \c kServiceTypeSSH</td><td>Secure Shell</td></tr>
			<tr><td> \c kServiceTypeDiskShare</td><td>Apple Remote Disk Share</td></tr>
			<tr><td> \c kServiceTypeVNC</td><td>Virtual Network Computing</td></tr>
			<tr><td> \c kServiceTypeTelnet</td><td>Telnet</td></tr>
			<tr><td> \c kServiceTypeTimbuktu</td><td>Timbuktu Remote Control Software</td></tr>
			<tr><td> \c kServiceTypeRemoteDiskManagement</td><td>Remote Disk Management</td></tr>
			<tr><td> \c kServiceTypeIMAP</td><td>IMAP (EMail)</td></tr>
			<tr><td> \c kServiceTypePOP3</td><td>POP3 (EMail)</td></tr>
			<tr><td> \c kServiceTypeRTSP</td><td>Real-Time Streaming Protocol</td></tr>
			<tr><td> \c kServiceTypeRTP</td><td>Real-Time Transport Protocol</td></tr>
			<tr><td> \c kServiceTypePulseAudioServer</td><td>Pulse Audio Server</td></tr>
			<tr><td> \c kServiceTypePulseAudioSink</td><td>Pulse Audio Sink</td></tr>
			<tr><td> \c kServiceTypePulseAudioSource</td><td>Pulse Audio Source</td></tr>
			<tr><td> \c kServiceTypeMusicPlayerDaemon</td><td>Music Player Daemon</td></tr>
			<tr><td> \c kServiceTypeRemoteJukebox</td><td>Remote Jukebox</td></tr>
			<tr><td> \c kServiceTypeVLC</td><td>VideoLAN</td></tr>
			<tr><td> \c kServiceTypeSIP</td><td>SIP</td></tr>
			<tr><td> \c kServiceTypeH323</td><td>H323</td></tr>
			<tr><td> \c kServiceTypeOLPCPresence</td><td>OLPC Presence Protocol</td></tr>
			<tr><td> \c kServiceTypeAsterixExchange</td><td>Asterix Exchange</td></tr>
			<tr><td> \c kServiceTypeSkype</td><td>Skype</td></tr>
			<tr><td> \c kServiceTypeMumble</td><td>Mumble</td></tr>
			<tr><td> \c kServiceTypePostgreSQL</td><td>PostgreSQL</td></tr>
			<tr><td> \c kServiceTypeLDAP</td><td>Lightweight Directory Access Protocol</td></tr>
			<tr><td> \c kServiceTypeLightroomP2P</td><td>Lightroom P2P</td></tr>
		</table>
	
	--]]

	kServiceTypeHttp = "_http._tcp.",
	kServiceTypeHttpS = "_https._tcp.",
	kServiceTypeWebDAV = "_webdav._tcp.",
	kServiceTypeWebDAVS = "_webdavs._tcp.",
	kServiceTypeAdobePhotoshop = "_photoshopserver._tcp.",
	kServiceTypeAdobeAcrobat = "_acrobatSRV._tcp.",
	kServiceTypeIPP = "_ipp._tcp.",
	kServiceTypePrinter = "_printer._tcp.",
	kServiceTypePDLPrinter = "_pdl-datastream._tcp.",
	kServiceTypeDigitalPhotoSharing = "_dpap._tcp.",
	kServiceTypeWorkstation = "_workstation._tcp.",
	kServiceTypeRSS = "_rss._tcp.",
	kServiceTypeDNS = "_domain._udp.",
	kServiceTypeNTP = "_ntp._udp.",
	kServiceTypeSMB = "_smb._tcp.",
	kServiceTypeAppleAirport = "_airport._tcp.",
	kServiceTypeAppleTimeMachine = "_adisk._tcp.",
	kServiceTypeAppleAFP = "_afpovertcp._tcp.",
	kServiceTypeAppleHomeSharing = "_home-sharing._tcp.",
	kServiceTypeAppleNetAssistant = "_net-assistant._udp.",
	kServiceTypeAppleITunesAudioAccess = "_daap._tcp.",
	kServiceTypeAppleITunesRemoteControl = "_dacp._tcp.",
	kServiceTypeAppleAirTunesRemoteAudio = "_raop._tcp.",
	kServiceTypeAppleIPodTouchMusicLibrary = "_touch-able._tcp.",
	kServiceTypeFTP = "_ftp._tcp.",
	kServiceTypeNFS = "_nfs._tcp.",
	kServiceTypeSSH = "_sftp-ssh._tcp.",
	kServiceTypeDiskShare = "_odisk._tcp.",
	kServiceTypeVNC = "_rfb._tcp.",
	kServiceTypeTelnet = "_telnet._tcp.",
	kServiceTypeTimbuktu = "_timbuktu._tcp.",
	kServiceTypeRemoteDiskManagement = "_udisks-ssh._tcp.",
	kServiceTypeIMAP = "_imap._tcp.",
	kServiceTypePOP3 = "_pop3._tcp.",
	kServiceTypeRTSP = "_rtsp._tcp.",
	kServiceTypeRTP = "_rtp._udp.",
	kServiceTypePulseAudioServer = "_pulse-server._tcp.",
	kServiceTypePulseAudioSink = "_pulse-sink._tcp.",
	kServiceTypePulseAudioSource = "_pulse-source._tcp.",
	kServiceTypeMusicPlayerDaemon = "_mpd._tcp.",
	kServiceTypeRemoteJukebox = "_remote-jukebox._tcp.",
	kServiceTypeVLC = "_vlc-http._tcp.",
	kServiceTypeSIP = "_sip._udp.",
	kServiceTypeH323 = "_h323._tcp.",
	kServiceTypeOLPCPresence = "_presence_olpc._tcp.",
	kServiceTypeAsterixExchange = "_iax._udp.",
	kServiceTypeSkype = "_skype._tcp.",
	kServiceTypeMumble = "_mumble._tcp.",
	kServiceTypePostgreSQL = "_postgresql._tcp.",
	kServiceTypeLDAP = "_ldap._tcp.",
	kServiceTypeLightroomP2P = "_lightroomp2p._tcp.",

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

	--[[!

		\page events Event stream observable notification types
		
		These \c WFBonjour class-level string constants can be used 
		to identify the various event stream notification types.
		
		Each event stream observable notification comes with cargo
		data, a Lua table. The table items describe the nature of
		the notification and carry result data.
		
		\see observable()
		
		<table>
			<tr>
				<th>Constant</th>
				<th>Description</th>
				<th>Cargo</th>
			</tr>
			<tr>
				<td>\c kEventWillStart</td>
				<td>
					<p>Bonjour engine is about to start.</p>
					<p>This notification is always emitted once by the event stream observable, 
					immediately after the client calls the \c start() API function, right before 
					the Bonjour engine is started.</p>
					<p>After this notification, either the \c kEventDidStart or the \c kEventDidNotStart 
					notification is emitted, providing details about the outcome of the engine start 
					operation.</p>
				</td>
				<td>
					<table>
						<tr>
							<th>Key</th>
							<th>Type</th>
							<th>Description</th>
						</tr>
						<tr>
							<td>\c &quot;event&quot;</td>
							<td>String</td>
							<td>Value of \c WFBonjour.kEventWillStart</td>
						</tr>
					</table>
				</td>
			</tr>
			<tr>
				<td>\c kEventDidStart</td>
				<td>
					<p>Bonjour engine did start.</p>
					<p>This notification indicates to the observer that the Bonjour engine has been 
					successfully started.</p>
				</td>
				<td>
					<table>
						<tr>
							<th>Key</th>
							<th>Type</th>
							<th>Description</th>
						</tr>
						<tr>
							<td>\c &quot;event&quot;</td>
							<td>String</td>
							<td>Value of \c WFBonjour.kEventDidStart</td>
						</tr>
					</table>
				</td>
			</tr>
			<tr>
				<td>\c kEventDidNotStart</td>
				<td>
					<p>Bonjour engine did not start.</p>
					<p>This notification indicates to the observer that the Bonjour engine has not 
					been started.</p>
				</td>
				<td>
					<table>
						<tr>
							<th>Key</th>
							<th>Type</th>
							<th>Description</th>
						</tr>
						<tr>
							<td>\c &quot;event&quot;</td>
							<td>String</td>
							<td>Value of \c WFBonjour.kEventDidNotStart</td>
						</tr>
						<tr>
							<td>\c &quot;success&quot;</td>
							<td>Boolean</td>
							<td>\c false</td>
						</tr>
						<tr>
							<td>\c &quot;code&quot;</td>
							<td>Number</td>
							<td>Numeric result code. \ref resultCode</td>
						</tr>
						<tr>
							<td>\c &quot;platform_code&quot;</td>
							<td>Number</td>
							<td>Numeric platform-specific result code</td>
						</tr>
					</table>
				</td>
			</tr>
			<tr>
				<td>\c kEventWillStop</td>
				<td>
					<p>Bonjour engine is about to stop.</p>
					<p>This notification is always emitted once by the event stream observable, 
					immediately after the client calls the \c stop() API function, right before 
					the Bonjour engine is stopped.</p>
					<p>After this notification, either the \c kEventDidStop or the \c kEventDidNotStop 
					notification is emitted, providing details about the outcome of the engine stop 
					operation.</p>
				</td>
				<td>
					<table>
						<tr>
							<th>Key</th>
							<th>Type</th>
							<th>Description</th>
						</tr>
						<tr>
							<td>\c &quot;event&quot;</td>
							<td>String</td>
							<td>Value of \c WFBonjour.kEventWillStop</td>
						</tr>
					</table>
				</td>
			</tr>
			<tr>
				<td>\c kEventDidStop</td>
				<td>
					<p>Bonjour engine did stop.</p>
					<p>This notification indicates to the observer that the Bonjour engine has been 
					successfully stopped.</p>
				</td>
				<td>
					<table>
						<tr>
							<th>Key</th>
							<th>Type</th>
							<th>Description</th>
						</tr>
						<tr>
							<td>\c &quot;event&quot;</td>
							<td>String</td>
							<td>Value of \c WFBonjour.kEventDidStop</td>
						</tr>
					</table>
				</td>
			</tr>
			<tr>
				<td>\c kEventDidNotStop</td>
				<td>
					<p>Bonjour engine did not stop.</p>
					<p>This notification indicates to the observer that the Bonjour engine has not 
					been stopped.</p>
				</td>
				<td>
					<table>
						<tr>
							<th>Key</th>
							<th>Type</th>
							<th>Description</th>
						</tr>
						<tr>
							<td>\c &quot;event&quot;</td>
							<td>String</td>
							<td>Value of \c WFBonjour.kEventDidNotStop</td>
						</tr>
						<tr>
							<td>\c &quot;success&quot;</td>
							<td>Boolean</td>
							<td>\c false</td>
						</tr>
						<tr>
							<td>\c &quot;code&quot;</td>
							<td>Number</td>
							<td>Numeric result code. \ref resultCode</td>
						</tr>
						<tr>
							<td>\c &quot;platform_code&quot;</td>
							<td>Number</td>
							<td>Numeric platform-specific result code</td>
						</tr>
					</table>
				</td>
			</tr>
			<tr>
				<td>\c kEventDidPublishService</td>
				<td>
					<p>Service has been published.</p>
					<p>This notification is emitted one or more times after a successful call to the 
					\c publishService() API function. It notifies the observer that the service has been 
					successfully registered and published on the network. If the service has been automatically 
					renamed due to a naming conflict, this name may differ from the original name given as a 
					parameter to a \c publishService() call.</p>
				</td>
				<td>
					<table>
						<tr>
							<th>Key</th>
							<th>Type</th>
							<th>Description</th>
						</tr>
						<tr>
							<td>\c &quot;event&quot;</td>
							<td>String</td>
							<td>Value of \c WFBonjour.kEventDidPublishService</td>
						</tr>
						<tr>
							<td>\c &quot;id&quot;</td>
							<td>Number</td>
							<td>Transparent publishing operation handle for this notification</td>
						</tr>
						<tr>
							<td>\c &quot;name&quot;</td>
							<td>String</td>
							<td>The fully qualified name (FQName) of the published service</td>
						</tr>
					</table>
				</td>
			</tr>
			<tr>
				<td>\c kEventDidStopPublishService</td>
				<td>
					<p>Service has been unpublished.</p>
					<p>This notification is emitted after a successful call to the \c stopPublishService() 
					API function. It notifies the observer that the service has been successfully deregistered 
					and unpublished on the network.</p>
					<p>This notification may also be emitted without a prior call to \c stopPublishService(), 
					in case the Bonjour engine encounters an internal or network error condition for this 
					service publishing request.</p>
				</td>
				<td>
					<table>
						<tr>
							<th>Key</th>
							<th>Type</th>
							<th>Description</th>
						</tr>
						<tr>
							<td>\c &quot;event&quot;</td>
							<td>String</td>
							<td>Value of \c WFBonjour.kEventDidStopPublishService</td>
						</tr>
						<tr>
							<td>\c &quot;id&quot;</td>
							<td>Number</td>
							<td>Transparent publishing operation handle for this notification</td>
						</tr>
						<tr>
							<td>\c &quot;success&quot;</td>
							<td>Boolean</td>
							<td>\c false, if this publishing operation stopped because of an error condition</td>
						</tr>
						<tr>
							<td>\c &quot;code&quot;</td>
							<td>Number</td>
							<td>Numeric result code. \ref resultCode</td>
						</tr>
						<tr>
							<td>\c &quot;platform_code&quot;</td>
							<td>Number</td>
							<td>Numeric platform-specific result code</td>
						</tr>
					</table>
				</td>
			</tr>
			<tr>
				<td>\c kEventBrowserDidAddService</td>
				<td>
					<p>A service has been discovered during a browse operation.</p>
					<p>This notification is emitted zero or more times, for each service that is discovered 
					during a browse operation, started with a successful call to the API function 
					\c browseForServices().</p>
				</td>
				<td>
					<table>
						<tr>
							<th>Key</th>
							<th>Type</th>
							<th>Description</th>
						</tr>
						<tr>
							<td>\c &quot;event&quot;</td>
							<td>String</td>
							<td>Value of \c WFBonjour.kEventBrowserDidAddService</td>
						</tr>
						<tr>
							<td>\c &quot;id&quot;</td>
							<td>Number</td>
							<td>Transparent browse operation handle for this notification</td>
						</tr>
						<tr>
							<td>\c &quot;name&quot;</td>
							<td>String</td>
							<td>service name</td>
						</tr>
						<tr>
							<td>\c &quot;type&quot;</td>
							<td>String</td>
							<td>service type</td>
						</tr>
						<tr>
							<td>\c &quot;domain&quot;</td>
							<td>String</td>
							<td>service domain</td>
						</tr>
						<tr>
							<td>\c &quot;more&quot;</td>
							<td>Boolean</td>
							<td>\c true, if the observer can expect more notifications coming for this browse 
							operation. Not authorative. Clients should defer UI updates until this property 
							is set to \c false.</td>
						</tr>
					</table>
				</td>
			</tr>
			<tr>
				<td>\c kEventBrowserDidRemoveService</td>
				<td>
					<p>A service did disappear during a browse operation.</p>
					<p>This notification is emitted zero or more times, for each service that disappeared 
					during a browse operation, started with a successful call to the API function 
					\c browseForServices().</p>
				</td>
				<td>
					<table>
						<tr>
							<th>Key</th>
							<th>Type</th>
							<th>Description</th>
						</tr>
						<tr>
							<td>\c &quot;event&quot;</td>
							<td>String</td>
							<td>Value of \c WFBonjour.kEventBrowserDidRemoveService</td>
						</tr>
						<tr>
							<td>\c &quot;id&quot;</td>
							<td>Number</td>
							<td>Transparent browse operation handle for this notification</td>
						</tr>
						<tr>
							<td>\c &quot;name&quot;</td>
							<td>String</td>
							<td>service name</td>
						</tr>
						<tr>
							<td>\c &quot;type&quot;</td>
							<td>String</td>
							<td>service type</td>
						</tr>
						<tr>
							<td>\c &quot;domain&quot;</td>
							<td>String</td>
							<td>service domain</td>
						</tr>
						<tr>
							<td>\c &quot;more&quot;</td>
							<td>Boolean</td>
							<td>\c true, if the observer can expect more notifications coming for this browse 
							operation. Not authorative. Clients should defer UI updates until this property 
							is set to \c false.</td>
						</tr>
					</table>
				</td>
			</tr>
			<tr>
				<td>\c kEventDidResolveService</td>
				<td>
					<p>A service has been resolved.</p>
					<p>This notification is emitted zero or more times after a successful call to the API 
					function resolveService().</p>
					<p>The notification may also be emitted at any time while a resolve operation is running, 
					in case the respective service gets updated with new or modified TXT record data.</p>
				</td>
				<td>
					<table>
						<tr>
							<th>Key</th>
							<th>Type</th>
							<th>Description</th>
						</tr>
						<tr>
							<td>\c &quot;event&quot;</td>
							<td>String</td>
							<td>Value of \c WFBonjour.kEventDidResolveService</td>
						</tr>
						<tr>
							<td>\c &quot;id&quot;</td>
							<td>Number</td>
							<td>Transparent resolve operation handle for this notification</td>
						</tr>
						<tr>
							<td>\c &quot;ip&quot;</td>
							<td>String</td>
							<td>service endpoint IP address</td>
						</tr>
						<tr>
							<td>\c &quot;isIPv6&quot;</td>
							<td>Boolean</td>
							<td>\c true, if \c ip represents an IPv6 address</td>
						</tr>
						<tr>
							<td>\c &quot;port&quot;</td>
							<td>Number</td>
							<td>service endpoint port number</td>
						</tr>
						<tr>
							<td>\c &quot;txt&quot;</td>
							<td>Table</td>
							<td>Key-value table representing the TXT record data presented 
							by the service endpoint. Keys are of type string.</td>
						</tr>
					</table>
				</td>
			</tr>
		</table>
	
	--]]

	kEventWillStart = 'WFBonjourWillStart',
	kEventDidStart = 'WFBonjourDidStart',
	kEventDidNotStart = 'WFBonjourDidNotStart',
	kEventWillStop = 'WFBonjourWillStop',
	kEventDidStop = 'WFBonjourDidStop',
	kEventDidNotStop = 'WFBonjourDidNotStop',
	kEventDidPublishService = 'WFBonjourDidPublishService',
	kEventDidStopPublishService = 'WFBonjourDidStopPublishService',
	kEventBrowserDidAddService = 'WFBonjourBrowserDidAddService',
	kEventBrowserDidRemoveService = 'WFBonjourBrowserDidRemoveService',
	kEventDidResolveService = 'WFBonjourDidResolveService',


--[[!

	\page resultCode Numeric result code description

	The WFBonjour namespace defines some constants representing
	API function call numeric result codes.

	<table>
		<tr><th>Constant</th><th>Description</th></tr>
		<tr><td>\c kResultSuccess</td><td>Operation was successful.</td></tr>
		<tr><td>\c kResultFailurePrerequisite</td><td>Operation failed because of a missing or invalid prerequisite.</td></tr>
		<tr><td>\c kResultFailureLogic</td><td>Operation failed because of an internal logic error.</td></tr>
		<tr><td>\c kResultFailureArguments</td><td>Operation failed because of missing or invalid argument(s).</td></tr>
		<tr><td>\c kResultFailureOutOfResources</td><td>Operation failed due to a lack of system resources (memory, i/o etc.).</td></tr>
		<tr><td>\c kResultFailureIO</td><td>Operation failed because of an i/o failure.</td></tr>
		<tr><td>\c kResultFailureConflict</td><td>Service publishing failed due to a naming conflict.</td></tr>
		<tr><td>\c kResultFailurePlatform</td><td>Operation failed due to a platform specific error. The platform-specific error code is in \c platform_code.</td></tr>
		<tr><td>\c kResultFailureNotImplemented</td><td>Operation failed because the requested functionality is not implemented.</td></tr>
	</table>
	
	\ref resultValue
	
--]]

	kResultSuccess = 0,
	kResultFailurePrerequisite = 1,
	kResultFailureLogic = 2,
	kResultFailureArguments = 3,
	kResultFailureOutOfResources = 4,
	kResultFailureIO = 5,
	kResultFailureConflict = 6,
	kResultFailurePlatform = 7,
	kResultFailureNotImplemented = 8,

}


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

--[[!

	\page resultValue API function result observable cargo description

	All WFBonjour API functions return an RxLua observable.
	
	If the function succeeds without any additional data to be sent
	to the caller, the observable completes immediately.
	
	If the function succeeeds and has additional data to be sent to
	the caller, the observable emits exactly one notification, containing
	the result value as cargo (see below). Then it completes.
	
	If the function fails, the observable emits an error, 
	containing the result value as cargo (see below).
	
	<table>
		<tr>
			<th>Name</th>
			<th>Type</th>
			<th>Description</th>
		</tr>
		<tr>
			<td>\c &quot;success&quot;</td>
			<td>Boolean</td>
			<td>\c false, if the function call failed. In this case, 
			\c code contains the numeric error code.</td>
		</tr>
		<tr>
			<td>\c &quot;code&quot;</td>
			<td>Number</td>
			<td>Numeric function call result code. \ref resultCode</td>
		</tr>
		<tr>
			<td>\c &quot;platform_code&quot;</td>
			<td>Number</td>
			<td>Numeric platform-specific result code</td>
		</tr>
		<tr>
			<td>\c &quot;data&quot;</td>
			<td>Any (optional)</td>
			<td>Optional result data. Type varies by API function call.</td>
		</tr>
	</table>
	
--]]

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

--[[!

	\brief API function: Start the Bonjour engine.
	
	To publish a service or discover and resolve services published by
	others on the network, the Bonjour engine needs to be started first.
	You start the Bonjour engine by calling this API function. Once you
	finished your Bonjour activities, the Bonjour engine should be stopped
	by calling the \c stop() API function. This call automatically stops
	all running publish, browse and resolve operations.

	There's one Bonjour engine per process. Starting and stopping
	the engine can happen from any thread.

	Starting and stopping the engine should not be nested.
	Doing multiple consecutive calls to start or stop the engine
	is considered an error.

	\note	Starting and stopping the Bonjour engine on mobile devices should
	also be triggered by certain system lifecycle events. For example,
	on a mobile device, the Bonjour engine should be stopped when the
	app enters a background mode (depending on the actual OS capabilities)
	and could be restarted when the app comes into the foreground again.

	\return Observable. If the function succeeds, the observable completes
	immediately. Otherwise it emits the result value as an error.
	\ref resultValue
	
	\see stop()
	
--]]

function WFBonjour.start()
	return WFRxNativeObservable( WFBonjourImpRx_native.start )
end

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

--[[!

	\brief API function: Stop the Bonjour engine.
	
	Once you finished your Bonjour activities, the Bonjour engine should 
	be stopped by calling this API function. This call automatically stops 
	all running publish, browse and resolve operations.

	There's one Bonjour engine per process. Starting and stopping
	the engine can happen from any thread.

	Starting and stopping the engine should not be nested.
	Doing multiple consecutive calls to start or stop the engine
	is considered an error.

	\note	Starting and stopping the Bonjour engine on mobile devices should
	also be triggered by certain system lifecycle events. For example,
	on a mobile device, the Bonjour engine should be stopped when the
	app enters a background mode (depending on the actual OS capabilities)
	and could be restarted when the app comes into the foreground again.

	\return Observable. If the function succeeds, the observable completes
	immediately. Otherwise it emits the result value as an error.
	\ref resultValue
	
	\see start()
	
--]]

function WFBonjour.stop()
	return WFRxNativeObservable( WFBonjourImpRx_native.stop )
end

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

--[[!

	\brief API function: Put the Bonjour engine to sleep for a 
	certain period of time.

	This call can be used for debugging and testing purposes.

	\param seconds The sleep period in seconds

	\return Observable. The observable completes after the
	specified timeout has elapsed.
	
--]]

function WFBonjour.sleep( seconds )
	WFArguments.check( 'number' )
	return WFRxNativeObservable( WFBonjourImpRx_native.sleep, seconds )
end

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

--[[!

	\brief	API function: Publish a service.

	To publish a service, you call the \c publishService() API function,
	providing the necessary details like port number and service type.
	This instructs the Bonjour engine to start publishing this service. 
	The event stream observer receives further notifications about the 
	progress and outcome of the operation. See: \ref events.

	For publishing, the name, service type and port number are mandatory.
	The domain and an additional key-value table (TXT record)
	are optional. If the service name is an empty string, the Bonjour engine
	creates a name based on the computer's network host name.
	
	The auto rename parameter controls how the Bonjour engine reacts 
	in case it detects a name contention on the network, i.e. another 
	published service with the same name. If set to \c true (default), 
	it automatically selects a new name and re-publishes the service 
	until no contention is detected. Otherwise the service publishing 
	operation would fail. 
	
	If the service domain argument is omitted or passed as an empty string,
	the service is published in the local area network, which is almost 
	always what you want.

	\note The Bonjour engine needs to be started for this call to succeed.
	
	\param name The designated service name. Pass an empty string to let
	the Bonjour engine select a name based on the computer's 
	network host name.
	\param type The service type. Pass one of the well-known WFBonjour service type 
	constants, or provide your own. Must not be empty. See: \ref serviceTypes.
	\param port The port number the service is listening on for incoming connections.
	\param txtRecords An optional key-value table (TXT record). Keys are of type string. 
	This data will be visible to other network nodes after resolving this service. 
	\param autoRename \c true (default), if the Bonjour engine should automatically 
	rename this service in case it detects a service name contention on the network.
	\param domain The network domain in which the service will be published. 
	Omitting this argument or passing an empty string publishes the service in the 
	local area network, which is almost always what you want.

	\return Observable. If the function succeeds, the observable emits
	a notification and completes. The \c data member of the
	notification cargo is the transparent numeric service Id, representing this
	publish operation. Otherwise it emits the result value as an error.
	\ref resultValue

	\see updatePublishedService()
	\see stopPublishService()

--]]

function WFBonjour.publishService( name, type, port, txtRecords, autoRename, domain )
	WFArguments.check( 'string', 'string', 'number', '?table', '?boolean', '?string' )
	return WFRxNativeObservable( WFBonjourImpRx_native.publishService, name, type, port, txtRecords, autoRename, domain )
end

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

--[[!

	\brief	API function: Update a published service.

	Update the key-value dictionary (TXT record) that is associated with
	a previous published service.

	Other network nodes that are running a resolve operation on this service,
	will get another resolve notification, reflecting the changed TXT record.

	\note The Bonjour engine needs to be started for this call to succeed.
	
	\param serviceId The numeric handle (service Id) of the published service.
	\param txtRecords A key-value table (TXT record). Keys are of type string. 
	This data will be visible to other network nodes after resolving this service. 

	\return Observable. If the function succeeds, the observable completes
	immediately. Otherwise it emits the result value as an error.
	\ref resultValue

	\see publishService()

--]]

function WFBonjour.updatePublishedService( serviceId, txtRecords )
	WFArguments.check( 'number', 'table' )
	return WFRxNativeObservable( WFBonjourImpRx_native.updatePublishedService, serviceId, txtRecords )
end

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

--[[!

	\brief	API function: Stop publishing a service.

	This removes the published service's records from the Bonjour engine, so it
	will no longer be discovered by other network nodes.

	\note The Bonjour engine needs to be started for this call to succeed.

	\param serviceId The numeric handle (service Id) of the published service.

	\return Observable. If the function succeeds, the observable completes
	immediately. Otherwise it emits the result value as an error.
	\ref resultValue

	\see publishService()

--]]

function WFBonjour.stopPublishService( serviceId )
	WFArguments.check( 'number' )
	return WFRxNativeObservable( WFBonjourImpRx_native.stopPublishService, serviceId )
end

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

--[[!

	\brief	API function: Browse the network to discover new services.

	To discover services of a particular type, published by other network nodes,
	you call this API function. After this call succeeds, the event stream observable
	emits a notification for each discovered service. This notification's cargo
	include the fully qualified domain name (FQName) for the discovered service.
	See: \ref events.
	
	Likewise, if a service gets unpublished, the event stream observable emits a 
	notification for this as well.

	For browsing, the service type is mandatory. The service domain is optional. 
	If it is omitted or passed as an empty string, the browse operation looks
	for services in the local area network, which is almost always what you want.

	To stop a running discover operation, you call the \c stopBrowseForServices()
	API function.

	\note The Bonjour engine needs to be started for this call to succeed.

	\param type The service type. Pass one of the well-known WFBonjour service type 
	constants, or provide your own. Must not be empty. See: \ref serviceTypes.
	\param domain The network domain in which the Bonjour engine will browse for 
	services. Omitting the argument or passing an empty string browses in the 
	local area network, which is almost always what you want.

	\return Observable. If the function succeeds, the observable emits
	a notification and completes. The \c data member of the
	notification cargo is the transparent numeric browse request Id, representing this
	browse operation. Otherwise it emits the result value as an error.
	\ref resultValue

	\see stopBrowseForServices()
	\see resolveService()

--]]

function WFBonjour.browseForServices( type, domain )
	WFArguments.check( 'string', '?string' )
	return WFRxNativeObservable( WFBonjourImpRx_native.browseForServices, type, domain )
end

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

--[[!

	\brief	API function: Stop a running browse request.

	\note The Bonjour engine needs to be started for this call to succeed.

	\param browseRequestId The numeric handle (browse request Id) for the browse operation.

	\return Observable. If the function succeeds, the observable completes
	immediately. Otherwise it emits the result value as an error.
	\ref resultValue

	\see browseForServices()

--]]

function WFBonjour.stopBrowseForServices( browseRequestId )
	WFArguments.check( 'number' )
	return WFRxNativeObservable( WFBonjourImpRx_native.stopBrowseForServices, browseRequestId )
end

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

--[[!

	\brief	API function: Resolve a fully qualified service name (FQName) 
	to get IP and port number.

	Before you can connect to a discovered service endpoint, the FQName needs to be 
	resolved to get the actual IP and port number for the service endpoint. 
	To resolve a FQName, you call the this API function,
	providing the FQName of the previously discovered service. After this call succeeds,
	the event stream observers will be notified with the details of the resolved
	endpoint, like IP and port number. See: \ref events.
	
	To stop a running resolve operation, you call the \c stopResolveService() API function.

	\note The Bonjour engine needs to be started for this call to succeed.

	\param name The name of the service's FQName
	\param type The type of the service's FQName
	\param domain The domain of the service's FQName

	\return Observable. If the function succeeds, the observable emits
	a notification and completes. The \c data member of the
	notification cargo is the transparent numeric resolve request Id, representing this
	resolve operation. Otherwise it emits the result value as an error.
	\ref resultValue

	\see stopResolveService()

--]]

function WFBonjour.resolveService( name, type, domain )
	WFArguments.check( 'string', 'string', 'string' )
	return WFRxNativeObservable( WFBonjourImpRx_native.resolveService, name, type, domain )
end

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

--[[!

	\brief	API function: Stop a running resolve request.

	\note The Bonjour engine needs to be started for this call to succeed.

	\param resolveRequestId The numeric handle (resolve request Id) for the resolve operation.

	\return Observable. If the function succeeds, the observable completes
	immediately. Otherwise it emits the result value as an error.
	\ref resultValue

	\see resolveService()

--]]

function WFBonjour.stopResolveService( resolveRequestId )
	WFArguments.check( 'number' )
	return WFRxNativeObservable( WFBonjourImpRx_native.stopResolveService, resolveRequestId )
end

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

--[[!

	\brief	API function: Create and return new Bonjour engine 
	event stream observable.

	The event stream observables emits notifications for all long-running
	Bonjour engine operations, like publishing, browsing and resolving
	services.
	
	This API function can be called at any time from any thread,
	regardless of the current Bonjour engine state.

	\return A newly created Bonjour engine event stream observable.

--]]

function WFBonjour.observable()
	return WFRxNativeObservable( WFBonjourImpRx_native.observable )
end

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

-- @end

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

return WFBonjour
