//
//  AFConnectionServer.h
//  Amber
//
//  Created by Keith Duncan on 25/12/2008.
//  Copyright 2008. All rights reserved.
//

#import "CoreNetworking/AFNetworkLayer.h"

#import "CoreNetworking/AFNetworkTypes.h"
#import "CoreNetworking/AFNetworkConnectionLayer.h"

@class AFNetworkSocket;
@class AFNetworkPool;
@class AFNetworkServer;

/*!
	\brief
	The server should consult the delegate for conditional operations. If your subclass provides a delegate protocol, it should conform to this one too.
 */
@protocol AFNetworkServerDelegate <AFNetworkConnectionLayerHostDelegate>

 @optional

/*
	\brief
	You can return FALSE to deny connectivity.
 
	\details
	Sent before the first layer is encapsulated.
 */
- (BOOL)networkServer:(AFNetworkServer *)server shouldAcceptConnection:(id <AFNetworkConnectionLayer>)connection;

/*!
	\brief
	Sent after each layer is encapsulated; before it is opened.
 */
- (void)networkServer:(AFNetworkServer *)server didEncapsulateLayer:(id <AFNetworkConnectionLayer>)connection;

@end


/*!
	\brief
	A generic construct for spawning new client layers.
	
	\details
	After instantiating the server you can use one of the convenience methods to open socket(s)
 */
@interface AFNetworkServer : NSObject <AFNetworkServerDelegate, AFNetworkConnectionLayerHostDelegate> {
 @private
	id <AFNetworkServerDelegate> _delegate;
	
	NSArray *_encapsulationClasses;
	NSArray *_clientPools;
	
	void *_dynamicStore;
	void *_dynamicStoreSource;
}

/*
	Addressing
 */

+ (NSSet *)localhostInternetSocketAddresses /* __attribute__((deprecated)) */;
+ (NSSet *)allInternetSocketAddresses /* __attribute__((deprecated)) */;

/*
	Initialization
 */

/*!
	\brief
	Designated Constructor.
	
	\details
	Call the designated initialiser with an appropriate encapsulation class.
	By default this creates a server with <tt>AFNetworkTransport</tt> as the encapsulation class.
	Subclasses should override this method.
 */
+ (id)server;

/*!
	\brief
	Designated Initialiser.
 */
- (id)initWithEncapsulationClass:(Class)encapsulationClass;

/*
	State
 */

/*!
	\brief
	The delegate is optional in this class, most servers should function without one
 */
@property (assign, nonatomic) id <AFNetworkServerDelegate> delegate;

/*
	Socket Opening
 */

/*!
	\brief
	See <tt>-openInternetSocketsWithSocketSignature:port:addresses:</tt>.
 */
- (BOOL)openInternetSocketsWithTransportSignature:(AFNetworkInternetTransportSignature const)signature socketAddresses:(NSSet *)socketAddresses errorHandler:(BOOL (^)(NSData *, NSError *))errorHandler;

/*!
	\brief
	Open IP sockets, the addresses passed in |sockaddrs| should be either (struct sockaddr_in) or (struct sockaddr_in6) or another future IP socket address, so long as there's a sixteen bit port number at an offset of (((uint8_t)(struct sockaddr_sa *))+16)
	
	\param port
	In-out parameter, passing zero in by reference will have the kernel allocate a port number, the location you provide will contain that number on return
	
	\param errorHandler
	Optional parameter, can be nil.
	If non-nil, the block is invoked for each error that occurs. Parameters to the block are the socket address on which an error occurred and the error. When the error handler returns YES, enumeration continues if possible. Enumeration stops immediately when the error handler returns NO.
	
	\return
	If any of the socket objects cannot be created and bound, and there isn't an errorHandler, this method closes any sockets that were successfully created and returns NO.
	If there is an errorHandler provided and it returns NO, this method again closes any sockets that were successfully created and returns NO.
	Otherwise if all the sockets are created and bound successfully, or there was an error and the errorHandler returned YES, this method returns YES.
 */
- (BOOL)openInternetSocketsWithSocketSignature:(AFNetworkSocketSignature const)signature port:(inout uint16_t *)portRef socketAddresses:(NSSet *)socketAddresses errorHandler:(BOOL (^)(NSData *, NSError *))errorHandler;

/*!
	\brief
	This method opens a UNIX socket at the specified path.
	
	\details
	This method makes no provisions for deleting an existing socket should it exist, and will fail if one does.
	
	\param location
	Only file:// URLs are supported, an exception is thrown if you provide another scheme.
	
	\return
	Returns NO if the socket couldn't be created.
 */
- (BOOL)openPathSocketWithLocation:(NSURL *)location error:(NSError **)errorRef;

/*!
	\brief
	Funnel method, all the socket opening methods call this one.
	
	\details
	Rarely applicable to call for higher-level servers, sockets are typically opened on the lowest layer of the stack.
 */
- (AFNetworkSocket *)openSocketWithSignature:(AFNetworkSocketSignature const)signature address:(NSData *)address error:(NSError **)errorRef;

/*
	Server Clients
 */

/*!
	\brief
	Determines the class of the |layer| parameter and wraps it in the encapsulation class one higher than it.
	
	\details
	Override point, if you need to customize layers before they are added to their connection pool, call super for creation first.
 */
- (void)encapsulateNetworkLayer:(id <AFNetworkConnectionLayer>)layer;

/*!
	\brief
	The pools of interest are likely to be the lowest level at index 0 containing the AFNetworkSockets and the top most pool containing the top-level connection objects this server has created.
 */
@property (readonly, retain, nonatomic) NSArray *clientPools;

@end
