/*
 * This file is part of the YSSDWebImage package.
 * (c) Olivier Poitrey <rs@dailymotion.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#import "YSSDImageCacheDefine.h"
#import "YSSDImageCodersManager.h"
#import "YSSDImageCoderHelper.h"
#import "YSSDAnimatedImage.h"
#import "UIImage+YSMetadata.h"
#import "YSSDInternalMacros.h"

UIImage * _Nullable YSSDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSString * _Nonnull cacheKey, YSSDWebImageOptions options, YSSDWebImageContext * _Nullable context) {
    UIImage *image;
    BOOL decodeFirstFrame = YSSD_OPTIONS_CONTAINS(options, YSSDWebImageDecodeFirstFrameOnly);
    NSNumber *scaleValue = context[YSSDWebImageContextImageScaleFactor];
    CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : YSSDImageScaleFactorForKey(cacheKey);
    NSNumber *preserveAspectRatioValue = context[YSSDWebImageContextImagePreserveAspectRatio];
    NSValue *thumbnailSizeValue;
    BOOL shouldScaleDown = YSSD_OPTIONS_CONTAINS(options, YSSDWebImageScaleDownLargeImages);
    if (shouldScaleDown) {
        CGFloat thumbnailPixels = YSSDImageCoderHelper.defaultScaleDownLimitBytes / 4;
        CGFloat dimension = ceil(sqrt(thumbnailPixels));
        thumbnailSizeValue = @(CGSizeMake(dimension, dimension));
    }
    if (context[YSSDWebImageContextImageThumbnailPixelSize]) {
        thumbnailSizeValue = context[YSSDWebImageContextImageThumbnailPixelSize];
    }
    
    YSSDImageCoderMutableOptions *mutableCoderOptions = [NSMutableDictionary dictionaryWithCapacity:2];
    mutableCoderOptions[YSSDImageCoderDecodeFirstFrameOnly] = @(decodeFirstFrame);
    mutableCoderOptions[YSSDImageCoderDecodeScaleFactor] = @(scale);
    mutableCoderOptions[YSSDImageCoderDecodePreserveAspectRatio] = preserveAspectRatioValue;
    mutableCoderOptions[YSSDImageCoderDecodeThumbnailPixelSize] = thumbnailSizeValue;
    mutableCoderOptions[YSSDImageCoderWebImageContext] = context;
    YSSDImageCoderOptions *coderOptions = [mutableCoderOptions copy];
    
    // Grab the image coder
    id<YSSDImageCoder> imageCoder;
    if ([context[YSSDWebImageContextImageCoder] conformsToProtocol:@protocol(YSSDImageCoder)]) {
        imageCoder = context[YSSDWebImageContextImageCoder];
    } else {
        imageCoder = [YSSDImageCodersManager sharedManager];
    }
    
    if (!decodeFirstFrame) {
        Class animatedImageClass = context[YSSDWebImageContextAnimatedImageClass];
        // check whether we should use `YSSDAnimatedImage`
        if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(YSSDAnimatedImage)]) {
            image = [[animatedImageClass alloc] initWithData:imageData scale:scale options:coderOptions];
            if (image) {
                // Preload frames if supported
                if (options & YSSDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) {
                    [((id<YSSDAnimatedImage>)image) preloadAllFrames];
                }
            } else {
                // Check image class matching
                if (options & YSSDWebImageMatchAnimatedImageClass) {
                    return nil;
                }
            }
        }
    }
    if (!image) {
        image = [imageCoder decodedImageWithData:imageData options:coderOptions];
    }
    if (image) {
        BOOL shouldDecode = !YSSD_OPTIONS_CONTAINS(options, YSSDWebImageAvoidDecodeImage);
        if ([image.class conformsToProtocol:@protocol(YSSDAnimatedImage)]) {
            // `YSSDAnimatedImage` do not decode
            shouldDecode = NO;
        } else if (image.yssd_isAnimated) {
            // animated image do not decode
            shouldDecode = NO;
        }
        if (shouldDecode) {
            image = [YSSDImageCoderHelper decodedImageWithImage:image];
        }
    }
    
    return image;
}
