//
//  MVMCoreUISplitViewController.m
//  myverizon
//
//  Created by Scott Pfeil on 1/13/14.
//  Copyright (c) 2014 Verizon Wireless. All rights reserved.
//

#import "MVMCoreUISplitViewController.h"
@import MVMCore.MVMCoreNavigationHandler;
@import MVMCore.MVMCoreDispatchUtility;
@import MVMCore.MVMCoreViewManagerProtocol;
@import MVMCore.MVMCoreActionUtility;
@import MVMCore.NSDictionary_MFConvenience;
#import "MVMCoreUIUtility.h"
#import "UIColor+MFConvenience.h"
#import "NSLayoutConstraint+MFConvenience.h"
#import "MFFonts.h"
#import <MVMCoreUI/MFSizeObject.h>
#import "MVMCoreUISession.h"
#import "MVMCoreUIConstants.h"
#import "MVMCoreUICommonViewsUtility.h"
#import "MVMCoreUITopAlertView.h"
#import <MVMCoreUI/MVMCoreUI-Swift.h>

@interface MVMCoreUISplitViewController ()

typedef NS_OPTIONS(NSInteger, MFExtendedDrawer) {
    MFExtendedDrawerNone = 0,
    MFExtendedDrawerRight,
    MFExtendedDrawerLeft
};

@property (weak, nonatomic) UIView *leftView;
@property (weak, nonatomic) UIView *mainView;
@property (weak, nonatomic) UIView *rightView;
@property (weak, nonatomic) NSLayoutConstraint *mainViewLeading;
@property (weak, nonatomic) NSLayoutConstraint *mainViewTrailing;
@property (weak, nonatomic) NSLayoutConstraint *leftPanelWidth;
@property (weak, nonatomic) NSLayoutConstraint *rightPanelWidth;

@property (weak, nonatomic) UIView *leftPanelSeparator;
@property (weak, nonatomic) UIView *rightPanelSeparator;

@property (weak, nonatomic) NSLayoutConstraint *bottomConstraint;

@property (weak, nonatomic, readwrite) NavigationController *navigationController;

// A view that covers the detail view when the master is out.
@property (weak, nonatomic) IBOutlet UIView *mainViewCoverView;

@property (weak, nonatomic) IBOutlet UIProgressView *bottomProgressBar;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bottomProgressBarHeightConstraint;

@property (nonatomic, strong) UIGestureRecognizer *tapToDismissGesture;

@property (nullable, readwrite, weak, nonatomic) NSObject <MVMCoreUIPanelProtocol> *explictlyShowingPanel;
@property (nonatomic) MFExtendedDrawer prioritizedExtendedPanel;

@property (nonatomic) MFExtendedDrawer extendedDrawers;
@property (nonatomic, readwrite) BOOL leftPanelIsAccessible;
@property (nonatomic, readwrite) BOOL rightPanelIsAccessible;
@property (weak, nonatomic, readwrite) UIViewController *navigationItemViewController;
@property (strong, nonatomic) NSNumber *transitionWidth;

// Dismisses any panel
- (void)dismissPanels:(id)sender;

@end

@implementation MVMCoreUISplitViewController

CGFloat const PanelAnimationDuration = 0.2;

+ (instancetype)mainSplitViewController {
    return [MVMCoreActionUtility initializerClassCheck:[MVMCoreUISession sharedGlobal].splitViewController classToVerify:self];
}

+ (nullable instancetype)setup:(nullable UIViewController <MVMCoreUIPanelProtocol> *)leftPanel rightPanel:(nullable UIViewController <MVMCoreUIPanelProtocol> *)rightPanel {
    MVMCoreUISplitViewController *splitViewController = [[self alloc] initWithLeftPanel:leftPanel rightPanel:rightPanel];
    [MVMCoreUISession sharedGlobal].splitViewController = splitViewController;
    return splitViewController;
}

+ (nullable instancetype)setupAsMainController:(nullable UIViewController <MVMCoreUIPanelProtocol> *)leftPanel rightPanel:(nullable UIViewController <MVMCoreUIPanelProtocol> *)rightPanel {
    MVMCoreUISplitViewController *splitViewController = [self setup:leftPanel rightPanel:rightPanel];
    [[MVMCoreUISession sharedGlobal] setupAsStandardLoadViewDelegate:splitViewController];
    return splitViewController;
}

- (nullable instancetype)initWithLeftPanel:(nullable UIViewController <MVMCoreUIPanelProtocol> *)leftPanel rightPanel:(nullable UIViewController <MVMCoreUIPanelProtocol> *)rightPanel {
    if (self = [super init]) {
        self.globalLeftPanel = leftPanel;
        self.globalRightPanel = rightPanel;
    }
    return self;
}

#pragma mark - Main Subclassables

- (MFNumberOfDrawers)numberOfDrawersShouldShow:(NSNumber *)forWidth {
    CGFloat width;
    if (forWidth != nil) {
        width = [forWidth floatValue];
    } else {
        width = [MVMCoreUISplitViewController getApplicationViewWidth];
    }
    return (width > 2000 ? MFTwoDrawer : (width > 1000 ? MFOneDrawer : MFNoDrawer));
}

- (nullable NSArray <UIBarButtonItem *>*)additionalLeftButtonsForViewController:(nonnull UIViewController *)viewController {
    return nil;
}

- (nullable NSArray <UIBarButtonItem *>*)additionalRightButtonsForViewController:(nonnull UIViewController *)viewController {
    return nil;
}

- (CGFloat)leftPanelExtendedWidth {
    if ([self.leftPanel respondsToSelector:@selector(panelExtendedWidth)]) {
        return [self.leftPanel panelExtendedWidth];
    }
    return 320;
}

- (CGFloat)leftPanelMaxWidth {
    if ([self.leftPanel respondsToSelector:@selector(panelMaxWidth)]) {
        return [self.leftPanel panelMaxWidth];
    }
    return 415;
}

- (CGFloat)rightPanelExtendedWidth {
    if ([self.rightPanel respondsToSelector:@selector(panelExtendedWidth)]) {
        return [self.rightPanel panelExtendedWidth];
    }
    return 320;
}

- (CGFloat)rightPanelMaxWidth {
    if ([self.rightPanel respondsToSelector:@selector(panelMaxWidth)]) {
        return [self.rightPanel panelMaxWidth];
    }
    return 500;
}

- (nullable UIImage *)imageForBackButton {
    return [MVMCoreUIUtility imageNamed:@"nav_back"];
}

#pragma mark - Button Presses

- (IBAction)leftPanelButtonPressed:(id)sender {
    [MVMCoreDispatchUtility performBlockOnMainThread:^{
        UIViewController *viewController = self.navigationController.topViewController;
        UIViewController *detailViewController = [self getCurrentDetailViewController];
        // If Viewcontroller confirms to protocol and implements the the method leftPanelButtonPressed
        if ([detailViewController conformsToProtocol:@protocol(MVMCoreUIDetailViewProtocol)]
            && [detailViewController respondsToSelector:@selector(isOverridingLeftButton)]
            && [((UIViewController <MVMCoreUIDetailViewProtocol> *)detailViewController) isOverridingLeftButton]) {
            return;
        }
        
        if (self.mainViewLeading.constant < .1) {
            // Hide the keyboard
            [viewController.view endEditing:YES];
            // Show
            [self showLeftPanelAnimated:YES];
        } else {
            // Hide
            [self hideLeftPanelIfNeededAnimated:YES];
        }
    }];
}

- (IBAction)backButtonPressed:(id)sender {
    [MVMCoreDispatchUtility performBlockOnMainThread:^{
        UIViewController *detailViewController = [self getCurrentDetailViewController];
        if ([detailViewController conformsToProtocol:@protocol(MVMCoreUIDetailViewProtocol)] && [detailViewController respondsToSelector:@selector(backButtonPressed)]) {
            [((UIViewController <MVMCoreUIDetailViewProtocol> *)detailViewController) backButtonPressed];
        } else {
            [[MVMCoreNavigationHandler sharedNavigationHandler] popTopViewControllerAnimated:YES];
        }
    }];
}

- (IBAction)rightPanelButtonPressed:(id)sender {
    [MVMCoreDispatchUtility performBlockOnMainThread:^{
        UIViewController *viewController = self.navigationController.topViewController;
        UIViewController *detailViewController = [self getCurrentDetailViewController];

        // If Viewcontroller confirms to protocol and implements the the method rightPanelButtonPressed
        if ([detailViewController conformsToProtocol:@protocol(MVMCoreUIDetailViewProtocol)]
            && [detailViewController respondsToSelector:@selector(isOverridingRightButton)]
            && [((UIViewController <MVMCoreUIDetailViewProtocol> *)detailViewController) isOverridingRightButton]) {
            return;
        }
        
        if (self.mainViewTrailing.constant < .1) {
            // Hide the keyboard
            [viewController.view endEditing:YES];
            // Show
            [self showRightPanelAnimated:YES];
        } else {
            // Hide
            [self hideRightPanelIfNeededAnimated:YES];
        }
    }];
}

#pragma mark - Left Panel Functions

- (BOOL)shouldExtendLeftPanel {
    MFNumberOfDrawers numberOfDrawers = [self numberOfDrawersShouldShow:self.transitionWidth];
    return [self shouldExtendLeftPanel:numberOfDrawers];
}

- (BOOL)shouldExtendLeftPanel:(MFNumberOfDrawers)numberOfDrawers {
    if (!(self.extendedDrawers & MFExtendedDrawerLeft)) {
        // Left panel not set to be extended.
        return NO;
    } else {
        if (numberOfDrawers == MFTwoDrawer) {
            // Both drawers should be extended
            return YES;
        } else if (numberOfDrawers == MFNoDrawer) {
            // No drawer is extended.
            return NO;
        } else {
            // left is extended if the right panel isn't prioritized.
            return self.prioritizedExtendedPanel != MFExtendedDrawerRight;
        }
    }
}

- (BOOL)leftPanelStaysExtended {
    MFNumberOfDrawers numberOfDrawers = [self numberOfDrawersShouldShow:self.transitionWidth];
    return [self shouldExtendLeftPanel:numberOfDrawers] && (numberOfDrawers != MFOneDrawer || self.explictlyShowingPanel != self.rightPanel);
}

- (void)setLeftNavigationItemForViewController:(UIViewController * _Nonnull)viewController accessible:(BOOL)accessible extended:(BOOL)extended {
    NSMutableArray *leftBarButtonItems = [NSMutableArray array];
    if (self.navigationController && [MVMCoreNavigationHandler.sharedNavigationHandler getViewControllersForNavigationController:self.navigationController].count > 1) {
        [leftBarButtonItems addObject:self.backButton];
    }
    if ((accessible && !extended) && self.leftPanelButton) {
        [leftBarButtonItems addObject:self.leftPanelButton];
    }
    NSArray *extraButtons = [self additionalLeftButtonsForViewController:viewController];
    if (extraButtons) {
        [leftBarButtonItems addObjectsFromArray:extraButtons];
    }
    [self.navigationController.topViewController.navigationItem setLeftBarButtonItems:(leftBarButtonItems.count > 0 ? leftBarButtonItems : nil) animated:!DisableAnimations];
}

- (void)setLeftPanelIsAccessible:(BOOL)leftPanelIsAccessible forViewController:(UIViewController *)viewController updateNavigationButtons:(BOOL)updateNavigationButtons {
    if ([self.leftPanel respondsToSelector:@selector(panelAvailable)]) {
        self.leftPanelIsAccessible = leftPanelIsAccessible && [self.leftPanel panelAvailable];
    } else {
        self.leftPanelIsAccessible = leftPanelIsAccessible;
    }
    self.navigationItemViewController = viewController;
    [MVMCoreDispatchUtility performBlockOnMainThread:^{
        BOOL extended = NO;
        if (!self.leftPanelIsAccessible) {
            
            // Hides panel if showing.
            [self hideLeftPanelAnimated:NO];
        } else {

            // Determine if we should show the panel (extended based on width or from explicit action).
            extended = [self leftPanelStaysExtended];
            if (extended || self.explictlyShowingPanel == self.leftPanel) {
                [self showLeftPanelAnimated:NO explict:NO];
            }
            
            if ([self.leftPanel respondsToSelector:@selector(resetIconToDefault)]) {
                [self.leftPanel resetIconToDefault];
            }
        }
        if (updateNavigationButtons) {
            [self setLeftNavigationItemForViewController:viewController accessible:self.leftPanelIsAccessible extended:extended];
        }
    }];
}

- (nonnull void (^)(void))getLeftPanelShowAnimationBlock {
    MFNumberOfDrawers numberOfDrawers = [self numberOfDrawersShouldShow:self.transitionWidth];
    return ^{
        
        // Bring panel onto screen.
        self.mainViewLeading.constant = self.leftPanelWidth.constant;
        
        // Make main view untouchable if panel is not extended.
        if (![self shouldExtendLeftPanel:numberOfDrawers]) {
            self.mainViewCoverView.alpha = 0.3;
            
            // right drawer is not always extended or we cannot fit both drawers
            if (!(self.extendedDrawers & MFExtendedDrawerRight) || numberOfDrawers == MFNoDrawer) {
                self.mainViewTrailing.constant = -self.leftPanelWidth.constant;
            } else if (numberOfDrawers < MFTwoDrawer) {
                self.mainViewTrailing.constant = -self.leftPanelWidth.constant + self.rightPanelWidth.constant;
            }
        }
        [self.view layoutIfNeeded];
    };
}

- (void)hideLeftPanelIfNeededAnimated:(BOOL)animated {
    if (![self shouldExtendLeftPanel] || self.explictlyShowingPanel == self.leftPanel)  {
        [self hideLeftPanelAnimated:animated];
    }
}

- (void)hideLeftPanelAnimated:(BOOL)animated {
    [self hideLeftPanelAnimated:animated checkingForOtherExtendedDrawers:YES];
}

- (void)hideLeftPanelAnimated:(BOOL)animated checkingForOtherExtendedDrawers:(BOOL)checkingForOtherExtendedDrawers {
    [MVMCoreDispatchUtility performBlockOnMainThread:^{
        if (self.mainViewLeading.constant > .1) {
            if (checkingForOtherExtendedDrawers && self.explictlyShowingPanel == self.leftPanel) {
                self.explictlyShowingPanel = nil;
            }
            void (^animation)(void) = ^{
                self.mainViewCoverView.alpha = 0;
                self.mainViewLeading.constant = 0;
                
                // If the right drawer should be extended, make sure it's extended.
                if (checkingForOtherExtendedDrawers && self.rightPanelIsAccessible && [self shouldExtendRightPanel]) {
                    void (^showRightPanel)(void) = [self getRightPanelShowAnimationBlock];
                    showRightPanel();
                } else {
                    self.mainViewTrailing.constant = 0;
                }
                [self.view layoutIfNeeded];
            };
            
            void (^completion)(BOOL) = ^(BOOL finished){
                self.mainViewCoverView.hidden = YES;
                [self panelDidDisappear:self.leftPanel animated:animated];
                self.mainView.accessibilityElementsHidden = NO;
                UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, self.mainView);
            };
            
            [self.leftPanelSeparator removeFromSuperview];
            [self panelWillDisappear:self.leftPanel animated:animated];
            if (animated) {
                [UIView animateWithDuration:PanelAnimationDuration delay:0 options:UIViewAnimationOptionCurveLinear animations:animation  completion:completion];
            } else {
                animation();
                completion(NO);
            }
        }
    }];
}

- (void)showLeftPanelAnimated:(BOOL)animated explict:(BOOL)explict {
    if (!self.leftPanel) {
        return;
    }
    [MVMCoreDispatchUtility performBlockOnMainThread:^{
        if (self.mainViewLeading.constant < .1) {
            BOOL shouldExtendLeftPanel = [self shouldExtendLeftPanel];
            
            if (explict) {
                self.explictlyShowingPanel = self.leftPanel;
            }
            
            void (^animations)(void) = [self getLeftPanelShowAnimationBlock];
            
            void (^completion)(BOOL) = ^(BOOL finished){
                [self panelDidAppear:self.leftPanel didExtend:shouldExtendLeftPanel animated:animated];
            };
            
            if (!shouldExtendLeftPanel) {
                if ([self.leftPanel respondsToSelector:@selector(showArrow)]){
                    [self.leftPanel showArrow];
                }
                self.mainView.accessibilityElementsHidden = YES;
                UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
            } else {
                if ([self.leftPanel respondsToSelector:@selector(hideArrow)]){
                    [self.leftPanel hideArrow];
                }
                
                UIView *leftPanelSeparator = [[UIView alloc] init];
                leftPanelSeparator.backgroundColor = [UIColor mfSilver];
                leftPanelSeparator.translatesAutoresizingMaskIntoConstraints = NO;
                [self.view addSubview:leftPanelSeparator];
                [leftPanelSeparator.widthAnchor constraintEqualToConstant:1].active = YES;
                [leftPanelSeparator.leftAnchor constraintEqualToAnchor:self.leftView.rightAnchor].active = YES;
                [leftPanelSeparator.topAnchor constraintEqualToAnchor:self.mainView.topAnchor].active = YES;
                [leftPanelSeparator.bottomAnchor constraintEqualToAnchor:self.mainView.bottomAnchor].active = YES;
                self.leftPanelSeparator = leftPanelSeparator;
            }
            
            self.mainViewCoverView.hidden = NO;
            [self panelWillAppear:self.leftPanel willExtend:shouldExtendLeftPanel animated:animated];
            if (animated) {
                [UIView animateWithDuration:PanelAnimationDuration delay:0 options:UIViewAnimationOptionCurveLinear animations:animations completion:completion];
            } else {
                animations();
                completion(NO);
            }
        }
    }];
}

- (void)showLeftPanelAnimated:(BOOL)animated {
    [self showLeftPanelAnimated:animated explict:YES];
}

#pragma mark - Right Panel Functions

- (void)setRightNavigationItemForViewController:(UIViewController * _Nonnull)viewController accessible:(BOOL)accessible extended:(BOOL)extended {
    NSMutableArray *navigationItems = [[NSMutableArray alloc] init];
    if ((accessible && !extended) && self.rightPanelButton) {
        [navigationItems addObject:self.rightPanelButton];
    }
    NSArray *extraButtons = [self additionalRightButtonsForViewController:viewController];
    if (extraButtons) {
        [navigationItems addObjectsFromArray:extraButtons];
    }
    [self.navigationController.topViewController.navigationItem setRightBarButtonItems:(navigationItems.count > 0 ? navigationItems : nil) animated:!DisableAnimations];
}

- (BOOL)shouldExtendRightPanel {
    MFNumberOfDrawers numberOfDrawers = [self numberOfDrawersShouldShow:self.transitionWidth];
    return [self shouldExtendRightPanel:numberOfDrawers];
}

- (BOOL)shouldExtendRightPanel:(MFNumberOfDrawers)numberOfDrawers {
    if (!(self.extendedDrawers & MFExtendedDrawerRight)) {
        // Panel not set to be extended.
        return NO;
    } else {
        if (numberOfDrawers == MFTwoDrawer) {
            // Both drawers should be extended
            return YES;
        } else if (numberOfDrawers == MFNoDrawer) {
            // No drawer is extended.
            return NO;
        } else {
            // Extend right if the left panel isn't prioritized.
            return self.prioritizedExtendedPanel != MFExtendedDrawerLeft;
        }
    }
}

- (BOOL)rightPanelStaysExtended {
    MFNumberOfDrawers numberOfDrawers = [self numberOfDrawersShouldShow:self.transitionWidth];
    return [self shouldExtendRightPanel:numberOfDrawers] && (numberOfDrawers != MFOneDrawer || self.explictlyShowingPanel != self.leftPanel);
}

- (void)setRightPanelIsAccessible:(BOOL)rightPanelIsAccessible forViewController:(UIViewController *)viewController updateNavigationButtons:(BOOL)updateNavigationButtons {
    
    if ([self.rightPanel respondsToSelector:@selector(panelAvailable)]) {
        self.rightPanelIsAccessible = rightPanelIsAccessible && [self.rightPanel panelAvailable];
    } else {
        self.rightPanelIsAccessible = rightPanelIsAccessible;
    }
    self.navigationItemViewController = viewController;
    [MVMCoreDispatchUtility performBlockOnMainThread:^{
        
        BOOL extended = NO;
        if (!rightPanelIsAccessible) {
            
            // Hides panel if showing.
            [self hideRightPanelAnimated:NO];
        } else {
            
            // Determine if we should show the right panel (extended based on width or from explicit action).
            extended = [self rightPanelStaysExtended];
            if (extended || self.explictlyShowingPanel == self.rightPanel) {
                [self showRightPanelAnimated:NO explict:NO];
            }
            
            if ([self.rightPanel respondsToSelector:@selector(resetIconToDefault)]) {
                [self.rightPanel resetIconToDefault];
            }
        }
        
        if (updateNavigationButtons) {
            [self setRightNavigationItemForViewController:viewController accessible:rightPanelIsAccessible extended:extended];
        }
    }];
}

- (nonnull void (^)(void))getRightPanelShowAnimationBlock {
    MFNumberOfDrawers numberOfDrawers = [self numberOfDrawersShouldShow:self.transitionWidth];
    return ^{
        
        // Bring right panel onto screen.
        self.mainViewTrailing.constant = self.rightPanelWidth.constant;
        
        // Right Panel is not always extended, make detail view untouchable
        if (![self shouldExtendRightPanel:numberOfDrawers]) {
            self.mainViewCoverView.alpha = 0.3;
            
            // Right drawer is not always extended or we cannot fit both drawers
            if (!(self.extendedDrawers & MFExtendedDrawerLeft) || numberOfDrawers == MFNoDrawer) {
                self.mainViewLeading.constant = -self.rightPanelWidth.constant;
            } else if (numberOfDrawers < MFTwoDrawer) {
                self.mainViewLeading.constant = -self.rightPanelWidth.constant + self.leftPanelWidth.constant;
            }
        }
        [self.view layoutIfNeeded];
    };
}

- (void)hideRightPanelIfNeededAnimated:(BOOL)animated {
    if (![self shouldExtendRightPanel] || self.explictlyShowingPanel == self.rightPanel) {
        [self hideRightPanelAnimated:animated];
    }
}

- (void)hideRightPanelAnimated:(BOOL)animated {
    [self hideRightPanelAnimated:animated checkingForOtherExtendedDrawers:YES];
}

- (void)hideRightPanelAnimated:(BOOL)animated checkingForOtherExtendedDrawers:(BOOL)checkingForOtherExtendedDrawers {
    [MVMCoreDispatchUtility performBlockOnMainThread:^{
        if (self.mainViewTrailing.constant > .1) {
            if (checkingForOtherExtendedDrawers && self.explictlyShowingPanel == self.rightPanel) {
                self.explictlyShowingPanel = nil;
            }
            void (^animation)(void) = ^{
                self.mainViewCoverView.alpha = 0;
                self.mainViewTrailing.constant = 0;
                
                // If the menu drawer should be extended, make sure it's extended.
                if (checkingForOtherExtendedDrawers && self.leftPanelIsAccessible && [self shouldExtendLeftPanel]) {
                    void (^showRightPanel)(void) = [self getLeftPanelShowAnimationBlock];
                    showRightPanel();
                } else {
                    self.mainViewLeading.constant = 0;
                }
                [self.view layoutIfNeeded];
            };
            
            void (^completion)(BOOL) = ^(BOOL finished){
                self.mainViewCoverView.hidden = YES;
                [self panelDidDisappear:self.rightPanel animated:animated];
                self.mainView.accessibilityElementsHidden = NO;
                UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, self.mainView);
            };
            
            [self.rightPanelSeparator removeFromSuperview];
            [self panelWillDisappear:self.rightPanel animated:animated];
            if (animated) {
                [UIView animateWithDuration:PanelAnimationDuration delay:0 options:UIViewAnimationOptionCurveLinear animations:animation  completion:completion];
            } else {
                animation();
                completion(NO);
            }
        }
    }];
}

- (void)showRightPanelAnimated:(BOOL)animated explict:(BOOL)explict {
    if (!self.rightPanel) {
        return;
    }
    [MVMCoreDispatchUtility performBlockOnMainThread:^{
        if (self.mainViewTrailing.constant < .1) {
            BOOL shouldExtendRightPanel = [self shouldExtendRightPanel];
            
            if (explict) {
                self.explictlyShowingPanel = self.rightPanel;
            }
            
            void (^animations)(void) = [self getRightPanelShowAnimationBlock];
            
            void (^completion)(BOOL) = ^(BOOL finished){
                [self panelDidAppear:self.rightPanel didExtend:shouldExtendRightPanel animated:animated];
                self.mainView.accessibilityElementsHidden = YES;
                UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, self.rightPanel);
            };
            
            self.mainViewCoverView.hidden = NO;
            if (!shouldExtendRightPanel) {
                if ([self.rightPanel respondsToSelector:@selector(showArrow)]){
                    [self.rightPanel showArrow];
                }
            } else {
                if ([self.rightPanel respondsToSelector:@selector(hideArrow)]){
                    [self.rightPanel hideArrow];
                }
                
                UIView *rightPanelSeparator = [[UIView alloc] init];
                rightPanelSeparator.backgroundColor = [UIColor mfSilver];
                rightPanelSeparator.translatesAutoresizingMaskIntoConstraints = NO;
                [self.view addSubview:rightPanelSeparator];
                [rightPanelSeparator.widthAnchor constraintEqualToConstant:1].active = YES;
                [rightPanelSeparator.leftAnchor constraintEqualToAnchor:self.rightView.leftAnchor].active = YES;
                [rightPanelSeparator.topAnchor constraintEqualToAnchor:self.mainView.topAnchor].active = YES;
                [rightPanelSeparator.bottomAnchor constraintEqualToAnchor:self.mainView.bottomAnchor].active = YES;
                self.rightPanelSeparator = rightPanelSeparator;
            }
            
            [self panelWillAppear:self.rightPanel willExtend:shouldExtendRightPanel animated:animated];
            if (animated) {
                [UIView animateWithDuration:PanelAnimationDuration delay:0 options:UIViewAnimationOptionCurveLinear animations:animations completion:completion];
            } else {
                animations();
                completion(NO);
            }
        }
    }];
}

- (void)showRightPanelAnimated:(BOOL)animated {
    [self showRightPanelAnimated:animated explict:YES];
}

#pragma mark - Other Panel Functions

- (void)forceHideBothDrawers {
    [self hideBothDrawersShouldForceHide:YES];
}

- (void)hideBothDrawersShouldForceHide:(BOOL)force {
    //force indicates if we really need to hide the panels
    //if not force, that means the hiding is just a temporary state, we might need to show certain panels based on other logics
    [self hideLeftPanelAnimated:NO checkingForOtherExtendedDrawers:!force];
    [self hideRightPanelAnimated:NO checkingForOtherExtendedDrawers:!force];
}

- (void)dismissPanels:(id)sender {
    [self hideLeftPanelIfNeededAnimated:YES];
    [self hideRightPanelIfNeededAnimated:YES];
}

- (void)panelWillAppear:(UIViewController <MVMCoreUIPanelProtocol> *)panel willExtend:(BOOL)willExtend animated:(BOOL)animated {
    if ([panel respondsToSelector:@selector(willAppear:)]) {
        [panel willAppear:animated];
    } else {
        [panel viewWillAppear:animated];
    }
    UIViewController *controller = [self getCurrentDetailViewController];
    if ([controller.class conformsToProtocol:@protocol(MVMCoreUIDetailViewProtocol)]) {
        UIViewController <MVMCoreUIDetailViewProtocol>* protocolController = (UIViewController <MVMCoreUIDetailViewProtocol>*)controller;
        if ([protocolController respondsToSelector:@selector(panelWillAppear:overtakingDetail:)]) {
           [protocolController panelWillAppear:panel overtakingDetail:!willExtend];
        } else if ([protocolController respondsToSelector:@selector(panelWillAppear:)]) {
            [protocolController panelWillAppear:panel];
        }
    }
}

- (void)panelDidAppear:(UIViewController <MVMCoreUIPanelProtocol> *)panel didExtend:(BOOL)didExtend animated:(BOOL)animated {
    if ([panel respondsToSelector:@selector(didAppear:)]) {
        [panel didAppear:animated];
    } else {
        [panel viewDidAppear:animated];
    }
    UIViewController *controller = [self getCurrentDetailViewController];
    if ([controller.class conformsToProtocol:@protocol(MVMCoreUIDetailViewProtocol)]) {
        UIViewController <MVMCoreUIDetailViewProtocol>* protocolController = (UIViewController <MVMCoreUIDetailViewProtocol>*)controller;
        if ([protocolController respondsToSelector:@selector(panelDidAppear:overtakingDetail:)]) {
            [protocolController panelDidAppear:panel overtakingDetail:!didExtend];
        } else if ([protocolController respondsToSelector:@selector(panelDidAppear:)]) {
            [protocolController panelDidAppear:panel];
        }
    }
}

- (void)panelWillDisappear:(UIViewController <MVMCoreUIPanelProtocol> *)panel animated:(BOOL)animated {
    if ([panel respondsToSelector:@selector(willDisappear:)]) {
        [panel willDisappear:animated];
    } else {
        [panel viewWillDisappear:animated];
    }
    UIViewController *controller = [self getCurrentDetailViewController];
    if ([controller.class conformsToProtocol:@protocol(MVMCoreUIDetailViewProtocol)]) {
        UIViewController <MVMCoreUIDetailViewProtocol>* protocolController = (UIViewController <MVMCoreUIDetailViewProtocol>*)controller;
        if ([protocolController respondsToSelector:@selector(panelWillDisappear:)]) {
            [protocolController panelWillDisappear:panel];
        }
    }
}

- (void)panelDidDisappear:(UIViewController <MVMCoreUIPanelProtocol> *)panel animated:(BOOL)animated {
    if ([panel respondsToSelector:@selector(didDisappear:)]) {
        [panel didDisappear:animated];
    } else {
        [panel viewDidDisappear:animated];
    }
    UIViewController *controller = [self getCurrentDetailViewController];
    if ([controller.class conformsToProtocol:@protocol(MVMCoreUIDetailViewProtocol)]) {
        UIViewController <MVMCoreUIDetailViewProtocol>* protocolController = (UIViewController <MVMCoreUIDetailViewProtocol>*)controller;
        if ([protocolController respondsToSelector:@selector(panelDidDisappear:)]) {
            [protocolController panelDidDisappear:panel];
        }
    }
}

- (void)addPanel:(nonnull UIViewController <MVMCoreUIPanelProtocol> *)panel {
    UIView *view = panel.view;
    [self addChildViewController:panel];
    [self.view addSubview:view];
    [panel didMoveToParentViewController:self];
}

- (void)removePanel:(nullable UIViewController <MVMCoreUIPanelProtocol> *)panel {
    [panel willMoveToParentViewController:nil];
    [panel.view removeFromSuperview];
    [panel removeFromParentViewController];
}

- (void)setupLeftPanel {
    UIViewController <MVMCoreUIPanelProtocol> *panel = nil;
    UIViewController *currentViewController = [self getCurrentDetailViewController];
    if ([currentViewController respondsToSelector:@selector(overrideLeftPanel)]) {
        panel = [((UIViewController <MVMCoreUIDetailViewProtocol> *)currentViewController) overrideLeftPanel];
    } else {
        panel = self.globalLeftPanel;
        self.leftPanelButton = nil;
    }
    
    if (!panel) {
        [self removePanel:self.leftPanel];
    } else if (panel && panel != self.leftPanel) {
        [self removePanel:self.leftPanel];
        [self addPanel:panel];
        self.leftView = panel.view;
        self.leftPanel = panel;
        self.leftView.translatesAutoresizingMaskIntoConstraints = NO;
        NSLayoutConstraint *leftPanelWidth = [NSLayoutConstraint constraintWithItem:self.leftView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:270];
        self.leftView.translatesAutoresizingMaskIntoConstraints = NO;
        leftPanelWidth.active = YES;
        self.leftPanelWidth = leftPanelWidth;
        [NSLayoutConstraint constraintWithItem:self.mainView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.leftView attribute:NSLayoutAttributeRight multiplier:1.0 constant:0].active = YES;
        [NSLayoutConstraint constraintWithItem:self.leftView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.mainView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0].active = YES;
        [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.leftView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0].active = YES;
        
        if ([panel respondsToSelector:@selector(buttonForPanel)]) {
            self.leftPanelButton = [panel buttonForPanel];
        } else if ([panel respondsToSelector:@selector(imageForButtonForPanel)]) {
            self.leftPanelButton = [[UIBarButtonItem alloc] initWithImage:[panel imageForButtonForPanel] style:UIBarButtonItemStylePlain target:self action:@selector(leftPanelButtonPressed:)];
        } else {
            self.leftPanelButton = nil;
        }
    }
}

- (void)setupRightPanel {
    UIViewController <MVMCoreUIPanelProtocol> *panel = nil;
    UIViewController *currentViewController = [self getCurrentDetailViewController];
    if ([currentViewController respondsToSelector:@selector(overrideRightPanel)]) {
        panel = [((UIViewController <MVMCoreUIDetailViewProtocol> *)currentViewController) overrideRightPanel];
    } else {
        panel = self.globalRightPanel;
    }
    
    if (!panel) {
        [self removePanel:self.rightPanel];
        self.rightPanelButton = nil;
    } else if (panel && panel != self.rightPanel) {
        [self removePanel:self.rightPanel];
        [self addPanel:panel];
        self.rightView = panel.view;
        self.rightPanel = panel;
        self.rightView.translatesAutoresizingMaskIntoConstraints = NO;
        NSLayoutConstraint *rightPanelWidth = [NSLayoutConstraint constraintWithItem:self.rightView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:270];
        rightPanelWidth.active = YES;
        self.rightPanelWidth = rightPanelWidth;
        [NSLayoutConstraint constraintWithItem:self.rightView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.mainView attribute:NSLayoutAttributeRight multiplier:1.0 constant:0].active = YES;
        [NSLayoutConstraint constraintWithItem:self.rightView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.mainView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0].active = YES;
        [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.rightView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0].active = YES;
        
        if ([panel respondsToSelector:@selector(buttonForPanel)]) {
            self.rightPanelButton = [panel buttonForPanel];
        } else if ([panel respondsToSelector:@selector(imageForButtonForPanel)]) {
            self.rightPanelButton = [[UIBarButtonItem alloc] initWithImage:[panel imageForButtonForPanel] style:UIBarButtonItemStylePlain target:self action:@selector(rightPanelButtonPressed:)];
        } else {
            self.rightPanelButton = nil;
        }
    }
}

- (void)setupPanels {
    [self forceHideBothDrawers];
    [self setupLeftPanel];
    [self setupRightPanel];
    self.explictlyShowingPanel = nil;
    [self.view layoutIfNeeded];
}

#pragma mark - TabBar

- (nullable UIView <TabBarProtocol>*)createTabBar {
    return nil;
}

- (void)addTabBar:(nonnull UIView <TabBarProtocol>*)tabBar {
    [self.view insertSubview:tabBar atIndex:0];
    self.tabBar = tabBar;
    [tabBar.topAnchor constraintEqualToAnchor:self.bottomProgressBar.bottomAnchor].active = YES;
    [NSLayoutConstraint constraintWithItem:tabBar attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.mainView attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0].active = YES;
    [NSLayoutConstraint constraintWithItem:tabBar attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.mainView attribute:NSLayoutAttributeRight multiplier:1.0 constant:0].active = YES;
    [self updateTabBarShowing:YES];
}

- (void)updateTabBarShowing:(BOOL)showing {
    self.tabBar.hidden = !showing;
    self.bottomConstraint.active = NO;
    if (showing && self.tabBar) {
        NSLayoutConstraint *bottom = [self.view.bottomAnchor constraintEqualToAnchor:self.tabBar.bottomAnchor];
        bottom.active = YES;
        self.bottomConstraint = bottom;
    } else {
        NSLayoutConstraint *bottom = [self.view.bottomAnchor constraintEqualToAnchor:self.bottomProgressBar.bottomAnchor];
        bottom.active = YES;
        self.bottomConstraint = bottom;
    }
    [self.view layoutIfNeeded];
}

#pragma mark - Bottom Progress Bar

- (void)setBottomProgressBarProgress:(float)progress {
    [MVMCoreDispatchUtility performBlockOnMainThread:^{
        if (self.bottomProgressBarHeightConstraint.constant != PaddingOne) {
            self.bottomProgressBarHeightConstraint.constant = PaddingOne;
            [self.bottomProgressBar.superview layoutIfNeeded];
        }
        
        if (progress > 0.05) {
            self.bottomProgressBar.progress = progress;
        } else {
            self.bottomProgressBarHeightConstraint.constant = 0;
            [self.bottomProgressBar.superview layoutIfNeeded];
        }
    }];
}

#pragma mark - View Cyle

- (void)loadView {
    
    UIView *view = [[UIView alloc] init];
    view.translatesAutoresizingMaskIntoConstraints = NO;
    self.view = view;
    
    // Top Alert
    MVMCoreUITopAlertView *topAlertView = nil;
    if ([[CoreUIObject sharedInstance].globalTopAlertDelegate respondsToSelector:@selector(getTopAlertView)]) {
        topAlertView = (MVMCoreUITopAlertView *)[[CoreUIObject sharedInstance].globalTopAlertDelegate getTopAlertView];
        if (topAlertView) {
            self.topAlertView = topAlertView;
            [self.view addSubview:topAlertView];
            [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[topAlertView]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:@{@"topAlertView":topAlertView}]];
        }
    }
    
    // The main view.
    NavigationController *navigationController = [NavigationController setupNavigationController];
    navigationController.manager = self;
    self.navigationController = navigationController;
    
    UIView *mainView = navigationController.view;
    mainView.translatesAutoresizingMaskIntoConstraints = NO;
    [self addChildViewController:navigationController];
    [self.view addSubview:mainView];
    [navigationController didMoveToParentViewController:self];
    self.mainView = mainView;
    
    NSLayoutConstraint *mainLeading = [NSLayoutConstraint constraintWithItem:mainView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0];
    mainLeading.active = YES;
    self.mainViewLeading = mainLeading;
    
    NSLayoutConstraint *mainTrailing = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:mainView attribute:NSLayoutAttributeRight multiplier:1.0 constant:0];
    mainTrailing.active = YES;
    self.mainViewTrailing = mainTrailing;
    
    // Create bottom progress bar
    UIProgressView *progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
    progressView.translatesAutoresizingMaskIntoConstraints = NO;
    progressView.progressTintColor = [UIColor mfTomatoRed];
    [self.view addSubview:progressView];
    self.bottomProgressBar = progressView;
    [NSLayoutConstraint constraintWithItem:progressView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:mainView attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0].active = YES;
    [NSLayoutConstraint constraintWithItem:progressView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:mainView attribute:NSLayoutAttributeRight multiplier:1.0 constant:0].active = YES;
    
    NSLayoutConstraint *bottomProgressHeight = [NSLayoutConstraint constraintWithItem:progressView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:0];
    bottomProgressHeight.active = YES;
    self.bottomProgressBarHeightConstraint = bottomProgressHeight;
    
    if (topAlertView) {
        [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[topAlertView]-0-[mainView]-0-[progressView]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(topAlertView, mainView, progressView)]];
    } else {
        [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[mainView]-0-[progressView]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(mainView, progressView)]];
    }
    
    // Add tabbar if we have it.
    UIView <TabBarProtocol>*tabs = [self createTabBar];
    if (tabs) {
        [self addTabBar:tabs];
    } else {
        [self updateTabBarShowing:NO];
    }
    
    // Cover View
    UIView *coverView = [MVMCoreUICommonViewsUtility commonView];
    coverView.backgroundColor = [UIColor blackColor];
    coverView.alpha = 0;
    coverView.hidden = YES;
    [self.view addSubview:coverView];
    self.mainViewCoverView = coverView;
    [NSLayoutConstraint constraintWithItem:coverView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:mainView attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0].active = YES;
    [NSLayoutConstraint constraintWithItem:coverView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:mainView attribute:NSLayoutAttributeRight multiplier:1.0 constant:0].active = YES;
    [NSLayoutConstraint constraintWithItem:coverView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0].active = YES;
    [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:coverView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0].active = YES;
    
    [self setupPanels];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.topAlertView pinATopViewController:self];
    
    // Creates the back button
    self.backButton = [[UIBarButtonItem alloc] initWithImage:[self imageForBackButton] style:UIBarButtonItemStylePlain target:self action:@selector(backButtonPressed:)];
    
    // Dismisses a panel if the user taps the main view.
    if (!self.tapToDismissGesture) {
        self.tapToDismissGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissPanels:)];
        [self.mainViewCoverView addGestureRecognizer:self.tapToDismissGesture];
    }
        
    self.extendedDrawers =  MFExtendedDrawerLeft | MFExtendedDrawerRight;
    self.prioritizedExtendedPanel = MFExtendedDrawerLeft;
    
    self.view.backgroundColor = [UIColor whiteColor];
}

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    
    // Sets the panel sizes, top space.
    CGFloat viewWidth = CGRectGetWidth(self.view.bounds);
    MFNumberOfDrawers numberOfDrawers = [self numberOfDrawersShouldShow:@(viewWidth)];
    
    CGFloat leftPanelExtendedWidth = [self leftPanelExtendedWidth];
    CGFloat leftPanelMaxWidth = [self leftPanelMaxWidth];
    if ([self shouldExtendLeftPanel:numberOfDrawers] && viewWidth > leftPanelExtendedWidth) {
        self.leftPanelWidth.constant = leftPanelExtendedWidth;
    } else if (viewWidth > leftPanelMaxWidth) {
        self.leftPanelWidth.constant = leftPanelMaxWidth;
    } else {
        self.leftPanelWidth.constant = viewWidth;
    }
    
    CGFloat rightPanelExtendedWidth = [self rightPanelExtendedWidth];
    CGFloat rightPanelMaxWidth = [self rightPanelMaxWidth];
    if ([self shouldExtendRightPanel:numberOfDrawers] && viewWidth > rightPanelExtendedWidth) {
        self.rightPanelWidth.constant = rightPanelExtendedWidth;
    } else if (viewWidth > rightPanelMaxWidth) {
        self.rightPanelWidth.constant = rightPanelMaxWidth;
    } else {
        self.rightPanelWidth.constant = viewWidth;
    }
    
    [self.view layoutIfNeeded];
}

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
    
    self.transitionWidth = @(size.width);

    [self forceHideBothDrawers];
    
    void (^animate)(id<UIViewControllerTransitionCoordinatorContext>) = nil;
    if (self.leftPanelIsAccessible || self.rightPanelIsAccessible) {
        animate = ^(id<UIViewControllerTransitionCoordinatorContext> context) {
            [self resetDrawers];
        };
    }
    
    [coordinator animateAlongsideTransition:animate completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
        self.transitionWidth = nil;
        /*self.leftPanel.needToUpdateUI = YES;
        [self.leftPanel.view setNeedsLayout];
        [self.leftPanel.view layoutIfNeeded];*/
        [self.topAlertView updateView:size.width];
    }];
}

- (void)resetDrawers {
    if (!self.navigationItemViewController) { return; }
    if ([self navigationBarModelExists]) {
        [self updateNavigationBarForViewController:self.navigationItemViewController];
    } else {
        // Legacy
        [self setLeftPanelIsAccessible:self.leftPanelIsAccessible forViewController:self.navigationItemViewController updateNavigationButtons:YES];
        [self setRightPanelIsAccessible:self.rightPanelIsAccessible forViewController:self.navigationItemViewController updateNavigationButtons:YES];
        
        [self.view setNeedsLayout];
        [self.view layoutIfNeeded];
    }
}

- (UIStatusBarStyle)preferredStatusBarStyle {
    if (self.topAlertView.topAlertObject) {
        return self.topAlertView.statusBarStyle;
    } else {
        UIStatusBarStyle style = [self getDefaultStatusBarStyle];
        [self.topAlertView resetDefaultBackgroundColor:[self getDefaultStatusBarBackgroundColor] basedOnStatusBarStyle:style];
        return style;
    }
}

- (UIStatusBarStyle)getDefaultStatusBarStyle {
    UIViewController *viewController = [self getCurrentDetailViewController];
    if ([viewController conformsToProtocol:@protocol(MVMCoreUIDetailViewProtocol)]
        && [viewController respondsToSelector:@selector(defaultStatusBarStyle)]
        && [((UIViewController <MVMCoreUIDetailViewProtocol> *)viewController) defaultStatusBarStyle]) {
        return [((UIViewController <MVMCoreUIDetailViewProtocol> *)viewController) defaultStatusBarStyle];
    }
    return UIStatusBarStyleDefault;
}

- (UIColor *)getDefaultStatusBarBackgroundColor {
    UIViewController *viewController = [self getCurrentDetailViewController];
    if ([viewController conformsToProtocol:@protocol(MVMCoreUIDetailViewProtocol)]
        && [viewController respondsToSelector:@selector(defaultStatusBarBackgroundColor)]
        && [((UIViewController <MVMCoreUIDetailViewProtocol> *)viewController) defaultStatusBarBackgroundColor]) {
        return [((UIViewController <MVMCoreUIDetailViewProtocol> *)viewController) defaultStatusBarBackgroundColor];
    }
    return nil;
}

- (BOOL)isAPanelShowing {
    return fabs(self.mainViewLeading.constant) > 1;
}

#pragma mark - Getters

// Returns the desired view or falls back. Hot fix until we can get away from using these functions...
+ (CGRect)getBounds:(UIView *)desiredView {
    UIView *view = desiredView ?: [MVMCoreNavigationHandler sharedNavigationHandler].navigationController.view ?: [UIApplication sharedApplication].keyWindow.rootViewController.view;
    return view ? view.bounds : [UIScreen mainScreen].bounds;
}

+ (CGFloat)getDetailViewWidth {
    return CGRectGetWidth([self getBounds:[MVMCoreUISession sharedGlobal].splitViewController.mainView]);
}

+ (CGFloat)getDetailViewHeight {
    return CGRectGetHeight([self getBounds:[MVMCoreUISession sharedGlobal].splitViewController.mainView]);
}

+ (CGFloat)getApplicationViewWidth {
    __block CGFloat width;
    [MVMCoreDispatchUtility performSyncBlockOnMainThread:^{
        width = CGRectGetWidth([self getBounds:[MVMCoreUISession sharedGlobal].splitViewController.view.superview]);
    }];
    return width;
}

+ (CGFloat)getApplicationViewMaxSize {
    return MAX(CGRectGetWidth([MVMCoreUISession sharedGlobal].splitViewController.view.bounds), CGRectGetHeight([MVMCoreUISession sharedGlobal].splitViewController.view.superview.bounds));
}

- (UIViewController *)getCurrentVisibleController {
    UIViewController *baseViewController = [MVMCoreNavigationHandler sharedNavigationHandler].viewControllerToPresentOn ?: [UIApplication sharedApplication].keyWindow.rootViewController;
    UIViewController *viewController = nil;
    while (baseViewController.presentedViewController && !baseViewController.presentedViewController.isBeingDismissed) {
        viewController = baseViewController.presentedViewController;
        baseViewController = viewController;
    }
    // if it is not presented viewcontroller, existing BAU logic will be working
    if (!viewController) {
        viewController = [MVMCoreUIUtility getViewControllerTraversingManagers:self.navigationController.topViewController];
    }
    return viewController;
}

- (UIViewController *)getCurrentDetailViewController {
    __block UIViewController *viewController = nil;
    [MVMCoreDispatchUtility performSyncBlockOnMainThread:^{
        viewController = [MVMCoreUIUtility getViewControllerTraversingManagers:self.navigationController.topViewController];
    }];
    return viewController;
}

#pragma mark - navigation bar

- (void)setNavigationIconColor:(nullable UIColor *)color {
    if ([self.leftPanelButton respondsToSelector:@selector(setIconColor:)]) {
        [((UIBarButtonItem <MVMCoreUIPanelButtonProtocol>*)self.leftPanelButton) setIconColor:color];
    }
    if ([self.rightPanelButton respondsToSelector:@selector(setIconColor:)]) {
        [((UIBarButtonItem <MVMCoreUIPanelButtonProtocol>*)self.rightPanelButton) setIconColor:color];
    }
}

@end
