/*
 * Copyright (c) 2006 Bea Lam. All rights reserved.
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation files
 * (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//
//  BBBluetoothOBEXClient.h
//  LightAquaBlue
//
//  Implements the client side of an OBEX session over a Bluetooth transport.
//  
//  There is an example in examples/LightAquaBlue/SimpleOBEXClient that shows
//  how to use this class to connect to and send files to an OBEX server.
//

#import <Cocoa/Cocoa.h>

#import <IOBluetooth/OBEX.h>
#import <IOBluetooth/Bluetooth.h>

@class OBEXSession;
@class BBOBEXHeaderSet;
@class BBOBEXRequest;
@class IOBluetoothDevice;
@class BBOBEXResponse;
@class IOBluetoothRFCOMMChannel;

@interface BBBluetoothOBEXClient : NSObject {
    OBEXSession* mSession;
    id mDelegate;
    
    OBEXMaxPacketLength	mMaxPacketLength;
    int mLastServerResponse;
    uint32_t mConnectionID;
    BOOL mHasConnectionID;
    
    BOOL mAborting;
    
    BBOBEXRequest *mCurrentRequest;
}

/*
 * Creates a BBBluetoothOBEXClient with the given <delegate>. The client will 
 * connect to the OBEX server on the given <deviceAddress> and <channelID>.
 */
- (id)initWithRemoteDeviceAddress:(const BluetoothDeviceAddress *)deviceAddress
                        channelID:(BluetoothRFCOMMChannelID)channelID
                         delegate:(id)delegate;

/*
 * Sends a Connect request with the given <headers>. 
 * 
 * Returns kOBEXSuccess if the request was sent, or some other OBEXError value 
 * from <IOBluetooth/OBEX.h> if there was an error. The delegate is informed 
 * through client:didFinishConnectRequestWithError:responseCode:responseHeaders: 
 * when the request is finished.
 */
- (OBEXError)sendConnectRequestWithHeaders:(BBOBEXHeaderSet *)headers;

/*
 * Sends a Disconnect request with the given <headers>. 
 * 
 * Returns kOBEXSuccess if the request was sent, or some other OBEXError value 
 * from <IOBluetooth/OBEX.h> if there was an error. The delegate is informed 
 * through client:didFinishDisconnectRequestWithError:responseCode:responseHeaders: 
 * when the request is finished.
 *
 * You must have already sent a Connect request; otherwise, this fails and
 * return kOBEXSessionNotConnectedError.
 *
 * Note the Connection ID is automatically sent in the request headers if one
 * was provided by the server in a previous Connect response.
 */
- (OBEXError)sendDisconnectRequestWithHeaders:(BBOBEXHeaderSet *)headers;

/*
 * Sends a Put request with the given <headers> that will send the data from
 * the given <inputStream>. (The stream must be already open, or the request
 * will fail!) To send a Put-Delete request, set <inputStream> to nil.
 * 
 * Returns kOBEXSuccess if the request was sent, or some other OBEXError value 
 * from <IOBluetooth/OBEX.h> if there was an error. The delegate is informed 
 * through client:didFinishPutRequestForStream:error:responseCode:responseHeaders: 
 * when the request is finished.
 *
 * You must have already sent a Connect request; otherwise, this fails and
 * return kOBEXSessionNotConnectedError.
 *
 * Note the Connection ID is automatically sent in the request headers if one
 * was provided by the server in a previous Connect response.
 */
- (OBEXError)sendPutRequestWithHeaders:(BBOBEXHeaderSet *)headers
                        readFromStream:(NSInputStream *)inputStream;

/*
 * Sends a Get request with the given <headers> that will write received data
 * to the given <outputStream>. (The stream must be already open, or the request
 * will fail!)
 * 
 * Returns kOBEXSuccess if the request was sent, or some other OBEXError value 
 * from <IOBluetooth/OBEX.h> if there was an error. The delegate is informed 
 * through client:didFinishGetRequestForStream:error:responseCode:responseHeaders: 
 * when the request is finished.
 *
 * You must have already sent a Connect request; otherwise, this fails and
 * return kOBEXSessionNotConnectedError.
 *
 * Note the Connection ID is automatically sent in the request headers if one
 * was provided by the server in a previous Connect response.
 */
- (OBEXError)sendGetRequestWithHeaders:(BBOBEXHeaderSet *)headers
                         writeToStream:(NSOutputStream *)outputStream;

/*
 * Sends a SetPath request with the given <headers>. Set
 * <changeToParentDirectoryFirst> to YES if you want to move up one directory
 * (i.e. "..") before changing to the directory specified in the headers. Set
 * <createDirectoriesIfNeeded> to YES if you want to create a directory 
 * (instead of receiving an error response) if it does not currently exist.
 * 
 * Returns kOBEXSuccess if the request was sent, or some other OBEXError value 
 * from <IOBluetooth/OBEX.h> if there was an error. The delegate is informed 
 * through client:didFinishSetPathRequestWithError:responseCode:responseHeaders: 
 * when the request is finished.
 *
 * You must have already sent a Connect request; otherwise, this fails and
 * return kOBEXSessionNotConnectedError.
 *
 * Note the Connection ID is automatically sent in the request headers if one
 * was provided by the server in a previous Connect response.
 */
- (OBEXError)sendSetPathRequestWithHeaders:(BBOBEXHeaderSet *)headers
              changeToParentDirectoryFirst:(BOOL)changeToParentDirectoryFirst
                 createDirectoriesIfNeeded:(BOOL)createDirectoriesIfNeeded;

/*
 * Aborts the current request if a Put or Get request is currently in progress.
 *
 * This schedules an Abort request to be sent when possible (i.e. when the 
 * client next receives a server response).
 *
 * Returns kOBEXSuccess if the request was sent, or some other OBEXError value 
 * from <IOBluetooth/OBEX.h> if there was an error. The delegate is informed 
 * through client:didFinishAbortRequestWithError:responseCode:forStream:
 * when the Abort request is finished.
 */
- (void)abortCurrentRequest;

/*
 * Returns whether the OBEX session is connected (i.e. whether a Connect
 * request has been sent, without a following Disconnect request).
 */
- (BOOL)isConnected;

/*
 * Returns the Connection ID for the OBEX session, if one was received in a
 * response to a previous Connect request.
 *
 * This is automatically sent by the client for each request; you do not need
 * to add it to the request headers yourself.
 */
- (uint32_t)connectionID;

/*
 * Returns the RFCOMM channel for the client.
 */
- (IOBluetoothRFCOMMChannel *)RFCOMMChannel;

/*
 * Returns whether this client has a Connection ID.
 */
- (BOOL)hasConnectionID;

/*
 * Returns the maximum packet length for the OBEX session.
 */
- (OBEXMaxPacketLength)maximumPacketLength;

/*
 * Sets the client delegate to <delegate>.
 */
- (void)setDelegate:(id)delegate;

/*
 * Returns the delegate for this client.
 */
- (id)delegate;

/*
 * Sets whether debug messages should be displayed (default is NO).
 */
+ (void)setDebug:(BOOL)debug;

@end



/*
 * This informal protocol describes the methods that can be implemented for a 
 * BBBluetoothOBEXClient delegate.
 */
@protocol BBBluetoothOBEXClientDelegate

/*
 * Called when a Connect request is completed. <error> is set to kOBEXSuccess 
 * if the request finished without an error, or some other OBEXError value
 * from <IOBluetooth/OBEX.h> if an error occured. <response> contains the
 * response code and headers.
 *
 * The <error> only indicates whether the request was processed successfully;
 * use the response code in <response> to see whether the request was actually
 * accepted by the OBEX server.
 */
- (void)client:(BBBluetoothOBEXClient *)client
didFinishConnectRequestWithError:(OBEXError)error 
      response:(BBOBEXResponse *)response;

/*
 * Called when a Disconnect request is completed. <error> is set to kOBEXSuccess 
 * if the request finished without an error, or some other OBEXError value
 * from <IOBluetooth/OBEX.h> if an error occured. <response> contains the
 * response code and headers.
 *
 * The <error> only indicates whether the request was processed successfully;
 * use the response code in <response> to see whether the request was actually
 * accepted by the OBEX server.
 */
- (void)client:(BBBluetoothOBEXClient *)client
didFinishDisconnectRequestWithError:(OBEXError)error 
      response:(BBOBEXResponse *)response;

/*
 * Called when a Put request is completed. <error> is set to kOBEXSuccess 
 * if the request finished without an error, or some other OBEXError value
 * from <IOBluetooth/OBEX.h> if an error occured. The <inputStream> is the
 * stream originally passed to sendPutRequestWithHeaders:readFromStream:, and
 * <response> contains the response code and headers.
 *
 * The <error> only indicates whether the request was processed successfully;
 * use the response code in <response> to see whether the request was actually
 * accepted by the OBEX server.
 */
- (void)client:(BBBluetoothOBEXClient *)client
didFinishPutRequestForStream:(NSInputStream *)inputStream
         error:(OBEXError)error
      response:(BBOBEXResponse *)response;

/*
 * Called each time the client sends another chunk of data to the OBEX server
 * during a Put request. <length> is the number of bytes sent.
 */
- (void)client:(BBBluetoothOBEXClient *)client
  didSendDataOfLength:(unsigned)length;

/*
 * Called each time the client receives another chunk of data from the OBEX
 * server during a Get request. <length> is the number of bytes received, and
 * <totalLength> is the total number of bytes the client expects to receive
 * for the request. <totalLength> is zero if the total length is unknown.
 */
- (void)client:(BBBluetoothOBEXClient *)session
didReceiveDataOfLength:(unsigned)length
    ofTotalLength:(unsigned)totalLength;

/*
 * Called when a Get request is completed. <error> is set to kOBEXSuccess 
 * if the request finished without an error, or some other OBEXError value
 * from <IOBluetooth/OBEX.h> if an error occured. The <outputStream> is the
 * stream originally passed to sendGetRequestWithHeaders:writeToStream:, and
 * <response> contains the response code and headers. 
 *
 * The <error> only indicates whether the request was processed successfully;
 * use the response code in <response> to see whether the request was actually
 * accepted by the OBEX server.
 */
- (void)client:(BBBluetoothOBEXClient *)client
didFinishGetRequestForStream:(NSOutputStream *)outputStream
         error:(OBEXError)error
      response:(BBOBEXResponse *)response;

/*
 * Called when a SetPath request is completed. <error> is set to kOBEXSuccess 
 * if the request finished without an error, or some other OBEXError value
 * from <IOBluetooth/OBEX.h> if an error occured. <response> contains the
 * response code and headers.
 *
 * The <error> only indicates whether the request was processed successfully;
 * use the response code in <response> to see whether the request was actually
 * accepted by the OBEX server.
 */
- (void)client:(BBBluetoothOBEXClient *)client
    didFinishSetPathRequestWithError:(OBEXError)error 
      response:(BBOBEXResponse *)response;

/*
 * Called when an Abort request is completed following a call to 
 * abortCurrentRequest:. <error> is set to kOBEXSuccess 
 * if the request finished without an error, or some other OBEXError value
 * from <IOBluetooth/OBEX.h> if an error occured. The <stream> is the
 * stream originally passed to sendPutRequestWithHeaders:readFromStream: or
 * sendGetRequestWithHeaders:writeToStream:, and <response> contains the
 * response code and headers.
 *
 * The <error> only indicates whether the request was processed successfully;
 * use the response code in <response> to see whether the request was actually
 * accepted by the OBEX server.
 */
- (void)client:(BBBluetoothOBEXClient *)session
didAbortRequestWithStream:(NSStream *)stream
         error:(OBEXError)error
      response:(BBOBEXResponse *)response;

@end
