








#import <Foundation/Foundation.h>

#import "MQTTMessage.h"
#import "MQTTPersistence.h"
#import "MQTTTransportProtocol.h"

@class MQTTSession;
@class MQTTSSLSecurityPolicy;



typedef NS_ENUM(NSInteger, MQTTSessionStatus) {
    MQTTSessionStatusCreated,
    MQTTSessionStatusConnecting,
    MQTTSessionStatusConnected,
    MQTTSessionStatusDisconnecting,
    MQTTSessionStatusClosed,
    MQTTSessionStatusError
};



typedef NS_ENUM(NSInteger, MQTTSessionEvent) {
    MQTTSessionEventConnected,
    MQTTSessionEventConnectionRefused,
    MQTTSessionEventConnectionClosed,
    MQTTSessionEventConnectionError,
    MQTTSessionEventProtocolError,
    MQTTSessionEventConnectionClosedByBroker
};



extern NSString * const MQTTSessionErrorDomain;



typedef NS_ENUM(NSInteger, MQTTSessionError) {
    MQTTSessionErrorConnectionRefused = -8, 
    MQTTSessionErrorIllegalMessageReceived = -7,
    MQTTSessionErrorDroppingOutgoingMessage = -6, 
    MQTTSessionErrorNoResponse = -6, 
    MQTTSessionErrorEncoderNotReady = -5,
    MQTTSessionErrorInvalidConnackReceived = -2, 
    MQTTSessionErrorNoConnackReceived = -1, 

    MQTTSessionErrorConnackUnacceptableProtocolVersion = 1, 
    MQTTSessionErrorConnackIdentifierRejected = 2, 
    MQTTSessionErrorConnackServeUnavailable = 3, 
    MQTTSessionErrorConnackBadUsernameOrPassword = 4, 
    MQTTSessionErrorConnackNotAuthorized = 5, 
    MQTTSessionErrorConnackReserved = 6, 
};




@protocol MQTTSessionDelegate <NSObject>

@optional



- (void)newMessage:(MQTTSession *)session
              data:(NSData *)data
           onTopic:(NSString *)topic
               qos:(MQTTQosLevel)qos
          retained:(BOOL)retained
               mid:(unsigned int)mid;



- (BOOL)newMessageWithFeedback:(MQTTSession *)session
                          data:(NSData *)data
                       onTopic:(NSString *)topic
                           qos:(MQTTQosLevel)qos
                      retained:(BOOL)retained
                           mid:(unsigned int)mid;



- (void)session:(MQTTSession*)session newMessage:(NSData*)data onTopic:(NSString*)topic;



- (void)handleEvent:(MQTTSession *)session event:(MQTTSessionEvent)eventCode error:(NSError *)error;



- (void)session:(MQTTSession*)session handleEvent:(MQTTSessionEvent)eventCode;



- (void)connected:(MQTTSession *)session;



- (void)connected:(MQTTSession *)session sessionPresent:(BOOL)sessionPresent;



- (void)connectionRefused:(MQTTSession *)session error:(NSError *)error;



- (void)connectionClosed:(MQTTSession *)session;



- (void)connectionError:(MQTTSession *)session error:(NSError *)error;



- (void)protocolError:(MQTTSession *)session error:(NSError *)error;



- (void)messageDelivered:(MQTTSession *)session msgID:(UInt16)msgID;



- (void)messageDelivered:(MQTTSession *)session
                   msgID:(UInt16)msgID
                   topic:(NSString *)topic
                    data:(NSData *)data
                     qos:(MQTTQosLevel)qos
              retainFlag:(BOOL)retainFlag;



- (void)subAckReceived:(MQTTSession *)session msgID:(UInt16)msgID grantedQoss:(NSArray<NSNumber *> *)qoss;



- (void)unsubAckReceived:(MQTTSession *)session msgID:(UInt16)msgID;



- (void)sending:(MQTTSession *)session type:(MQTTCommandType)type qos:(MQTTQosLevel)qos retained:(BOOL)retained duped:(BOOL)duped mid:(UInt16)mid data:(NSData *)data;



- (void)received:(MQTTSession *)session type:(MQTTCommandType)type qos:(MQTTQosLevel)qos retained:(BOOL)retained duped:(BOOL)duped mid:(UInt16)mid data:(NSData *)data;



- (BOOL)ignoreReceived:(MQTTSession *)session type:(MQTTCommandType)type qos:(MQTTQosLevel)qos retained:(BOOL)retained duped:(BOOL)duped mid:(UInt16)mid data:(NSData *)data;



- (void)buffered:(MQTTSession *)session
          queued:(NSUInteger)queued
       flowingIn:(NSUInteger)flowingIn
      flowingOut:(NSUInteger)flowingOut;



- (void)buffered:(MQTTSession *)session
       flowingIn:(NSUInteger)flowingIn
      flowingOut:(NSUInteger)flowingOut;

@end

typedef void (^MQTTConnectHandler)(NSError *error);
typedef void (^MQTTDisconnectHandler)(NSError *error);
typedef void (^MQTTSubscribeHandler)(NSError *error, NSArray<NSNumber *> *gQoss);
typedef void (^MQTTUnsubscribeHandler)(NSError *error);
typedef void (^MQTTPublishHandler)(NSError *error);




@interface MQTTSession : NSObject



@property (weak, nonatomic) id<MQTTSessionDelegate> delegate;



@property (strong, nonatomic) id<MQTTPersistence> persistence;



@property (copy, nonatomic) MQTTConnectHandler connectHandler;



@property (strong) void (^connectionHandler)(MQTTSessionEvent event);



@property (strong) void (^messageHandler)(NSData* message, NSString* topic);



@property (nonatomic, readonly) MQTTSessionStatus status;



@property (nonatomic, readonly) BOOL sessionPresent;



@property (strong, nonatomic) NSString *streamSSLLevel;



@property (readonly) NSString *host;



@property (readonly) UInt32 port;



@property (strong, nonatomic) NSString *clientId;



@property (strong, nonatomic) NSString *userName;



@property (strong, nonatomic) NSString *password;



@property (nonatomic) UInt16 keepAliveInterval;



@property (readonly, strong, nonatomic) NSNumber *serverKeepAlive;



@property (readonly, nonatomic) UInt16 effectiveKeepAlive;




@property (nonatomic) double dupTimeout;



@property (nonatomic) BOOL cleanSessionFlag;



@property (nonatomic) BOOL willFlag;



@property (strong, nonatomic) NSString *willTopic;



@property (strong, nonatomic) NSData *willMsg;



@property (nonatomic) MQTTQosLevel willQoS;



@property (nonatomic) BOOL willRetainFlag;



@property (nonatomic) MQTTProtocolVersion protocolLevel;



@property (strong, nonatomic) NSNumber *sessionExpiryInterval;



@property (strong, nonatomic) NSString *authMethod;



@property (strong, nonatomic) NSData *authData;



@property (strong, nonatomic) NSNumber *requestProblemInformation;



@property (strong, nonatomic) NSNumber *willDelayInterval;



@property (strong, nonatomic) NSNumber *requestResponseInformation;



@property (strong, nonatomic) NSNumber *receiveMaximum;



@property (strong, nonatomic) NSNumber *topicAliasMaximum;



@property (strong, nonatomic) NSDictionary <NSString *, NSString*> *userProperty;



@property (strong, nonatomic) NSNumber *maximumPacketSize;



@property (strong, nonatomic) dispatch_queue_t queue;




@property (strong, nonatomic) MQTTMessage *connectMessage;



@property (strong, nonatomic) id <MQTTTransport> transport;



@property (strong, nonatomic) NSArray *certificates;



@property (nonatomic) BOOL voip;





- (void)connect;




- (void)connectWithConnectHandler:(MQTTConnectHandler)connectHandler;




- (void)disconnect;



- (void)disconnectWithReturnCode:(MQTTReturnCode)returnCode
           sessionExpiryInterval:(NSNumber *)sessionExpiryInterval
                    reasonString:(NSString *)reasonString
                    userProperty:(NSDictionary <NSString *, NSString *> *)userProperty;




- (MQTTSession *)init;






- (UInt16)subscribeToTopic:(NSString *)topic
                   atLevel:(MQTTQosLevel)qosLevel;



- (UInt16)subscribeToTopic:(NSString *)topic
                   atLevel:(MQTTQosLevel)qosLevel
          subscribeHandler:(MQTTSubscribeHandler)subscribeHandler;





- (UInt16)subscribeToTopics:(NSDictionary<NSString *, NSNumber *> *)topics;





- (UInt16)subscribeToTopics:(NSDictionary<NSString *, NSNumber *> *)topics
           subscribeHandler:(MQTTSubscribeHandler)subscribeHandler;




- (UInt16)unsubscribeTopic:(NSString *)topic;





- (UInt16)unsubscribeTopic:(NSString *)topic
        unsubscribeHandler:(MQTTUnsubscribeHandler)unsubscribeHandler;




- (UInt16)unsubscribeTopics:(NSArray<NSString *> *)topics;



- (UInt16)unsubscribeTopics:(NSArray<NSString *> *)topics
         unsubscribeHandler:(MQTTUnsubscribeHandler)unsubscribeHandler;




- (UInt16)publishData:(NSData *)data
              onTopic:(NSString *)topic
               retain:(BOOL)retainFlag
                  qos:(MQTTQosLevel)qos;




- (UInt16)publishData:(NSData *)data
              onTopic:(NSString *)topic
               retain:(BOOL)retainFlag
                  qos:(MQTTQosLevel)qos
       publishHandler:(MQTTPublishHandler)publishHandler;



- (void)closeWithDisconnectHandler:(MQTTDisconnectHandler)disconnectHandler;



- (void)closeWithReturnCode:(MQTTReturnCode)returnCode
      sessionExpiryInterval:(NSNumber *)sessionExpiryInterval
               reasonString:(NSString *)reasonString
               userProperty:(NSDictionary <NSString *, NSString *> *)userProperty
          disconnectHandler:(MQTTDisconnectHandler)disconnectHandler;

@end
