//
// ZYJMQTTMessage.h
// ZYJMQTTClient.framework
//
// Copyright © 2013-2017, Christoph Krey. All rights reserved.
//
// based on
//
// Copyright (c) 2011, 2013, 2lemetry LLC
//
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// Contributors:
//    Kyle Roche - initial API and implementation and/or initial documentation
//

#import <Foundation/Foundation.h>
@class ZYJMQTTProperties;

/**
 Enumeration of ZYJMQTT Quality of Service levels
 */
typedef NS_ENUM(UInt8, ZYJMQTTQosLevel) {
    ZYJMQTTQosLevelAtMostOnce = 0,
    ZYJMQTTQosLevelAtLeastOnce = 1,
    ZYJMQTTQosLevelExactlyOnce = 2
};

/**
 Enumeration of ZYJMQTT protocol version
 */
typedef NS_ENUM(UInt8, ZYJMQTTProtocolVersion) {
    ZYJMQTTProtocolVersion0 = 0,
    ZYJMQTTProtocolVersion31 = 3,
    ZYJMQTTProtocolVersion311 = 4,
    ZYJMQTTProtocolVersion50 = 5
};

typedef NS_ENUM(UInt8, ZYJMQTTCommandType) {
    ZYJMQTT_None = 0,
    ZYJMQTTConnect = 1,
    ZYJMQTTConnack = 2,
    ZYJMQTTPublish = 3,
    ZYJMQTTPuback = 4,
    ZYJMQTTPubrec = 5,
    ZYJMQTTPubrel = 6,
    ZYJMQTTPubcomp = 7,
    ZYJMQTTSubscribe = 8,
    ZYJMQTTSuback = 9,
    ZYJMQTTUnsubscribe = 10,
    ZYJMQTTUnsuback = 11,
    ZYJMQTTPingreq = 12,
    ZYJMQTTPingresp = 13,
    ZYJMQTTDisconnect = 14,
    ZYJMQTTAuth = 15
};

@interface ZYJMQTTMessage : NSObject

@property (nonatomic) ZYJMQTTCommandType type;
@property (nonatomic) ZYJMQTTQosLevel qos;
@property (nonatomic) BOOL retainFlag;
@property (nonatomic) BOOL dupFlag;
@property (nonatomic) UInt16 mid;
@property (strong, nonatomic) NSData *data;
@property (strong, nonatomic) NSNumber *returnCode;
@property (strong, nonatomic) NSNumber *connectAcknowledgeFlags;
@property (strong, nonatomic) ZYJMQTTProperties *properties;

/**
 Enumeration of ZYJMQTT return codes
 */

typedef NS_ENUM(NSUInteger, ZYJMQTTReturnCode) {
    ZYJMQTTAccepted = 0,
    ZYJMQTTRefusedUnacceptableProtocolVersion = 1,
    ZYJMQTTRefusedIdentiferRejected = 2,
    ZYJMQTTRefusedServerUnavailable = 3,
    ZYJMQTTRefusedBadUserNameOrPassword = 4,
    ZYJMQTTRefusedNotAuthorized = 5,

    ZYJMQTTSuccess = 0,
    ZYJMQTTDisconnectWithWillMessage = 4,
    ZYJMQTTNoSubscriptionExisted = 17,
    ZYJMQTTContinueAuthentication = 24,
    ZYJMQTTReAuthenticate = 25,
    ZYJMQTTUnspecifiedError = 128,
    ZYJMQTTMalformedPacket = 129,
    ZYJMQTTProtocolError = 130,
    ZYJMQTTImplementationSpecificError = 131,
    ZYJMQTTUnsupportedProtocolVersion = 132,
    ZYJMQTTClientIdentifierNotValid = 133,
    ZYJMQTTBadUserNameOrPassword = 134,
    ZYJMQTTNotAuthorized = 135,
    ZYJMQTTServerUnavailable = 136,
    ZYJMQTTServerBusy = 137,
    ZYJMQTTBanned = 138,
    ZYJMQTTServerShuttingDown = 139,
    ZYJMQTTBadAuthenticationMethod = 140,
    ZYJMQTTKeepAliveTimeout = 141,
    ZYJMQTTSessionTakenOver = 142,
    ZYJMQTTTopicFilterInvalid = 143,
    ZYJMQTTTopicNameInvalid = 144,
    ZYJMQTTPacketIdentifierInUse = 145,
    ZYJMQTTPacketIdentifierNotFound = 146,
    ZYJMQTTReceiveMaximumExceeded = 147,
    ZYJMQTTPacketTooLarge = 149,
    ZYJMQTTMessageRateTooHigh = 150,
    ZYJMQTTQuotaExceeded = 151,
    ZYJMQTTAdministrativeAction = 152,
    ZYJMQTTPayloadFormatInvalid = 153,
    ZYJMQTTRetainNotSupported = 154,
    ZYJMQTTQoSNotSupported = 155,
    ZYJMQTTUseAnotherServer = 156,
    ZYJMQTTServerMoved = 157,
    ZYJMQTTSharedSubscriptionNotSupported = 158,
    ZYJMQTTConnectionRateExceeded = 159,
    ZYJMQTTSubscriptionIdentifiersNotSupported = 161,
    ZYJMQTTWildcardSubscriptionNotSupported = 162
};

// factory methods
+ (ZYJMQTTMessage *)connectMessageWithClientId:(NSString*)clientId
                                   userName:(NSString*)userName
                                   password:(NSString*)password
                                  keepAlive:(NSInteger)keeplive
                               cleanSession:(BOOL)cleanSessionFlag
                                       will:(BOOL)will
                                  willTopic:(NSString*)willTopic
                                    willMsg:(NSData*)willData
                                    willQoS:(ZYJMQTTQosLevel)willQoS
                                 willRetain:(BOOL)willRetainFlag
                              protocolLevel:(ZYJMQTTProtocolVersion)protocolLevel
                      sessionExpiryInterval:(NSNumber *)sessionExpiryInterval
                                 authMethod:(NSString *)authMethod
                                   authData:(NSData *)authData
                  requestProblemInformation:(NSNumber *)requestProblemInformation
                          willDelayInterval:(NSNumber *)willDelayInterval
                 requestResponseInformation:(NSNumber *)requestResponseInformation
                             receiveMaximum:(NSNumber *)receiveMaximum
                          topicAliasMaximum:(NSNumber *)topicAliasMaximum
                               userProperty:(NSDictionary <NSString *, NSString *> *)userProperty
                          maximumPacketSize:(NSNumber *)maximumPacketSize
;

+ (ZYJMQTTMessage *)pingreqMessage;

+ (ZYJMQTTMessage *)disconnectMessage:(ZYJMQTTProtocolVersion)protocolLevel
                        returnCode:(ZYJMQTTReturnCode)returnCode
             sessionExpiryInterval:(NSNumber *)sessionExpiryInterval
                      reasonString:(NSString *)reasonString
                      userProperty:(NSDictionary <NSString *, NSString *> *)userProperty;

+ (ZYJMQTTMessage *)subscribeMessageWithMessageId:(UInt16)msgId
                                        topics:(NSDictionary *)topics
                                 protocolLevel:(ZYJMQTTProtocolVersion)protocolLevel
                        subscriptionIdentifier:(NSNumber *)subscriptionIdentifier;

+ (ZYJMQTTMessage *)unsubscribeMessageWithMessageId:(UInt16)msgId
                                          topics:(NSArray *)topics
                                   protocolLevel:(ZYJMQTTProtocolVersion)protocolLevel;

+ (ZYJMQTTMessage *)publishMessageWithData:(NSData*)payload
                                onTopic:(NSString*)topic
                                    qos:(ZYJMQTTQosLevel)qosLevel
                                  msgId:(UInt16)msgId
                             retainFlag:(BOOL)retain
                                dupFlag:(BOOL)dup
                          protocolLevel:(ZYJMQTTProtocolVersion)protocolLevel
                 payloadFormatIndicator:(NSNumber *)payloadFormatIndicator
              publicationExpiryInterval:(NSNumber *)publicationExpiryInterval
                             topicAlias:(NSNumber *)topicAlias
                          responseTopic:(NSString *)responseTopic
                        correlationData:(NSData *)correlationData
                           userProperty:(NSDictionary <NSString *, NSString *> *)userProperty
                            contentType:(NSString *)contentType;

+ (ZYJMQTTMessage *)pubackMessageWithMessageId:(UInt16)msgId
                              protocolLevel:(ZYJMQTTProtocolVersion)protocolLevel
                                 returnCode:(ZYJMQTTReturnCode)returnCode
                               reasonString:(NSString *)reasonString
                               userProperty:(NSDictionary <NSString *, NSString *> *)userProperty;

+ (ZYJMQTTMessage *)pubrecMessageWithMessageId:(UInt16)msgId
                              protocolLevel:(ZYJMQTTProtocolVersion)protocolLevel
                                 returnCode:(ZYJMQTTReturnCode)returnCode
                               reasonString:(NSString *)reasonString
                               userProperty:(NSDictionary <NSString *, NSString *> *)userProperty;

+ (ZYJMQTTMessage *)pubrelMessageWithMessageId:(UInt16)msgId
                              protocolLevel:(ZYJMQTTProtocolVersion)protocolLevel
                                 returnCode:(ZYJMQTTReturnCode)returnCode
                               reasonString:(NSString *)reasonString
                               userProperty:(NSDictionary <NSString *, NSString *> *)userProperty;

+ (ZYJMQTTMessage *)pubcompMessageWithMessageId:(UInt16)msgId
                               protocolLevel:(ZYJMQTTProtocolVersion)protocolLevel
                                  returnCode:(ZYJMQTTReturnCode)returnCode
                                reasonString:(NSString *)reasonString
                                userProperty:(NSDictionary <NSString *, NSString *> *)userProperty;

+ (ZYJMQTTMessage *)messageFromData:(NSData *)data protocolLevel:(ZYJMQTTProtocolVersion)protocolLevel;

// instance methods
- (instancetype)initWithType:(ZYJMQTTCommandType)type;
- (instancetype)initWithType:(ZYJMQTTCommandType)type
                        data:(NSData *)data;
- (instancetype)initWithType:(ZYJMQTTCommandType)type
                         qos:(ZYJMQTTQosLevel)qos
                        data:(NSData *)data;
- (instancetype)initWithType:(ZYJMQTTCommandType)type
                         qos:(ZYJMQTTQosLevel)qos
                  retainFlag:(BOOL)retainFlag
                     dupFlag:(BOOL)dupFlag
                        data:(NSData *)data;

@property (NS_NONATOMIC_IOSONLY, readonly, copy) NSData *wireFormat;


@end

@interface NSMutableData (ZYJMQTT)
- (void)appendByte:(UInt8)byte;
- (void)appendUInt16BigEndian:(UInt16)val;
- (void)appendUInt32BigEndian:(UInt32)val;
- (void)appendVariableLength:(unsigned long)length;
- (void)appendZYJMQTTString:(NSString *)string;
- (void)appendBinaryData:(NSData *)data;

@end
