//
//  XPSDKVideoConnectionFrame.h
//  XProtect
//
//  Created by Aleksandra Spirovska on 11/29/17.
//  Copyright © 2017 Milestone Systems A/S. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "XPSDKVideoConnection.h"

typedef enum {
    XPSDKVideoConnectionFrameHeaderExtensionSize = 0x01,
    XPSDKVideoConnectionFrameHeaderExtensionLive = 0x02,
    XPSDKVideoConnectionFrameHeaderExtensionPlayback = 0x04,
    XPSDKVideoConnectionFrameHeaderExtensionNativeData = 0x08,
    XPSDKVideoConnectionFrameHeaderExtensionMotionEvents = 0x10,//arcus only
    XPSDKVideoConnectionFrameHeaderLocationInfo = 0x20,
    XPSDKVideoConnectionFrameHeaderStreamInfo = 0x40,
    XPSDKVideoConnectionFrameHeaderExtensionCarousel = 0x80,
    XPSDKVideoConnectionFrameheaderAll = 0xFF
}  XPSDKVideoConnectionFrameHeaderExtensionFlags;

typedef short unsigned int XPSDKVideoConnectionFrameHeaderExtensionMask;

typedef enum {
    XPSDKVideoConnectionFrameLiveFeed = 1,
    XPSDKVideoConnectionFrameMotion = 2,
    XPSDKVideoConnectionFrameRecording = 4,
    XPSDKVideoConnectionFrameNotification = 8,
    XPSDKVideoConnectionFrameCameraConnectionLost = 16,
    XPSDKVideoConnectionFrameDatabaseFail = 32,
    XPSDKVideoConnectionFrameDiskFull = 64,
    XPSDKVideoConnectionFrameClientLiveStopped = 128
} XPSDKVideoConnectionFrameLiveFlags;

typedef unsigned int XPSDKVideoConnectionFrameLiveEventsMask;

typedef enum {
    XPSDKVideoConnectionFramePlayStopped =     0x1,
    XPSDKVideoConnectionFramePlayForward =     0x2,
    XPSDKVideoConnectionFramePlayBackward =    0x4,
    XPSDKVideoConnectionFrameDatabaseStart =   0x10,
    XPSDKVideoConnectionFrameDatabaseEnd =     0x20,
    XPSDKVideoConnectionFrameDatabaseError =   0x40
} XPSDKVideoConnectionFramePlaybackFlags;

typedef unsigned int XPSDKVideoConnectionFramePlaybackEventsMask;

/*!
 The XPSDKVideoConnectionFrame represents a frame of video, sent over video connection.
 A frame always contains a header, may contain one or more header extensions and may contain a single (JPEG encoded) image.
 This class provides methods to analyze binary data and determine if it contains a complete and valid frame to be parsed. Use them before attempting to init an instance.
 
 */
@interface XPSDKVideoConnectionFrame : NSObject {
@private
    XPSDKVideoID videoID;
    NSDate * timestamp;
    long long timestamp_ms;
    NSUInteger frameNumber;
    XPSDKVideoConnectionFrameHeaderExtensionMask headerExtensionFlags;
    
    CGSize sourceSize;
    UIEdgeInsets sourceCrop;
    CGSize destinationSize;
    NSUInteger resamplingTag;
    
    XPSDKVideoConnectionFrameLiveEventsMask currentLiveEvents;
    XPSDKVideoConnectionFrameLiveEventsMask changedLiveEvents;
    XPSDKVideoConnectionFrameLiveEventsMask hasFrameStreamInfo;
    
    XPSDKVideoConnectionFramePlaybackEventsMask currentPlaybackEvents;
    XPSDKVideoConnectionFramePlaybackEventsMask changedPlaybackEvents;
    XPSDKVideoConnectionFramePlaybackEventsMask headerStreamInfo;
    
    UIImage * image;
}

@property (nonatomic, readonly) XPSDKVideoID videoID; /// ID of the video as specified in the frame's header
@property (nonatomic) NSDate * timestamp; /// Timestamp of the frame
@property (nonatomic, readonly) NSUInteger frameNumber; /// Index of the frame (not used at the moment)
@property (nonatomic, readonly) long long timestamp_ms; /// Timestamp of the frame (in ms)

@property (strong, nonatomic) NSString *carouselVideoID;

/// @{ 
/// header extension flags
@property (nonatomic, readonly) BOOL hasSizeInformation;
@property (nonatomic, readonly) BOOL hasLiveInformation;
@property (nonatomic, readonly) BOOL hasPlaybackInformation;
@property (nonatomic, readonly) BOOL hasCarouselInformation;
/// @}

/// @{
/*!
 If a frame contains size information (header extension) we get several properties - resolution of the camera, what region is cropped and sent and what are the dimensions of the image we will receive. This is not sent with every frame we get, but only if any of these change (say after changeStream commands).
 
 sourceSize is the resolution of the camera
 sourceCrop is not a crop rectangle and is improperly defined as UIEdgeInsets. top/left correspond to the offset from the top and left edge of the camera but bottom and right are actually the coordinates of the bottom right corner of the crop area.
 destinationSize is the dimensions of the image we (will) receive
 sourceRect is the crop rectangle as proper rectangle - top left is the top left corner and width/height is width/height - both in camera's resolution
 */
@property (nonatomic, readonly) CGSize sourceSize;
@property (nonatomic, readonly) UIEdgeInsets sourceCrop;
@property (nonatomic, readonly) CGSize destinationSize;
@property (nonatomic, readonly) NSUInteger resamplingTag;
@property (nonatomic, readonly) CGRect sourceRect;
/// @}

/// @{
/*! 
 Current / Changed live events come in pair if the frame contains the Live header extension. Both properties contain a mask of  XPSDKVideoConnectionFrameLiveFlags.
 */
@property (nonatomic, readonly) XPSDKVideoConnectionFrameLiveEventsMask currentLiveEvents;
@property (nonatomic, readonly) XPSDKVideoConnectionFrameLiveEventsMask changedLiveEvents;
/// @}

/// @{
/*! 
 Current / Changed playback events come in pair if the frame contains the Playback header extension. Both properties contain a mask of  XPSDKVideoConnectionFramePlaybackFlags.
 */
@property (nonatomic, readonly) XPSDKVideoConnectionFramePlaybackEventsMask currentPlaybackEvents;
@property (nonatomic, readonly) XPSDKVideoConnectionFramePlaybackEventsMask changedPlaybackEvents;
/// @}

@property (nonatomic, strong) UIImage * image; /// Image, if any, sent with the frame

/*!
 Checks a byte stream and verifies if we have enough data in it to construct a frame object
 @param data The byte array to check
 @return Yes if the data contains enough data to parse the base header, the header contains a valid frame length and that there is enough data to construct a frame with that length.
 
 Note: if the base frame header contains an unnaturally long expected frame length (say 1GB) this method will return NO if the data is less than that size. It could be good idea to have some limit on how large a frame may be so we can detect such potentially invalid headers and discard that data, sending the video connection in "self repair" mode
 */
+ (BOOL) dataContainsCompleteFrame:(NSData *) data;

/*!
 Checks a byte stream and verifies if the data contains the correct video ID
 @param data The data to be checked
 @param videoID The video ID to check for
 @return Yes if the data seems to contain a valid frame
 */
+ (BOOL) data:(NSData *) data matchesVideoID: (NSString *) videoID;

/*!
 Designated initializer - c reates a new frame object from a byte stream
 @param data input data
 @param totalSize Pointer to an unsigned integer variable. The initializer will set it to the actual number of bytes read to construct the frame
 */
- (id) initWithData: (NSData *) data;

//segmentation only - fallback to MJPEG
- (BOOL)isSegmentedStream;

@end
