//
// © 2018-2020 Qualcomm Technologies, Inc. and/or its subsidiaries. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "IoTTypes.h"

@protocol IoTAppListenerProtocol;
@class IoTAllPlayController;
@class IoTServiceDiscoveryResult;
@class IoTPlayer;
@class IoTPlayerGroup;
@class IoTDevice;

NS_ASSUME_NONNULL_BEGIN

#pragma mark -

/**
 Represents the IoTivity stack and provides access to various model representations of groups, playlists etc.
 Whilst not enforced as a singleton, it is expected that an application would have one instance of IoTClient.
 */
@interface IoTClient : NSObject

/**
 @brief Object to notify when changes occur during service discovery or to services already discovered. All messages are sent on main queue.
 */
@property (nonatomic, weak) id<IoTAppListenerProtocol> delegate;

/**
 @brief Indicates if IoTClient instance is in running state (IoTivity stack initialised and device discovery initiated at regular intervals).
 */
@property (nonatomic, readonly) BOOL isStarted;

- (instancetype)initWithApplicationName:(NSString *)appName;

/**
 @brief Starts the IoTivity Stack and begins detection of AllPlay and IoTSys services.
 */
- (void)start;

/**
 @brief Removes all discovered AllPlay and IoTSys services from memory and tears down IoTivity stack.
 */
- (void)stop;

/**
 @brief Fetches all the currently available IoTPlayer instances. These represent the discovered AllPlay services running on the speakers.
 @return an array of IoTPlayer objects.
 */
- (NSArray<IoTPlayer *> *)getPlayers;

/**
 @brief Fetches all the currently available IoTPlayerGroup instances. These represent both grouped *and* ungrouped speakers. Ungrouped players are added to special "convenience groups" with one member.
 @return an array of IoTPlayerGroup objects.
 */
- (NSArray<IoTPlayerGroup *> *)getPlayerGroups;

/**
 @brief Fetches all the currently available IoTDevice instances. These represent the discovered IoTSys services running on the speakers.
 @return an array of IoTDevice objects.
 */
- (NSArray<IoTDevice *> *)getDevices;

/**
 @brief Return the IOTPlayer object corresponding to the given player ID.
 @param playerID the playerID for the object to be returned.
 @return the IoTPlayer object with to the given playerID. Returns nil if no object with that ID exists.
 */
- (nullable IoTPlayer *)playerForID:(NSString *)playerID;

/**
 @brief Return the IOTDevice object corresponding to the given device ID.
 @param deviceID the deviceID for the object to be returned.
 @return the IoTDevice object with to the given deviceID. Returns nil if no object with that ID exists.
 */
- (nullable IoTDevice *)deviceForID:(NSString *)deviceID;

/**
 @brief Return the IOTDevice object that represents the IoTSys service running on the same speaker as the supplied player.
 @param player the IoTPlayer instance representing the AllPlay service running on the speaker.
 @return the corresponding IoTDevice object. Returns nil if no corresponding device object exists (for example, if IoTSys is not running on that speaker).
 */
- (nullable IoTDevice *)deviceForPlayer:(IoTPlayer *)player;

/**
 @brief Return the IOTPlayer object that represents the AllPlay service running on the same speaker as the supplied IoTDevice object.
 @param device the IoTDevice instance representing the IoTSys service running on the speaker.
 @return the corresponding IOTPlayer object. Returns nil if no corresponding player object exists (for example, if AllPlay is not running on that speaker).
 */
- (nullable IoTPlayer *)playerForDevice:(IoTDevice *)device;

/**
 @brief Create a new player group with the supplied name.
 @param name the name for the new group.
 @param completion block to be called asynchronously upon completion (successful or otherwise) of the group creation.
 @param queue the dispatch queue to use when calling the completion block.
 */
- (void)createPlayerGroupWithName:(NSString *)name
                       completion:(nullable void(^)(BOOL success, NSString * _Nullable groupID, NSError * _Nullable error))completion
                  completionQueue:(nullable dispatch_queue_t)queue;

/**
 @brief Rename a player group with the supplied name.
 @param groupID the group ID of the group to be renamed.
 @param newName the new name for the group.
 @param completion block to be called asynchronously upon completion (successful or otherwise) of the group renaming.
 @param queue the dispatch queue to use when calling the completion block.
 */
- (void)renamePlayerGroupWithID:(NSString *)groupID
                        newName:(NSString *)newName
                     completion:(nullable IoTCompletionHandler)completion
                completionQueue:(nullable dispatch_queue_t)queue;

/**
 @brief Delete the player group with the given ID.
 @param groupID the group ID of the group to be deleted.
 @param completion block to be called asynchronously upon completion (successful or otherwise) of the group deletion.
 @param queue the dispatch queue to use when calling the completion block.
 */
- (void)deletePlayerGroupWithID:(NSString *)groupID
                     completion:(nullable IoTCompletionHandler)completion
                completionQueue:(nullable dispatch_queue_t)queue;

/**
 @brief Adds players (AllPlay services) to a pre-existing player group player.
 @discussion This method calls the completion block with a failed state if any of the players cannot be added to the group. The completion block may be called before the grouping state of the players has been updated.
 @param playerIDs a set of the player IDs for the players to be added to the group.
 @param groupID the group ID of the group to add the players to.
 @param completion block to be called asynchronously upon completion (successful or otherwise) of the addition.
 @param queue the dispatch queue to use when calling the completion block.
 */
- (void)addPlayersWithIDs:(NSSet<NSString *> *)playerIDs
      toPlayerGroupWithID:(NSString *)groupID
               completion:(nullable IoTCompletionHandler)completion
          completionQueue:(nullable dispatch_queue_t)queue;

/**
 @brief Remove given players from their player group.
 @discussion The completion block may be called before the grouping state of the players has been updated.
 @param playerIDs a set of the player IDs for the players to be removed from their group.
 @param completion block to be called asynchronously upon completion (successful or otherwise) of the removal.
 @param queue the dispatch queue to use when calling the completion block.
 */
- (void)removePlayersWithIDs:(NSSet<NSString *> *)playerIDs
fromPlayerGroupWithCompletion:(nullable IoTCompletionHandler)completion
             completionQueue:(nullable dispatch_queue_t)queue;

@end

NS_ASSUME_NONNULL_END
