//
//  Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//

#import "AttachmentUploadView.h"
#import "OWSBezierPathView.h"
#import "OWSProgressView.h"
#import "OWSUploadingService.h"
#import "TSAttachmentStream.h"
#import "UIView+OWS.h"

NS_ASSUME_NONNULL_BEGIN

@interface AttachmentUploadView ()

@property (nonatomic) TSAttachmentStream *attachment;

@property (nonatomic) OWSBezierPathView *bezierPathView;

@property (nonatomic) OWSProgressView *progressView;

@property (nonatomic) AttachmentStateBlock _Nullable attachmentStateCallback;

@property (nonatomic) BOOL isAttachmentReady;

@property (nonatomic) CGFloat lastProgress;

@end

#pragma mark -

@implementation AttachmentUploadView

- (instancetype)initWithAttachment:(TSAttachmentStream *)attachment
                         superview:(UIView *)superview
           attachmentStateCallback:(AttachmentStateBlock _Nullable)attachmentStateCallback
{
    self = [super init];

    if (self) {
        OWSAssert(attachment);
        OWSAssert(superview);

        self.attachment = attachment;
        self.attachmentStateCallback = attachmentStateCallback;

        [superview addSubview:self];
        [self autoPinToSuperviewEdges];

        _bezierPathView = [OWSBezierPathView new];
        self.bezierPathView.configureShapeLayerBlock = ^(CAShapeLayer *layer, CGRect bounds) {
            layer.path = [UIBezierPath bezierPathWithRect:bounds].CGPath;
            layer.fillColor = [UIColor colorWithWhite:0.f alpha:0.4f].CGColor;
        };
        [self addSubview:self.bezierPathView];
        [self.bezierPathView autoPinToSuperviewEdges];

        // The progress view is white.  It will only be shown
        // while the mask layer is visible, so it will show up
        // even against all-white attachments.
        _progressView = [OWSProgressView new];
        self.progressView.color = [UIColor whiteColor];
        [self addSubview:self.progressView];

        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(attachmentUploadProgress:)
                                                     name:kAttachmentUploadProgressNotification
                                                   object:nil];

        _isAttachmentReady = self.attachment.isUploaded;

        [self ensureViewState];

        if (attachmentStateCallback) {
            self.attachmentStateCallback(_isAttachmentReady);
        }
    }
    return self;
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)setIsAttachmentReady:(BOOL)isAttachmentReady
{
    if (_isAttachmentReady == isAttachmentReady) {
        return;
    }

    _isAttachmentReady = isAttachmentReady;

    [self ensureViewState];

    if (self.attachmentStateCallback) {
        self.attachmentStateCallback(isAttachmentReady);
    }
}

- (void)setLastProgress:(CGFloat)lastProgress
{
    _lastProgress = lastProgress;

    [self ensureViewState];
}

- (void)ensureViewState
{
    self.bezierPathView.hidden = self.isAttachmentReady || self.lastProgress == 0;
    self.progressView.hidden = self.isAttachmentReady || self.lastProgress == 0;
}

- (void)attachmentUploadProgress:(NSNotification *)notification
{
    NSDictionary *userinfo = [notification userInfo];
    double progress = [[userinfo objectForKey:kAttachmentUploadProgressKey] doubleValue];
    NSString *attachmentID = [userinfo objectForKey:kAttachmentUploadAttachmentIDKey];
    if ([self.attachment.uniqueId isEqual:attachmentID]) {
        if (!isnan(progress)) {
            [self.progressView setProgress:progress];
            self.lastProgress = progress;
            self.isAttachmentReady = self.attachment.isUploaded;
        } else {
            OWSFail(@"%@ Invalid attachment progress.", self.logTag);
            self.isAttachmentReady = YES;
        }
    }
}

- (void)setBounds:(CGRect)bounds
{
    BOOL sizeDidChange = !CGSizeEqualToSize(bounds.size, self.bounds.size);
    [super setBounds:bounds];
    if (sizeDidChange) {
        [self updateLayout];
    }
}

- (void)setFrame:(CGRect)frame
{
    BOOL sizeDidChange = !CGSizeEqualToSize(frame.size, self.frame.size);
    [super setFrame:frame];
    if (sizeDidChange) {
        [self updateLayout];
    }
}

- (void)updateLayout
{
    // Center the progress bar within the bubble mask.
    //
    // TODO: Verify that this layout works in RTL.
    const CGFloat kBubbleTailWidth = 6.f;
    CGRect bounds = self.bounds;
    bounds.size.width -= kBubbleTailWidth;
    if (self.isRTL) {
        bounds.origin.x += kBubbleTailWidth;
    }

    const CGFloat progressWidth = round(bounds.size.width * 0.45f);
    const CGFloat progressHeight = round(MIN(bounds.size.height * 0.5f, progressWidth * 0.09f));
    CGRect progressFrame = CGRectMake(round(bounds.origin.x + (bounds.size.width - progressWidth) * 0.5f),
        round(bounds.origin.y + (bounds.size.height - progressHeight) * 0.5f),
        progressWidth,
        progressHeight);
    self.progressView.frame = progressFrame;
}

@end

NS_ASSUME_NONNULL_END
