//
//  SeMobGIFImageView.m
//  SeMob
//
//  Created by yangbin on 2017/8/10.
//

#import "SeMobGIFImageView.h"
#import <ImageIO/ImageIO.h>

@interface SeMobGIFImageView()
@property (nonatomic) CGImageSourceRef sourceRef;
@property (nonatomic) NSUInteger currentIndex;
@property (nonatomic) NSUInteger maxImageCount;

@end
@implementation SeMobGIFImageView

+ (SeMobGIFImageView *)imageViewWithGIFData:(NSData *)data
{
    SeMobGIFImageView *view = [[SeMobGIFImageView alloc] init];
    view.gifData = data;
    return view;
}

- (void)dealloc
{
    if (_sourceRef) {
        CFRelease(_sourceRef);
    }
    self.sourceRef = NULL;
}

- (void)didMoveToWindow
{
    if (self.window == nil) {
        [self stopAnimating];
    }
}

- (void)startAnimating
{
    [self stopAnimating];
    if (!_gifData) {
        return;
    }
    _currentIndex = 0;
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)_gifData, NULL);
    self.sourceRef = source;
    size_t count = CGImageSourceGetCount(source);
    self.maxImageCount = count;
    
    if (count <= 1) {
        UIImage *animatedImage = [[UIImage alloc] initWithData:_gifData];
        self.image = animatedImage;
        return;
    } else {
        [self loadNextImage];
    }
}

- (void)stopAnimating
{
    if (_sourceRef) {
        CFRelease(_sourceRef);
    }
    self.sourceRef = NULL;
    self.maxImageCount = 0;
    self.currentIndex = 0;
}

- (void)loadNextImage
{
    if (_sourceRef == NULL) {
        return;
    }
    CGImageRef image = CGImageSourceCreateImageAtIndex(_sourceRef, _currentIndex, NULL);
    
    float duration = [self semobGIF_frameDurationAtIndex:_currentIndex source:_sourceRef];
    
    UIImage *imgCurrent = [UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp];
    
    CGImageRelease(image);
    self.image = imgCurrent;
    __weak typeof(self) weakSelf = self;
    CGImageSourceRef current = _sourceRef;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        if (weakSelf == nil || weakSelf.sourceRef == NULL) {
            return ;
        }
        if (current != weakSelf.sourceRef) {
            return;
        }
        weakSelf.currentIndex += 1;
        if (weakSelf.currentIndex >= weakSelf.maxImageCount) {
            weakSelf.currentIndex = 0;
        }
        [weakSelf loadNextImage];
    });
}

- (float)semobGIF_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source
{
    float frameDuration = 0.1f;
    CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
    NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
    NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
    
    NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
    if (delayTimeUnclampedProp) {
        frameDuration = [delayTimeUnclampedProp floatValue];
    }
    else {
        
        NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
        if (delayTimeProp) {
            frameDuration = [delayTimeProp floatValue];
        }
    }
    
    // Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
    // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
    // a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
    // for more information.
    
    if (frameDuration < 0.011f) {
        frameDuration = 0.100f;
    }
    
    CFRelease(cfFrameProperties);
    return frameDuration;
}

@end
