/**
 * Copyright (c) 2015-present, Parse, LLC.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

#import <Foundation/Foundation.h>

///--------------------------------------
#pragma mark - SDK Version
///--------------------------------------

#define PARSE_VERSION @"1.12.0"

///--------------------------------------
#pragma mark - Platform
///--------------------------------------

extern NSString *const _Nonnull kPFDeviceType;

///--------------------------------------
#pragma mark - Cache Policies
///--------------------------------------

/**
 `PFCachePolicy` specifies different caching policies that could be used with `PFQuery`.

 This lets you show data when the user's device is offline,
 or when the app has just started and network requests have not yet had time to complete.
 Parse takes care of automatically flushing the cache when it takes up too much space.

 @warning Cache policy could only be set when Local Datastore is not enabled.

 @see PFQuery
 */
typedef NS_ENUM(uint8_t, PFCachePolicy) {
    /**
     The query does not load from the cache or save results to the cache.
     This is the default cache policy.
     */
    kPFCachePolicyIgnoreCache = 0,
    /**
     The query only loads from the cache, ignoring the network.
     If there are no cached results, this causes a `NSError` with `kPFErrorCacheMiss` code.
     */
    kPFCachePolicyCacheOnly,
    /**
     The query does not load from the cache, but it will save results to the cache.
     */
    kPFCachePolicyNetworkOnly,
    /**
     The query first tries to load from the cache, but if that fails, it loads results from the network.
     If there are no cached results, this causes a `NSError` with `kPFErrorCacheMiss` code.
     */
    kPFCachePolicyCacheElseNetwork,
    /**
     The query first tries to load from the network, but if that fails, it loads results from the cache.
     If there are no cached results, this causes a `NSError` with `kPFErrorCacheMiss` code.
     */
    kPFCachePolicyNetworkElseCache,
    /**
     The query first loads from the cache, then loads from the network.
     The callback will be called twice - first with the cached results, then with the network results.
     Since it returns two results at different times, this cache policy cannot be used with synchronous or task methods.
     */
    kPFCachePolicyCacheThenNetwork
};

///--------------------------------------
#pragma mark - Logging Levels
///--------------------------------------

/**
 `PFLogLevel` enum specifies different levels of logging that could be used to limit or display more messages in logs.

 @see `Parse.+setLogLevel:`
 @see `Parse.+logLevel`
 */
typedef NS_ENUM(uint8_t, PFLogLevel) {
    /**
     Log level that disables all logging.
     */
    PFLogLevelNone = 0,
    /**
     Log level that if set is going to output error messages to the log.
     */
    PFLogLevelError = 1,
    /**
     Log level that if set is going to output the following messages to log:
     - Errors
     - Warnings
     */
    PFLogLevelWarning = 2,
    /**
     Log level that if set is going to output the following messages to log:
     - Errors
     - Warnings
     - Informational messages
     */
    PFLogLevelInfo = 3,
    /**
     Log level that if set is going to output the following messages to log:
     - Errors
     - Warnings
     - Informational messages
     - Debug messages
     */
    PFLogLevelDebug = 4
};

///--------------------------------------
#pragma mark - Errors
///--------------------------------------

/**
 Error domain used for all `NSError`s in the SDK.
 */
extern NSString *const _Nonnull PFParseErrorDomain;

/**
 `PFErrorCode` enum contains all custom error codes that are used as `code` for `NSError` for callbacks on all classes.

 These codes are used when `domain` of `NSError` that you receive is set to `PFParseErrorDomain`.
 */
typedef NS_ENUM(NSInteger, PFErrorCode) {
    /**
     Internal server error. No information available.
     */
    kPFErrorInternalServer = 1,
    /**
     The connection to the Parse servers failed.
     */
    kPFErrorConnectionFailed = 100,
    /**
     Object doesn't exist, or has an incorrect password.
     */
    kPFErrorObjectNotFound = 101,
    /**
     You tried to find values matching a datatype that doesn't
     support exact database matching, like an array or a dictionary.
     */
    kPFErrorInvalidQuery = 102,
    /**
     Missing or invalid classname. Classnames are case-sensitive.
     They must start with a letter, and `a-zA-Z0-9_` are the only valid characters.
     */
    kPFErrorInvalidClassName = 103,
    /**
     Missing object id.
     */
    kPFErrorMissingObjectId = 104,
    /**
     Invalid key name. Keys are case-sensitive.
     They must start with a letter, and `a-zA-Z0-9_` are the only valid characters.
     */
    kPFErrorInvalidKeyName = 105,
    /**
     Malformed pointer. Pointers must be arrays of a classname and an object id.
     */
    kPFErrorInvalidPointer = 106,
    /**
     Malformed json object. A json dictionary is expected.
     */
    kPFErrorInvalidJSON = 107,
    /**
     Tried to access a feature only available internally.
     */
    kPFErrorCommandUnavailable = 108,
    /**
     Field set to incorrect type.
     */
    kPFErrorIncorrectType = 111,
    /**
     Invalid channel name. A channel name is either an empty string (the broadcast channel)
     or contains only `a-zA-Z0-9_` characters and starts with a letter.
     */
    kPFErrorInvalidChannelName = 112,
    /**
     Invalid device token.
     */
    kPFErrorInvalidDeviceToken = 114,
    /**
     Push is misconfigured. See details to find out how.
     */
    kPFErrorPushMisconfigured = 115,
    /**
     The object is too large.
     */
    kPFErrorObjectTooLarge = 116,
    /**
     That operation isn't allowed for clients.
     */
    kPFErrorOperationForbidden = 119,
    /**
     The results were not found in the cache.
     */
    kPFErrorCacheMiss = 120,
    /**
     Keys in `NSDictionary` values may not include `$` or `.`.
     */
    kPFErrorInvalidNestedKey = 121,
    /**
     Invalid file name.
     A file name can contain only `a-zA-Z0-9_.` characters and should be between 1 and 36 characters.
     */
    kPFErrorInvalidFileName = 122,
    /**
     Invalid ACL. An ACL with an invalid format was saved. This should not happen if you use `PFACL`.
     */
    kPFErrorInvalidACL = 123,
    /**
     The request timed out on the server. Typically this indicates the request is too expensive.
     */
    kPFErrorTimeout = 124,
    /**
     The email address was invalid.
     */
    kPFErrorInvalidEmailAddress = 125,
    /**
     A unique field was given a value that is already taken.
     */
    kPFErrorDuplicateValue = 137,
    /**
     Role's name is invalid.
     */
    kPFErrorInvalidRoleName = 139,
    /**
     Exceeded an application quota. Upgrade to resolve.
     */
    kPFErrorExceededQuota = 140,
    /**
     Cloud Code script had an error.
     */
    kPFScriptError = 141,
    /**
     Cloud Code validation failed.
     */
    kPFValidationError = 142,
    /**
     Product purchase receipt is missing.
     */
    kPFErrorReceiptMissing = 143,
    /**
     Product purchase receipt is invalid.
     */
    kPFErrorInvalidPurchaseReceipt = 144,
    /**
     Payment is disabled on this device.
     */
    kPFErrorPaymentDisabled = 145,
    /**
     The product identifier is invalid.
     */
    kPFErrorInvalidProductIdentifier = 146,
    /**
     The product is not found in the App Store.
     */
    kPFErrorProductNotFoundInAppStore = 147,
    /**
     The Apple server response is not valid.
     */
    kPFErrorInvalidServerResponse = 148,
    /**
     Product fails to download due to file system error.
     */
    kPFErrorProductDownloadFileSystemFailure = 149,
    /**
     Fail to convert data to image.
     */
    kPFErrorInvalidImageData = 150,
    /**
     Unsaved file.
     */
    kPFErrorUnsavedFile = 151,
    /**
     Fail to delete file.
     */
    kPFErrorFileDeleteFailure = 153,
    /**
     Application has exceeded its request limit.
     */
    kPFErrorRequestLimitExceeded = 155,
    /**
     Invalid event name.
     */
    kPFErrorInvalidEventName = 160,
    /**
     Username is missing or empty.
     */
    kPFErrorUsernameMissing = 200,
    /**
     Password is missing or empty.
     */
    kPFErrorUserPasswordMissing = 201,
    /**
     Username has already been taken.
     */
    kPFErrorUsernameTaken = 202,
    /**
     Email has already been taken.
     */
    kPFErrorUserEmailTaken = 203,
    /**
     The email is missing, and must be specified.
     */
    kPFErrorUserEmailMissing = 204,
    /**
     A user with the specified email was not found.
     */
    kPFErrorUserWithEmailNotFound = 205,
    /**
     The user cannot be altered by a client without the session.
     */
    kPFErrorUserCannotBeAlteredWithoutSession = 206,
    /**
     Users can only be created through sign up.
     */
    kPFErrorUserCanOnlyBeCreatedThroughSignUp = 207,
    /**
     An existing Facebook account already linked to another user.
     */
    kPFErrorFacebookAccountAlreadyLinked = 208,
    /**
     An existing account already linked to another user.
     */
    kPFErrorAccountAlreadyLinked = 208,
    /**
     Error code indicating that the current session token is invalid.
     */
    kPFErrorInvalidSessionToken = 209,
    kPFErrorUserIdMismatch = 209,
    /**
     Facebook id missing from request.
     */
    kPFErrorFacebookIdMissing = 250,
    /**
     Linked id missing from request.
     */
    kPFErrorLinkedIdMissing = 250,
    /**
     Invalid Facebook session.
     */
    kPFErrorFacebookInvalidSession = 251,
    /**
     Invalid linked session.
     */
    kPFErrorInvalidLinkedSession = 251,
};

///--------------------------------------
#pragma mark - Blocks
///--------------------------------------

@class PFObject;
@class PFUser;

typedef void (^PFBooleanResultBlock)(BOOL succeeded, NSError *_Nullable error);
typedef void (^PFIntegerResultBlock)(int number, NSError *_Nullable error);
typedef void (^PFArrayResultBlock)(NSArray *_Nullable objects, NSError *_Nullable error);
typedef void (^PFObjectResultBlock)(PFObject *_Nullable object,  NSError *_Nullable error);
typedef void (^PFSetResultBlock)(NSSet *_Nullable channels, NSError *_Nullable error);
typedef void (^PFUserResultBlock)(PFUser *_Nullable user, NSError *_Nullable error);
typedef void (^PFDataResultBlock)(NSData *_Nullable data, NSError *_Nullable error);
typedef void (^PFDataStreamResultBlock)(NSInputStream *_Nullable stream, NSError *_Nullable error);
typedef void (^PFFilePathResultBlock)(NSString *_Nullable filePath, NSError *_Nullable error);
typedef void (^PFStringResultBlock)(NSString *_Nullable string, NSError *_Nullable error);
typedef void (^PFIdResultBlock)(_Nullable id object, NSError *_Nullable error);
typedef void (^PFProgressBlock)(int percentDone);

///--------------------------------------
#pragma mark - Network Notifications
///--------------------------------------

/**
 The name of the notification that is going to be sent before any URL request is sent.
 */
extern NSString *const _Nonnull PFNetworkWillSendURLRequestNotification;

/**
 The name of the notification that is going to be sent after any URL response is received.
 */
extern NSString *const _Nonnull PFNetworkDidReceiveURLResponseNotification;

/**
 The key of request(NSURLRequest) in the userInfo dictionary of a notification.
 @note This key is populated in userInfo, only if `PFLogLevel` on `Parse` is set to `PFLogLevelDebug`.
 */
extern NSString *const _Nonnull PFNetworkNotificationURLRequestUserInfoKey;

/**
 The key of response(NSHTTPURLResponse) in the userInfo dictionary of a notification.
 @note This key is populated in userInfo, only if `PFLogLevel` on `Parse` is set to `PFLogLevelDebug`.
 */
extern NSString *const _Nonnull PFNetworkNotificationURLResponseUserInfoKey;

/**
 The key of repsonse body (usually `NSString` with JSON) in the userInfo dictionary of a notification.
 @note This key is populated in userInfo, only if `PFLogLevel` on `Parse` is set to `PFLogLevelDebug`.
 */
extern NSString *const _Nonnull PFNetworkNotificationURLResponseBodyUserInfoKey;


///--------------------------------------
#pragma mark - Deprecated Macros
///--------------------------------------

#ifndef PARSE_DEPRECATED
#  ifdef __deprecated_msg
#    define PARSE_DEPRECATED(_MSG) __deprecated_msg(_MSG)
#  else
#    ifdef __deprecated
#      define PARSE_DEPRECATED(_MSG) __attribute__((deprecated))
#    else
#      define PARSE_DEPRECATED(_MSG)
#    endif
#  endif
#endif

///--------------------------------------
#pragma mark - Extensions Macros
///--------------------------------------

#ifndef PF_EXTENSION_UNAVAILABLE
#  if PARSE_IOS_ONLY
#    ifdef NS_EXTENSION_UNAVAILABLE_IOS
#      define PF_EXTENSION_UNAVAILABLE(_msg) NS_EXTENSION_UNAVAILABLE_IOS(_msg)
#    else
#      define PF_EXTENSION_UNAVAILABLE(_msg)
#    endif
#  else
#    ifdef NS_EXTENSION_UNAVAILABLE_MAC
#      define PF_EXTENSION_UNAVAILABLE(_msg) NS_EXTENSION_UNAVAILABLE_MAC(_msg)
#    else
#      define PF_EXTENSION_UNAVAILABLE(_msg)
#    endif
#  endif
#endif

///--------------------------------------
#pragma mark - Swift Macros
///--------------------------------------

#ifndef PF_SWIFT_UNAVAILABLE
#  ifdef NS_SWIFT_UNAVAILABLE
#    define PF_SWIFT_UNAVAILABLE NS_SWIFT_UNAVAILABLE("")
#  else
#    define PF_SWIFT_UNAVAILABLE
#  endif
#endif

///--------------------------------------
#pragma mark - Platform Availability Defines
///--------------------------------------

#ifndef TARGET_OS_IOS
#  define TARGET_OS_IOS TARGET_OS_IPHONE
#endif
#ifndef TARGET_OS_WATCH
#  define TARGET_OS_WATCH 0
#endif
#ifndef TARGET_OS_TV
#  define TARGET_OS_TV 0
#endif

#ifndef PF_TARGET_OS_OSX
#  define PF_TARGET_OS_OSX (TARGET_OS_MAC && !TARGET_OS_IOS && !TARGET_OS_WATCH && !TARGET_OS_TV)
#endif

///--------------------------------------
#pragma mark - Avaiability Macros
///--------------------------------------

#ifndef PF_IOS_UNAVAILABLE
#  ifdef __IOS_UNAVILABLE
#    define PF_IOS_UNAVAILABLE __IOS_UNAVAILABLE
#  else
#    define PF_IOS_UNAVAILABLE
#  endif
#endif

#ifndef PF_IOS_UNAVAILABLE_WARNING
#  if TARGET_OS_IOS
#    define PF_IOS_UNAVAILABLE_WARNING _Pragma("GCC warning \"This file is unavailable on iOS.\"")
#  else
#    define PF_IOS_UNAVAILABLE_WARNING
#  endif
#endif

#ifndef PF_OSX_UNAVAILABLE
#  if PF_TARGET_OS_OSX
#    define PF_OSX_UNAVAILABLE __OSX_UNAVAILABLE
#  else
#    define PF_OSX_UNAVAILABLE
#  endif
#endif

#ifndef PF_OSX_UNAVAILABLE_WARNING
#  if PF_TARGET_OS_OSX
#    define PF_OSX_UNAVAILABLE_WARNING _Pragma("GCC warning \"This file is unavailable on OS X.\"")
#  else
#    define PF_OSX_UNAVAILABLE_WARNING
#  endif
#endif

#ifndef PF_WATCH_UNAVAILABLE
#  ifdef __WATCHOS_UNAVAILABLE
#    define PF_WATCH_UNAVAILABLE __WATCHOS_UNAVAILABLE
#  else
#    define PF_WATCH_UNAVAILABLE
#  endif
#endif

#ifndef PF_WATCH_UNAVAILABLE_WARNING
#  if TARGET_OS_WATCH
#    define PF_WATCH_UNAVAILABLE_WARNING _Pragma("GCC warning \"This file is unavailable on watchOS.\"")
#  else
#    define PF_WATCH_UNAVAILABLE_WARNING
#  endif
#endif

#ifndef PF_TV_UNAVAILABLE
#  ifdef __TVOS_PROHIBITED
#    define PF_TV_UNAVAILABLE __TVOS_PROHIBITED
#  else
#    define PF_TV_UNAVAILABLE
#  endif
#endif

#ifndef PF_TV_UNAVAILABLE_WARNING
#  if TARGET_OS_TV
#    define PF_TV_UNAVAILABLE_WARNING _Pragma("GCC warning \"This file is unavailable on tvOS.\"")
#  else
#    define PF_TV_UNAVAILABLE_WARNING
#  endif
#endif
