//
//  MVMCoreTopAlertOperation.m
//  mobilefirst
//
//  Created by Scott Pfeil on 6/4/16.
//  Copyright © 2016 Verizon Wireless. All rights reserved.
//

#import "MVMCoreTopAlertOperation.h"
#import "MVMCoreTopAlertObject.h"
#import "MVMCoreAlertHandler.h"
#import <MVMCoreUI/MVMCoreUI-Swift.h>
#import <MVMCoreUI/MVMCoreUISplitViewController.h>

@interface MVMCoreTopAlertOperation () {
    __block BOOL _paused;
    __block BOOL _displayed;
    __block BOOL _animating;
    __block BOOL _displayable;
}

@property (readwrite, getter=isPaused) BOOL paused;
@property (readwrite, getter=isDisplayed) BOOL displayed;
@property (readwrite, getter=isAnimating) BOOL animating;

// For thread safety
@property (strong, nonatomic) dispatch_queue_t pausedQueue;
@property (strong, nonatomic) dispatch_queue_t displayedQueue;
@property (strong, nonatomic) dispatch_queue_t animatingQueue;
@property (strong, nonatomic) dispatch_queue_t displayableQueue;

@property (nonatomic, strong) dispatch_source_t timerSource;

@end

@implementation MVMCoreTopAlertOperation

- (instancetype)init {
    
    self = [super init];
    if (self) {
        self.pausedQueue = dispatch_queue_create("paused", DISPATCH_QUEUE_CONCURRENT);
        self.displayedQueue = dispatch_queue_create("displayed", DISPATCH_QUEUE_CONCURRENT);
        self.animatingQueue = dispatch_queue_create("animating", DISPATCH_QUEUE_CONCURRENT);
        self.displayableQueue = dispatch_queue_create("displayable", DISPATCH_QUEUE_CONCURRENT);
        self.displayable = YES;
    }
    return self;
}

- (nullable instancetype)initWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject {
    
    if (self = [self init]) {
        self.topAlertObject = topAlertObject;
        
        // Sets the queue priority for various types of alerts.
        self.queuePriority = [[CoreUIObject sharedInstance].globalTopAlertDelegate priorityForTopAlertByObject:topAlertObject];
    }
    return self;
}

- (void)updateWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject {
    self.topAlertObject = topAlertObject;
    self.queuePriority = [[CoreUIObject sharedInstance].globalTopAlertDelegate priorityForTopAlertByObject:topAlertObject];
    if (self.isExecuting && !self.isCancelled && !self.isPaused) {
        [self updateDismissTimer];
        UIView <MVMCoreTopAlertViewProtocol>*topAlertView = [[CoreUIObject sharedInstance].globalTopAlertDelegate getTopAlertView];
        if ([topAlertView respondsToSelector:@selector(updateTopAlertWith:)]) {
            [topAlertView updateTopAlertWith:topAlertObject];
        }
    }
}

- (void)updateDisplayableByPageType:(nullable NSString *)pageType {
    NSArray <NSString *>*pages = [self.topAlertObject.json array:@"pages"];
    if (pages.count == 0) {
        self.displayable = YES;
        return;
    }
    if (pageType.length == 0) {
        self.displayable = NO;
        return;
    }
    self.displayable = [pages containsObject:pageType];
}

- (BOOL)isPaused {
    __block BOOL isPaused;
    dispatch_sync(self.pausedQueue, ^{
        isPaused = self->_paused;
    });
    return isPaused;
}

- (void)setPaused:(BOOL)paused {
    dispatch_barrier_async(self.pausedQueue, ^{
        self->_paused = paused;
    });
}

- (BOOL)isDisplayed {
    __block BOOL isDisplayed;
    dispatch_sync(self.displayedQueue, ^{
        isDisplayed = self->_displayed;
    });
    return isDisplayed;
}

- (void)setDisplayed:(BOOL)displayed {
    dispatch_barrier_async(self.displayedQueue, ^{
        self->_displayed = displayed;
    });
}

- (BOOL)isAnimating {
    __block BOOL isAnimating;
    dispatch_sync(self.animatingQueue, ^{
        isAnimating = self->_animating;
    });
    return isAnimating;
}

- (void)setAnimating:(BOOL)animating {
    dispatch_barrier_async(self.animatingQueue, ^{
        self->_animating = animating;
    });
}


- (BOOL)isDisplayable {
    __block BOOL isDisplayable;
    dispatch_sync(self.displayableQueue, ^{
        isDisplayable = self->_displayable;
    });
    return isDisplayable;
}

- (void)setDisplayable:(BOOL)displayable {
    if (displayable != self.isDisplayable) {
        BOOL isReady = [super isReady];
        if (isReady) {
            [self willChangeValueForKey:@"isReady"];
        }
        dispatch_barrier_async(self.displayableQueue, ^{
            self->_displayable = displayable;
        });
        if (isReady) {
            [self didChangeValueForKey:@"isReady"];
        }
    }
}

- (BOOL)isReady {
    if (self.isCancelled) {
        return [super isReady];
    }
    return [super isReady] && self.isDisplayable;
}

- (void)main {
    
    // Always check for cancellation before launching the task.
    if ([self checkAndHandleForCancellation]) {
        return;
    }
    
    // Do nothing if paused
    if (!self.isPaused) {

        // Display alert only if alerts aren't supressed.
        if (![[MVMCoreAlertHandler sharedAlertHandler] mfAlertsSupressed]) {
            
            // Show
            if (![[CoreUIObject sharedInstance].globalTopAlertDelegate respondsToSelector:@selector(getTopAlertView)]) {

                // Needs to be a top alert view....
                [self markAsFinished];
            } else {
                UIView <MVMCoreTopAlertViewProtocol>*topAlertView = [[CoreUIObject sharedInstance].globalTopAlertDelegate getTopAlertView];
                [topAlertView showWithTopAlertObject:self.topAlertObject animationDelegate:self completionHandler:^(BOOL finished) {
                    
                    self.displayed = YES;
                    if (self.isCancelled) {
                        
                        // Cancelled, dismiss immediately.
                        [self dismissAlertView:YES forceful:YES];
                    } else if (self.isPaused) {
                        
                        // Paused, dismiss for the time being if persistent.
                        [self dismissAlertView:!self.topAlertObject.persistent forceful:YES];
                    } else {
                        [self updateDismissTimer];
                    }
                }];
            }
        } else {
            [self pause];
        }
    }
}

/// Updates the timer to dismiss the top alert.
- (void)updateDismissTimer {
    if (self.timerSource) {
        dispatch_source_cancel(self.timerSource);
    }
    if (self.topAlertObject.persistent) {
        return;
    }
    
    NSInteger dismissTime;
    if (self.topAlertObject.topAlertDismissTime > 0) {
        dismissTime = self.topAlertObject.topAlertDismissTime;
    } else {
        dismissTime = TopAlertDismissTime;
    }
        
    self.timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    dispatch_source_set_timer(self.timerSource, dispatch_time(DISPATCH_TIME_NOW, dismissTime * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, (1ull * NSEC_PER_SEC) / 10);
    
    __weak typeof(self) weakSelf = self;
    dispatch_source_set_event_handler(self.timerSource, ^{
        if (weakSelf.isFinished || [weakSelf checkAndHandleForCancellation]) {
            return;
        }
        [weakSelf dismissAlertView:YES forceful:NO];
    });
    dispatch_resume(self.timerSource);
}

- (void)cancel {
    [super cancel];
    
    // Do nothing if animating.
    if (!self.isAnimating) {
        
        if (self.isDisplayed) {
            [self dismissAlertView:YES forceful:YES];
        } else if (self.isExecuting) {
            [self markAsFinished];
        }
    }
}

- (void)dismissAlertView:(BOOL)andFinish forceful:(BOOL)forceful {
    if (self.timerSource) {
        dispatch_source_cancel(self.timerSource);
    }
    if (self.isDisplayed && !self.isAnimating) {
        
        // Dismisses.
        [[[CoreUIObject sharedInstance].globalTopAlertDelegate getTopAlertView] hideAlertView:forceful completionHandler:^(BOOL finished) {
            
            self.displayed = NO;
            if (andFinish) {
                [self markAsFinished];
            }
        }];
    }
}

- (void)pause {
    
    if (!self.paused) {
        [self willChangeValueForKey:@"isPaused"];
        self.paused = YES;
        [self didChangeValueForKey:@"isPaused"];
    }
    [self dismissAlertView:!self.topAlertObject.persistent forceful:YES];
}

- (void)unpause {
    
    if (self.paused) {
        [self willChangeValueForKey:@"isPaused"];
        self.paused = NO;
        [self didChangeValueForKey:@"isPaused"];
    }
    if (self.executing) {
        [self start];
    }
}

#pragma mark - Delegate functions
             
- (void)topAlertViewBeginAnimation {
    self.animating = YES;
}

- (void)topAlertViewFinishAnimation {
    self.animating = NO;
}

- (void)topAlertCloseButtonPressed {
    [self dismissAlertView:YES forceful:YES];
}

- (id)copyWithZone:(nullable NSZone *)zone {
    MVMCoreTopAlertOperation *copyObject = [[MVMCoreTopAlertOperation alloc] init];
    copyObject.topAlertObject = self.topAlertObject;
    copyObject.paused = self.paused;
    copyObject.reAddAfterCancel = self.reAddAfterCancel;
    copyObject.displayable = self.isDisplayable;
    copyObject.queuePriority = self.queuePriority;
    for (NSOperation *dependency in self.dependencies) {
        [copyObject addDependency:dependency];
    }
    copyObject.name = self.name;
    copyObject.qualityOfService = self.qualityOfService;
    return copyObject;
}

@end
