import Foundation
import Phidget22_C

/**
The Phidget NET class controls all network functionality of a Phidget program. It can be used to enable automated Phidget server discovery over the local network, and to connect to or reject specific servers. This allows for the use of remote Phidgets in your program.

You must enable server discovery or add at least one server before setting other properties of this class, such as disabling servers, or setting server passwords. Similarly, server discovery must remain enabled, or at least one server must remain added, to maintain memory of those preferences.
*/
public class NetBase {

	/**
	PhidgetServer flag indicating that the server requires a password to authenticate
	*/
	public static let authRequired: Int = 1

	/**
	Registers a server that the client will try to connect to. The client will continually try to connect to the server, increasing the time between each attempt to a maximum interval of 16 seconds.  
	  
	This call is intended for use when server discovery is not enabled.  
	  
	The server name used by this function does not have to match the name of the server running on the host machine.  
	  
	This call will fail if a server with the same name has already been discovered.  
	  
	This call will fail if `setServerPassword()` has already been called with the same server name, as `setServerPassword()` registers the server entry anticipating the discovery of the server.  
	  
	See:

	*   `removeServer()`
	*   `enableServerDiscovery()`

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- serverName: A unique name for the server (not the hostname)
		- address: The hostname or address of the server to connect to
		- port: The port number of the server to connect to
		- password: The password for the server to connect to (empty string if no password is required)
		- flags: connection flags: should be set to 0
	*/
	public static func addServer(serverName: String, address: String, port: Int, password: String = "", flags: Int = 0) throws {
		let result: PhidgetReturnCode
		result = PhidgetNet_addServer(serverName, address, Int32(port), password, Int32(flags))
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	Removes a registration for a server that the client is trying to connect to.If the client is currently connected to the server, the connection will be closed.  
	  
	If the server was discovered (not added by `addServer()`), the connection may be reestablished if and when the server is rediscovered. `disableServer()` should be used to prevent the reconnection of a discovered server  
	  
	See:

	*   `addServer()`
	*   `disableServer()`
	*   `disableServerDiscovery()`

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- serverName: The name of the server to remove
	*/
	public static func removeServer(serverName: String) throws {
		let result: PhidgetReturnCode
		result = PhidgetNet_removeServer(serverName)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	Enables attempts to connect to a discovered server, if attempts were previously disabled by `disableServer()`. All servers are enabled by default.  
	  
	This call will fail if the server was not previously added, disabled or discovered.  
	  
	See:

	*   `disableServer()`

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- serverName: The name of the server to enable
	*/
	public static func enableServer(serverName: String) throws {
		let result: PhidgetReturnCode
		result = PhidgetNet_enableServer(serverName)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	Prevents attempts to automatically connect to a server.

	By default the client will continually attempt to connect to added or discovered servers.This call will disable those attempts, but will not close an already established connection.  
	  
	See:

	*   `addServer()`
	*   `enableServer()`
	*   `enableServerDiscovery()`

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- serverName: The name of the server to stop connections to
		- flags: Should be 0
	*/
	public static func disableServer(serverName: String, flags: Int = 0) throws {
		let result: PhidgetReturnCode
		result = PhidgetNet_disableServer(serverName, Int32(flags))
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	Enables the dynamic discovery of servers that publish their identity to the network. Currently Multicast DNS is used to discover and publish Phidget servers.

	`enableServerDiscovery()` must be called once for each server type. Multiple calls for the same server type are ignored  
	  
	See:

	*   `disableServerDiscovery()`
	*   `addServer()`

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- serverType: The server type listen for
	*/
	public static func enableServerDiscovery(serverType: ServerType = .deviceRemote) throws {
		let result: PhidgetReturnCode
		result = PhidgetNet_enableServerDiscovery(PhidgetServerType(serverType.rawValue))
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	Disables the dynamic discovery of servers that publish their identity.

	`disableServerDiscovery()` does not disconnect already established connections.`removeServer()` can be used to disconnect from a server, but unless discovery is also disabled, the connection may be reestablished.  
	  
	See:

	*   `enableServerDiscovery()`
	*   `disableServer()`
	*   `removeServer()`

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- serverType: The server type to disable
	*/
	public static func disableServerDiscovery(serverType: ServerType = .deviceRemote) throws {
		let result: PhidgetReturnCode
		result = PhidgetNet_disableServerDiscovery(PhidgetServerType(serverType.rawValue))
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	Sets the password that will be used to attempt to connect to the server. If the server has not already been added or discovered, a placeholder server entry will be registered to use this password on the server once it is discovered.

	- throws:
	An error or type `PhidgetError`

	- parameters:
		- serverName: The name of the server
		- password: The password to use for the server (empty string if no password)
	*/
	public static func setServerPassword(serverName: String, password: String) throws {
		let result: PhidgetReturnCode
		result = PhidgetNet_setServerPassword(serverName, password)
		if result != EPHIDGET_OK {
			throw (PhidgetError(code: result))
		}
	}

	/**
	Subscribe to this event if you would like to know when a server has been added.

	---
	## Parameters:
	*   `server`: The server that has been added.
	*   `kv`: Opaque structure containing keys related to the server
	*/
	public static let serverAdded = StaticEvent<(server: PhidgetServer, kv: UnsafeRawPointer)> ( cinit: { PhidgetNet_setOnServerAddedHandler(nativeServerAddedHandler, nil) } )
	static let nativeServerAddedHandler : PhidgetNet_OnServerAddedCallback = { ctx, server, kv in
		Net.serverAdded.raise((PhidgetServer(server!.pointee), UnsafeRawPointer(kv!)));
	}

	/**
	Subscribe to this event if you would like to know when a server has been removed.

	---
	## Parameters:
	*   `server`: The server that has been removed.
	*/
	public static let serverRemoved = StaticEvent<PhidgetServer> ( cinit: { PhidgetNet_setOnServerRemovedHandler(nativeServerRemovedHandler, nil) } )
	static let nativeServerRemovedHandler : PhidgetNet_OnServerRemovedCallback = { ctx, server in
		Net.serverRemoved.raise(PhidgetServer(server!.pointee));
	}

}
