//
//  MVMCoreCache.h
//  myverizon
//
//  Created by Scott Pfeil on 11/27/13.
//  Copyright (c) 2013 Verizon Wireless. All rights reserved.
//
//  Caches the json that comes from the server.

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

//block returned when getting image
//parameters are UIImage object for the image, NSData for gif images, UIImage object for the image, A BOOL to indicate if it is a fall back image.
typedef void(^MVMCoreGetImageBlock)(UIImage * _Nullable, NSData * _Nullable, BOOL);

@interface MVMCoreCache : NSObject

// The static string cache. Stored on the device.
@property (nullable, strong, nonatomic, readonly) NSDictionary *staticStringCache;
@property (nonnull, strong, nonatomic) NSOperationQueue *completionQueue;

// Returns the shared instance of this singleton
+ (nullable instancetype)sharedCache;

#pragma mark - Page and Module Handling

// Checks the set of pageTypes to be cached for the given pageType.
- (BOOL)shouldCacheJSONWithPageType:(nonnull NSString *)pageType;

// Checks the set of modules to be cached for the given module
- (BOOL)shouldCacheJSONWithModule:(nonnull NSString *)module;

// For pages external to the mobile first framework to be added to the list to not cache
- (void)addPageTypesToNotCache:(nullable NSArray <NSString *>*)array;

// For modules external to the mobile first framework to be added to the list to not cache
- (void)addModulesToNotCache:(nullable NSArray <NSString *>*)array;

#pragma mark - Simple Fetch

// Gets a json dictionary from the cache by pageType. Pass in the block that you want to run once the dictionary is received. This will be run on a background thread.
- (void)fetchJSONForPageType:(nullable NSString *)pageType completionHandler:(nonnull void (^)(NSDictionary * _Nullable jsonDictionary))completionHandler;

// Gets a json dictionary from the cache by module. Pass in the block that you want to run once the dictionary is received. This will be run on a background thread.
- (void)fetchJSONForModule:(nullable NSString *)module completionHandler:(nonnull void (^)(NSDictionary * _Nullable jsonDictionary))completionHandler;

// Gets a json dictionary from the cache with all the requested modules. Pass in the block that you want to run once the dictionary is received. This will be run on a background thread.
- (void)fetchJSONForModules:(nullable NSArray *)modules completionHandler:(nonnull void (^)(NSDictionary * _Nullable jsonDictionary))completionHandler;

#pragma mark - Advanced Fetch

// Pass in the block that you want to run once the dictionary is received and which queue to run it on. Pass in if you'd like the current thread to wait.
- (void)fetchJSONForPageType:(nullable NSString *)pageType queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionHandler:(nonnull void (^)(NSDictionary * _Nullable jsonDictionary))completionHandler;

// Gets a json dictionary from the cache by module. Pass in the block that you want to run once the dictionary is received and which queue to run it on. Pass in if you'd like the current thread to wait.
- (void)fetchJSONForModule:(nullable NSString *)module queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionHandler:(nonnull void (^)(NSDictionary * _Nullable jsonDictionary))completionHandler;

// Gets a json dictionary from the cache with all the requested modules. Pass in the block that you want to run once the dictionary is received and which queue to run it on. Pass in if you'd like the current thread to wait.
- (void)fetchJSONForModules:(nullable NSArray *)modules queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionHandler:(nonnull void (^)(NSDictionary * _Nullable jsonDictionary))completionHandler;

#pragma mark - Simple Insertion

// Adds a json dictionary to the cache by pageType.
- (void)addPageToCache:(nonnull NSDictionary *)jsonDictionary pageType:(nonnull NSString *)pageType;

// Adds a json dictionary to the cache by module.
- (void)addModuleToCache:(nonnull NSDictionary *)jsonDictionary module:(nonnull NSString *)module;

// Adds a json dictionary to the cache by modules.
- (void)addModulesToCache:(nonnull NSDictionary *)jsonDictionary;

#pragma mark - Advanced Insertion

// Adds a json dictionary to the cache by pageType. Pass in the block that you want to run once the dictionary is received and which queue to run it on. Pass in if you'd like the current thread to wait.
- (void)addPageToCache:(nonnull NSDictionary *)jsonDictionary pageType:(nonnull NSString *)pageType queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionBlock:(nullable void (^)(void))completionBlock;

// Adds a json dictionary to the cache by module. Pass in the block that you want to run once the dictionary is received and which queue to run it on. Pass in if you'd like the current thread to wait.
- (void)addModuleToCache:(nonnull NSDictionary *)jsonDictionary module:(nonnull NSString *)module queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionBlock:(nullable void (^)(void))completionBlock;

// Pass in a dictionary containing modules to store in the cache. Pass in the block that you want to run once the dictionary is received and which queue to run it on. Pass in if you'd like the current thread to wait.
- (void)addModulesToCache:(nonnull NSDictionary *)jsonDictionary queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionBlock:(nullable void (^)(void))completionBlock;

#pragma mark - Simple Deletion

// Removes a json dictionary from the cache by pageType.
- (void)removeJSONForPageType:(nonnull NSString *)pageType;

// Removes a json dictionary from the cache by module.
- (void)removeJSONForModule:(nonnull NSString *)module;

// Removes the json for modules.
- (void)removeJSONForModules:(nonnull NSArray *)modules;

// Clears the page and module data.
- (void)clearMFCache;

#pragma mark - Advanced Deletion

// Removes a json dictionary from the cache by pageType. Pass in the block that you want to run once the dictionary is received and which queue to run it on. Pass in if you'd like the current thread to wait.
- (void)removeJSONForPageType:(nonnull NSString *)pageType queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionBlock:(nullable void (^)(void))completionBlock;

// Removes a json dictionary from the cache by module. Pass in the block that you want to run once the dictionary is received and which queue to run it on.
- (void)removeJSONForModule:(nonnull NSString *)module queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionBlock:(nullable void (^)(void))completionBlock;

// Removes the json for modules. Pass in the block that you want to run once the dictionary is received and which queue to run it on.
- (void)removeJSONForModules:(nonnull NSArray *)modules queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionBlock:(nullable void (^)(void))completionBlock;

#pragma mark Image Functions

// Subclass to return the bundle to use
- (nonnull NSBundle *)bundleToUseForImages;

// Checks if the image is in the cache. If not, will try to download or create the image.
// Width is used for downloading from scene7.
// Height is used for downloading from scene7.
// Format is used for downloading from scene7
// Most cases only need to provide the width. If both are provided and the aspect ratio is different from the images, it will center the image.
// In the future, may need to use align for the shop flow.
// localFallbackImageName: should be the name of a local file to use in case of failure to download.
- (void)getImage:(nullable NSString *)pathOrName useWidth:(BOOL)useWidth widthForS7:(NSInteger)widthForS7 useHeight:(BOOL)useHeight heightForS7:(NSInteger)heightForS7 localFallbackImageName:(nullable NSString *)fallbackImageName completionHandler:(nonnull MVMCoreGetImageBlock)completionHandler;
- (void)getImage:(nullable NSString *)pathOrName useWidth:(BOOL)useWidth widthForS7:(NSInteger)widthForS7 useHeight:(BOOL)useHeight heightForS7:(NSInteger)heightForS7 format:(nullable NSString *)format localFallbackImageName:(nullable NSString *)fallbackImageName completionHandler:(nonnull MVMCoreGetImageBlock)completionHandler;
- (void)getGif:(nullable NSString *)pathOrName useWidth:(BOOL)useWidth widthForS7:(NSInteger)widthForS7 useHeight:(BOOL)useHeight heightForS7:(NSInteger)heightForS7 format:(nullable NSString *)format localFallbackImageName:(nullable NSString *)fallbackImageName completionHandler:(nonnull MVMCoreGetImageBlock)completionHandler;

// Gets a cropped version of the requested image. Similar to the method above, but you can specify the final rect
- (void)getCroppedImage:(nullable NSString *)pathOrName useWidth:(BOOL)useWidth widthForS7:(NSInteger)widthForS7 useHeight:(BOOL)useHeight heightForS7:(NSInteger)heightForS7 finalRect:(CGRect)finalRect flipImage:(BOOL)flipImage localFallbackImageName:(nullable NSString *)fallbackImageName completionHandler:(nonnull MVMCoreGetImageBlock)completionHandler;

// Gets an image from the cache.
- (nullable UIImage *)getCachedImageWithName:(nonnull NSString *)imageName;
- (nullable NSData *)getCachedDataWithName:(nonnull NSString *)imageName;

// Adds the image to the cache
- (void)addImageToCache:(nonnull UIImage *)image withName:(nonnull NSString *)imageName;
- (void)addDataToCache:(nonnull NSData *)data withName:(nonnull NSString *)imageName;

// Removes image from cache if we need to update
- (void)removeImageFromCache:(nonnull NSString *)imageName;

// clears the image cache
- (void)clearImageCache;

@end
