#import "TGMenuView.h"

#import <QuartzCore/QuartzCore.h>

#import "TGFont.h"
#import "TGImageUtils.h"

#pragma mark -

static CGFloat diameter = 16.0f;

static UIColor *highlightColor() {
    static UIColor *color = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        color = [UIColor colorWithWhite:1.0f alpha:0.25f];
    });
    return color;
}

static UIImage *menuBackgroundMask() {
    static UIImage *image = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        UIColor *color = [UIColor whiteColor];
        UIGraphicsBeginImageContextWithOptions(CGSizeMake(diameter, diameter), false, 0.0f);
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSetFillColorWithColor(context, color.CGColor);
        CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, diameter, diameter));
        image = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:(NSInteger)(diameter / 2.0f) topCapHeight:(NSInteger)(diameter / 2.0f)];
        UIGraphicsEndImageContext();
    });
    return image;
}

static UIImage *menuHighlightedBackground() {
    static UIImage *image = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        UIColor *color = highlightColor();
        UIGraphicsBeginImageContextWithOptions(CGSizeMake(diameter, diameter), false, 0.0f);
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSetFillColorWithColor(context, color.CGColor);
        CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, diameter, diameter));
        image = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:(NSInteger)(diameter / 2.0f) topCapHeight:(NSInteger)(diameter / 2.0f)];
        UIGraphicsEndImageContext();
    });
    return image;
}

static CGFloat pagerButtonWidth = 32.0f;
static UIImage *pagerLeftButtonImage() {
    static UIImage *image = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        CGSize size = CGSizeMake(pagerButtonWidth, 36.0f);
        UIGraphicsBeginImageContextWithOptions(size, false, 0.0f);
        CGContextRef context = UIGraphicsGetCurrentContext();
        
        CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
        CGContextSaveGState(context);
        CGContextTranslateCTM(context, size.width / 2.0f, size.height / 2.0f);
        CGContextScaleCTM(context, -0.5f, 0.5f);
        CGContextTranslateCTM(context, -size.width / 2.0f + 8.0f, -size.height / 2.0f + 7.0f);
        TGDrawSvgPath(context, @"M0,0 L0,22 L18,11 L0,0 L0,0 Z ");
        CGContextSetFillColorWithColor(context, highlightColor().CGColor);
        CGContextRestoreGState(context);
        
        CGContextSetFillColorWithColor(context, highlightColor().CGColor);
        CGContextFillRect(context, CGRectMake(size.width - 1.0f, 0.0f, 1.0f, size.height));
        image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    });
    return image;
}

static UIImage *pagerLeftButtonHighlightedImage() {
    static UIImage *image = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        CGSize size = CGSizeMake(pagerButtonWidth, 36.0f);
        UIGraphicsBeginImageContextWithOptions(size, false, 0.0f);
        CGContextRef context = UIGraphicsGetCurrentContext();

        CGContextSetFillColorWithColor(context, highlightColor().CGColor);
        [menuHighlightedBackground() drawInRect:CGRectMake(0.0f, 0.0f, size.width * 2.0f, size.height)];
        
        CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
        CGContextSaveGState(context);
        CGContextTranslateCTM(context, size.width / 2.0f, size.height / 2.0f);
        CGContextScaleCTM(context, -0.5f, 0.5f);
        CGContextTranslateCTM(context, -size.width / 2.0f + 8.0f, -size.height / 2.0f + 7.0f);
        TGDrawSvgPath(context, @"M0,0 L0,22 L18,11 L0,0 L0,0 Z ");
        CGContextSetFillColorWithColor(context, highlightColor().CGColor);
        CGContextRestoreGState(context);
        
        image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    });
    return image;
}

@protocol TGMenuButtonViewDelegate <NSObject>

- (void)menuButtonHighlighted;

@end

@interface TGMenuButtonView () {
    UIView *_highlightedView;
}

@property (nonatomic) bool highlightDisabled;
@property (nonatomic) bool isOptional;
@property (nonatomic) bool isTrailing;
@property (nonatomic, weak) id<TGMenuButtonViewDelegate> delegate;
@property (nonatomic) bool isMultiline;
@property (nonatomic) CGFloat maxWidth;

@end

@implementation TGMenuButtonView

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self != nil) {
        _highlightedView = [[UIView alloc] init];
        _highlightedView.backgroundColor = highlightColor();
        [self addSubview:_highlightedView];
        _highlightedView.hidden = true;
    }
    return self;
}

- (void)setHighlighted:(BOOL)highlighted
{
    [super setHighlighted:highlighted];
    bool selected = self.selected;
    
    __strong id<TGMenuButtonViewDelegate> delegate = _delegate;
    [delegate menuButtonHighlighted];
    
    highlighted = highlighted || selected;
    
    _highlightedView.hidden = !(highlighted || selected) || _highlightDisabled;
}

- (void)setSelected:(BOOL)selected
{
    [super setSelected:selected];
    bool highlighted = self.highlighted;
    
    __strong id<TGMenuButtonViewDelegate> delegate = _delegate;
    [delegate menuButtonHighlighted];
    
    selected = selected || highlighted;
    
    _highlightedView.hidden = !(highlighted || selected) || _highlightDisabled;
}

- (void)sizeToFit
{
    if (self.isMultiline)
    {
        CGSize size = [[self titleForState:UIControlStateNormal] sizeWithFont:self.titleLabel.font constrainedToSize:CGSizeMake(self.maxWidth - 34.0f, FLT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
        self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, ceil(size.width) + 34, MAX(41.0f, ceil(size.height) + 20.0f));
    }
    else
    {
        self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, [[self titleForState:UIControlStateNormal] sizeWithFont:self.titleLabel.font].width + 34, 41);
    }
}

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    _highlightedView.frame = CGRectMake(0.0f, -20.0f, self.frame.size.width, self.frame.size.height + 40.0f);
}

@end

#pragma mark -

@interface TGMenuView () <TGMenuButtonViewDelegate, UIScrollViewDelegate>
{
    NSDictionary *_userInfo;
    
    UIScrollView *_buttonContainer;
    UIView *_buttonContainerContainer;
    UIButton *_leftPagerButton;
    UIButton *_rightPagerButton;
    
    UIImageView *_containerMaskView;
    
    CGFloat _maxWidth;
}

@property (nonatomic, strong) NSMutableArray *buttonViews;
@property (nonatomic, strong) NSMutableArray *separatorViews;
@property (nonatomic, strong) NSArray *buttonDescriptions;

@property (nonatomic) CGFloat arrowLocation;
@property (nonatomic) bool arrowOnTop;

@property (nonatomic, strong) UIImageView *arrowTopView;
@property (nonatomic, strong) UIImageView *arrowBottomView;

@property (nonatomic, strong) ASHandle *watcherHandle;

@end

@implementation TGMenuView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        self.alpha = 0.0f;
        self.layer.anchorPoint = CGPointMake(0.5f, 1.0f);
        self.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
        
        _maxWidth = 310.0f;
        
        //_arrowTopView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"MenuArrowTop.png"] highlightedImage:[UIImage imageNamed:@"MenuArrowTop_Highlighted.png"]];
        _arrowTopView = [[UIImageView alloc] init];
        _arrowTopView.frame = CGRectMake(0.0f, 0.0f, 20.0f, 12.0f);
        [self addSubview:_arrowTopView];
        
        //_arrowBottomView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"MenuArrowBottom.png"] highlightedImage:[UIImage imageNamed:@"MenuArrowBottom_Highlighted.png"]];
        _arrowBottomView = [[UIImageView alloc] init];
        _arrowBottomView.frame = CGRectMake(0.0f, 0.0f, 20.0f, 14.5f);
        [self addSubview:_arrowBottomView];
        
        _buttonContainerContainer = [[UIView alloc] init];
        
        if (iosMajorVersion() >= 8) {
            UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]];
            effectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
            effectView.frame = CGRectMake(0.0f, -20.0f, 0.0f, 40.0f);
            [_buttonContainerContainer addSubview:effectView];
        }
        
        UIView *effectView = [[UIView alloc] init];
        effectView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:iosMajorVersion() >= 8 ? 0.8f : 0.9f];
        effectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        effectView.frame = CGRectMake(0.0f, -20.0f, 0.0f, 40.0f);
        [_buttonContainerContainer addSubview:effectView];
        
        [self addSubview:_buttonContainerContainer];
        
        _buttonContainer = [[UIScrollView alloc] init];
        _buttonContainer.clipsToBounds = true;
        _buttonContainer.alwaysBounceHorizontal = false;
        _buttonContainer.alwaysBounceVertical = false;
        _buttonContainer.showsHorizontalScrollIndicator = false;
        _buttonContainer.showsVerticalScrollIndicator = false;
        _buttonContainer.pagingEnabled = true;
        _buttonContainer.delaysContentTouches = false;
        _buttonContainer.canCancelContentTouches = true;
        _buttonContainer.delegate = self;
        _buttonContainer.scrollEnabled = false;
        [_buttonContainerContainer addSubview:_buttonContainer];
        
        _leftPagerButton = [[UIButton alloc] init];
        [_leftPagerButton setBackgroundImage:pagerLeftButtonImage() forState:UIControlStateNormal];
        [_leftPagerButton setBackgroundImage:pagerLeftButtonHighlightedImage() forState:UIControlStateHighlighted];
        [_leftPagerButton addTarget:self action:@selector(pagerButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
        _rightPagerButton = [[UIButton alloc] init];
        [_rightPagerButton setBackgroundImage:pagerLeftButtonImage() forState:UIControlStateNormal];
        [_rightPagerButton setBackgroundImage:pagerLeftButtonHighlightedImage() forState:UIControlStateHighlighted];
        _rightPagerButton.transform = CGAffineTransformMakeScale(-1.0f, 1.0f);
        [_rightPagerButton addTarget:self action:@selector(pagerButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:_leftPagerButton];
        [self addSubview:_rightPagerButton];
        
        _buttonViews = [[NSMutableArray alloc] init];
        _separatorViews = [[NSMutableArray alloc] init];
        
        _arrowLocation = 50;
    }
    return self;
}

- (void)setButtonsAndActions:(NSArray *)buttonsAndActions watcherHandle:(ASHandle *)watcherHandle
{
    _watcherHandle = watcherHandle;
    
    _buttonDescriptions = buttonsAndActions;
    
    int index = -1;
    for (NSDictionary *dict in buttonsAndActions)
    {
        index++;
        
        NSString *title = [dict objectForKey:@"title"];
        
        TGMenuButtonView *buttonView = nil;
        
        if (index < (int)_buttonViews.count)
            buttonView = [_buttonViews objectAtIndex:index];
        else
        {
            buttonView = [[TGMenuButtonView alloc] init];
            
            if (self.multiline)
            {
                buttonView.titleLabel.numberOfLines = 0;
                buttonView.isMultiline = true;
                buttonView.maxWidth = _maxWidth;
            }
            
            buttonView.delegate = self;
            [buttonView setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
            [buttonView setTitleColor:UIColorRGBA(0xffffff, 0.5f) forState:UIControlStateDisabled];
            buttonView.titleLabel.font = TGSystemFontOfSize(14);
            [buttonView addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
            [_buttonViews addObject:buttonView];
            [_buttonContainer addSubview:buttonView];
        }
        
        buttonView.isTrailing = [dict[@"trailing"] boolValue];
        buttonView.isOptional = [dict[@"optional"] boolValue];
        
        [buttonView setTitle:title forState:UIControlStateNormal];
        buttonView.selected = false;
    }
    
    while ((int)_buttonViews.count > index + 1)
    {
        TGMenuButtonView *buttonView = [_buttonViews lastObject];
        buttonView.delegate = nil;
        [buttonView removeFromSuperview];
        [_buttonViews removeLastObject];
    }
    
    if (_buttonViews.count != 0) {
        while (_separatorViews.count < _buttonViews.count - 1)
        {
            UIView *separatorView = [[UIImageView alloc] init];
            separatorView.backgroundColor = highlightColor();
            [_buttonContainer addSubview:separatorView];
            [_separatorViews addObject:separatorView];
        }
    }
    
    if (_buttonViews.count != 0) {
        while (_separatorViews.count > _buttonViews.count - 1)
        {
            UIImageView *separatorView = [_separatorViews lastObject];
            [separatorView removeFromSuperview];
            [_separatorViews removeLastObject];
        }
    }
    
    index = -1;
    for (TGMenuButtonView *buttonView in _buttonViews)
    {
        index++;
        
        [buttonView sizeToFit];
        if (index == 0 || index == (int)_buttonViews.count - 1)
        {
            CGRect buttonFrame = buttonView.frame;
            buttonFrame.size.width += 1;
            buttonView.frame = buttonFrame;
        }
    }
    
    [self updateBackgrounds];
    
    [self setNeedsLayout];
}

- (void)setButtonHighlightDisabled:(bool)buttonHighlightDisabled
{
    _buttonHighlightDisabled = buttonHighlightDisabled;
    
    for (TGMenuButtonView *view in _buttonViews)
        view.highlightDisabled = buttonHighlightDisabled;
}

- (void)menuButtonHighlighted
{
    if (self.buttonHighlightDisabled)
        return;
    
    NSInteger highlightedIndex = -1;
    
    bool arrowHighlighted = false;
    
    NSInteger index = -1;
    for (TGMenuButtonView *buttonView in _buttonViews)
    {
        index++;
        
        bool containsArrow = _arrowLocation >= buttonView.frame.origin.x && _arrowLocation < buttonView.frame.origin.x + buttonView.frame.size.width;
        
        if (index == 0)
        {
            if (_arrowLocation < buttonView.frame.size.width)
                containsArrow = true;
        }
        
        if (index == (NSInteger)_buttonViews.count - 1)
        {
            if (_arrowLocation >= buttonView.frame.origin.x)
                containsArrow = true;
        }
        
        if (buttonView.highlighted || buttonView.selected)
        {
            arrowHighlighted = containsArrow;
            highlightedIndex = index;
            break;
        }
    }
}

- (UIImage *)highlightMask {
    UIGraphicsBeginImageContextWithOptions(_buttonContainer.bounds.size, false, 0.0f);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
    
    [menuBackgroundMask() drawInRect:CGRectMake(0.0f, 10.0f, _buttonContainer.bounds.size.width, _buttonContainer.bounds.size.height - 20.0f)];
    
    if (!_arrowBottomView.hidden) {
        CGPoint arrow = [_arrowBottomView convertRect:_arrowBottomView.bounds toView:_buttonContainerContainer].origin;
        arrow.x += 1.0f;
        CGContextBeginPath(context);
        CGContextMoveToPoint(context, arrow.x, arrow.y);
        CGContextAddLineToPoint(context, arrow.x + 18.0f, arrow.y);
        CGContextAddLineToPoint(context, arrow.x + 18.0f / 2.0f, arrow.y + 10.0f);
        CGContextClosePath(context);
        CGContextFillPath(context);
    } else if (!_arrowTopView.hidden) {
        CGPoint arrow = [_arrowTopView convertRect:_arrowTopView.bounds toView:_buttonContainerContainer].origin;
        arrow.x += 1.0f;
        arrow.y += 1.0f;
        CGContextBeginPath(context);
        CGContextMoveToPoint(context, arrow.x, arrow.y + 10.0f);
        CGContextAddLineToPoint(context, arrow.x + 18.0f / 2.0f, arrow.y);
        CGContextAddLineToPoint(context, arrow.x + 18.0f, arrow.y + 10.0f);
        CGContextClosePath(context);
        CGContextFillPath(context);
    }
    
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

- (void)updateBackgrounds
{
    NSInteger index = -1;
    for (TGMenuButtonView *buttonView in _buttonViews)
    {
        index++;
        
        UIEdgeInsets titleInset = UIEdgeInsetsMake(0, 0, 1, 0);
        
        if (index == 0)
        {
            //titleInset.left += 2;
        }
        
        if (index == (NSInteger)_buttonViews.count - 1)
        {
            //titleInset.right += 2;
        }
        
        buttonView.titleEdgeInsets = titleInset;
    }
}

- (void)sizeToFitToWidth:(CGFloat)maxWidth {
    _maxWidth = maxWidth - 20.0f;
    [self sizeToFit];
}

- (void)sizeToFit
{
    CGAffineTransform transform = self.transform;
    self.transform = CGAffineTransformIdentity;
    
    CGFloat maxWidth = _maxWidth;
    CGFloat buttonHeight = 41.0f;
    
    NSMutableArray *pages = [[NSMutableArray alloc] init];
    NSMutableArray *currentPageButtons = [[NSMutableArray alloc] init];
    CGFloat currentPageWidth = 0.0f;
    
    NSMutableArray *optionalButtons = [[NSMutableArray alloc] init];
    
    for (TGMenuButtonView *buttonView in _buttonViews)
    {
        if (buttonView.isOptional) {
            buttonView.hidden = true;
            [optionalButtons addObject:buttonView];
        } else {
            CGFloat buttonWidth = buttonView.frame.size.width;
            bool added = false;
            if (currentPageWidth + buttonWidth > maxWidth) {
                if (currentPageButtons.count == 0) {
                    [currentPageButtons addObject:buttonView];
                    added = true;
                }
                
                [pages addObject:currentPageButtons];
                currentPageButtons = [[NSMutableArray alloc] init];
                currentPageWidth = 0.0f;
            }
            
            if (!added) {
                currentPageWidth += buttonWidth;
                [currentPageButtons addObject:buttonView];
            }
        }

    }
    
    if (currentPageButtons.count != 0) {
        if (currentPageButtons.count == 1) {
            for (TGMenuButtonView *buttonView in optionalButtons)
            {
                CGFloat buttonWidth = buttonView.frame.size.width;
                if (currentPageWidth + buttonWidth > maxWidth) {
                    break;
                }
                
                buttonView.hidden = false;
                currentPageWidth += buttonWidth;
                [currentPageButtons addObject:buttonView];
            }
        }
        
        [pages addObject:currentPageButtons];
    }
    
    for (NSMutableArray *page in pages) {
        NSUInteger index = 0;
        for (TGMenuButtonView *button in page) {
            if (button.isTrailing) {
                if (index + 1 != page.count) {
                    [page removeObjectAtIndex:index];
                    [page addObject:button];
                }
                break;
            }
            index++;
        }
    }
    
    CGFloat maxPageWidth = 0.0f;

    NSInteger pageIndex = -1;
    for (NSArray *buttons in pages) {
        CGFloat sumWidth = 0.0f;
        NSInteger buttonIndex = -1;
        for (UIView *button in buttons) {
            [button sizeToFit];
            buttonIndex++;
            if (buttonIndex != 0) {
                sumWidth += 1.0f;
            }
            sumWidth += button.frame.size.width;
            
            if (_multiline) {
                buttonHeight = MAX(buttonHeight, button.frame.size.height);
            }
        }
        if (pages.count > 1) {
            if (pageIndex == 0) {
                sumWidth += pagerButtonWidth;
            } else if (pageIndex == (NSInteger)pages.count - 1) {
                sumWidth += pagerButtonWidth;
            } else {
                sumWidth += pagerButtonWidth * 2.0f;
            }
        }
        maxPageWidth = MAX(maxPageWidth, MIN(maxWidth, sumWidth));
    }
    
    NSInteger nextSeparatorIndex = 0;
    
    CGFloat diff = buttonHeight - 41.0f;
    CGFloat currentPageStart = 0.0f;
    pageIndex = -1;
    for (NSArray *buttons in pages) {
        pageIndex++;
        
        CGFloat sumWidth = 0.0f;
        NSInteger buttonIndex = -1;
        for (UIView *button in buttons) {
            buttonIndex++;
            if (buttonIndex != 0) {
                sumWidth += 1.0f;
            }
            sumWidth += button.frame.size.width;
        }
        
        CGFloat leftOffset = 0.0f;
        CGFloat pageContentWidth = maxPageWidth;
        if (pages.count > 1) {
            if (pageIndex == 0) {
                pageContentWidth -= pagerButtonWidth;
            } else if (pageIndex == (NSInteger)pages.count - 1) {
                leftOffset = pagerButtonWidth;
                pageContentWidth -= pagerButtonWidth;
            } else {
                leftOffset = pagerButtonWidth;
                pageContentWidth -= pagerButtonWidth * 2.0f;
            }
        }
        
        CGFloat factor = pageContentWidth / sumWidth;
        CGFloat buttonStart = currentPageStart + leftOffset;
        buttonIndex = -1;
        for (UIView *button in buttons) {
            buttonIndex++;
            
            if (buttonIndex != 0) {
                UIView *separatorView = _separatorViews[nextSeparatorIndex++];
                separatorView.frame = CGRectMake(buttonStart, 0.0f, 1.0f, 36.0f + 20.0f);
                buttonStart += 1.0f;
            }
            
            CGFloat buttonWidth = CGFloor(button.frame.size.width * factor);
            if (buttonIndex == (NSInteger)buttons.count - 1) {
                buttonWidth = MAX(buttonWidth, currentPageStart + leftOffset + pageContentWidth - buttonStart);
            }
            button.frame = CGRectMake(buttonStart, -2.0f + 10.0f, buttonWidth, button.frame.size.height);
            
            buttonStart += buttonWidth;
        }
        
        currentPageStart += maxPageWidth;
    }

    _buttonContainerContainer.frame = CGRectMake(0.0f, 2.0f - 10.0f, maxPageWidth, 36.0f + 20.0f + diff);
    _buttonContainer.frame = _buttonContainerContainer.bounds;
    _buttonContainer.contentSize = CGSizeMake(maxPageWidth * pages.count, _buttonContainer.frame.size.height);
    _buttonContainer.contentOffset = CGPointZero;
    
    _leftPagerButton.frame = CGRectMake(0.0f, 2.0f, pagerButtonWidth, 36.0f);
    _rightPagerButton.frame = CGRectMake(maxPageWidth - pagerButtonWidth, 2.0f, pagerButtonWidth, 36.0f);
    
    //_backgroundView.frame = CGRectMake(0.0f, 2.0f, maxPageWidth, 36.0f);
    self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, maxPageWidth, buttonHeight);
    
    CGFloat minArrowX = 10.0f;
    CGFloat maxArrowX = self.frame.size.width - 10.0f;
    
    CGFloat arrowX = CGFloor(_arrowLocation - _arrowTopView.frame.size.width / 2);
    arrowX = MIN(MAX(minArrowX, arrowX), maxArrowX);
    
    _arrowTopView.frame = CGRectMake(arrowX, -9.0, _arrowTopView.frame.size.width, _arrowTopView.frame.size.height);
    _arrowBottomView.frame = CGRectMake(arrowX, 37.0f + diff, _arrowBottomView.frame.size.width, _arrowBottomView.frame.size.height);
    
    _arrowTopView.hidden = !_arrowOnTop;
    _arrowBottomView.hidden = _arrowOnTop;
    
    if (_containerMaskView == nil) {
        _containerMaskView = [[UIImageView alloc] init];
        //[_buttonContainerContainer addSubview:_containerMaskView];
    }
    _containerMaskView.image = [self highlightMask];
    [_containerMaskView sizeToFit];
    _buttonContainerContainer.layer.mask = _containerMaskView.layer;
    
    [self scrollViewDidScroll:_buttonContainer];
    
    self.transform = transform;
}

- (void)showInView:(UIView *)view fromRect:(CGRect)rect
{
    [self showInView:view fromRect:rect animated:true];
}

- (void)showInView:(UIView *)view fromRect:(CGRect)rect animated:(bool)animated
{
    CGAffineTransform transform = self.transform;
    self.transform = CGAffineTransformIdentity;
    
    CGRect frame = self.frame;
    frame.origin.x = CGFloor(rect.origin.x + rect.size.width / 2 - frame.size.width / 2);
    if (frame.origin.x < 4)
        frame.origin.x = 4;
    if (frame.origin.x + frame.size.width > view.frame.size.width - 4)
        frame.origin.x = view.frame.size.width - 4 - frame.size.width;
    
    frame.origin.y = rect.origin.y - frame.size.height - 14;
    if (frame.origin.y < 2)
    {
        frame.origin.y = rect.origin.y + rect.size.height + 17;
        if (frame.origin.y + frame.size.height > view.frame.size.height - 14)
        {
            frame.origin.y = CGFloor((view.frame.size.height - frame.size.height) / 2);
            _arrowOnTop = false;
        }
        else
            _arrowOnTop = true;
    }
    else
    {
        _arrowOnTop = false;
    }
    
    _arrowLocation = CGFloor(rect.origin.x + rect.size.width / 2) - frame.origin.x;
    
    self.layer.anchorPoint = CGPointMake(MAX(0.0f, MIN(1.0f, _arrowLocation / frame.size.width)), _arrowOnTop ? -0.2f : 1.2f);
    
    self.frame = frame;
    [self setNeedsLayout];
    [self layoutIfNeeded];
    [self sizeToFit];
    
    self.transform = transform;
    
    self.layer.rasterizationScale = [[UIScreen mainScreen] scale];
    self.layer.shouldRasterize = true;
    
    self.alpha = 1.0f;
 
    if (animated)
    {
        [UIView animateWithDuration:0.142 delay:0 options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState animations:^
        {
            self.transform = CGAffineTransformMakeScale(1.07f, 1.07f);
        } completion:^(BOOL finished)
        {
            if(finished)
            {
                [UIView animateWithDuration:0.08 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^
                {
                    self.transform = CGAffineTransformMakeScale(0.967f, 0.967f);
                } completion:^(BOOL finished)
                {
                    if (finished)
                    {
                        [UIView animateWithDuration:0.06 delay:0 options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState animations:^
                        {
                            self.transform = CGAffineTransformIdentity;
                        } completion:^(BOOL finished)
                        {
                            if (finished)
                            {
                                self.layer.shouldRasterize = false;
                            }
                        }];
                    }
                }];
            }
        }];
    }
    else
    {
        self.transform = CGAffineTransformIdentity;
        self.alpha = 0.0f;
        [UIView animateWithDuration:0.3 animations:^
        {
            self.alpha = 1.0f;
        }];
    }
}

- (void)hide:(dispatch_block_t)completion
{
    [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^
    {
        self.alpha = 0.0f;
    } completion:^(BOOL finished)
    {
        if (finished)
        {
            self.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
            
            if (completion)
                completion();
        }
    }];
}

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    /*_buttonContainer.frame = CGRectMake(0.0f, 2.0f, self.frame.size.width, self.frame.size.height - 5.0f);
    
    float currentX = 0;
    
    NSInteger index = -1;
    for (TGMenuButtonView *buttonView in _buttonViews)
    {
        index++;
        
        buttonView.frame = CGRectMake(currentX, -2.0f, buttonView.frame.size.width, buttonView.frame.size.height);
        currentX += buttonView.frame.size.width;
        [buttonView layoutSubviews];
    }
    
    index = -1;
    for (TGMenuButtonView *buttonView in _buttonViews)
    {
        index++;
        
        CGFloat linePosition = 0.0f;
        CGFloat lineWidth = buttonView.frame.size.width;
        
        if (index > 0)
        {
            UIImageView *separatorView = [_separatorViews objectAtIndex:index - 1];
            separatorView.frame = CGRectMake(buttonView.frame.origin.x - 1, 0.0f, separatorView.image.size.width, 36.0f);
        }
        
        bool containsArrow = _arrowLocation >= buttonView.frame.origin.x && _arrowLocation < buttonView.frame.origin.x + buttonView.frame.size.width;
        
        if (index == 0)
        {
            linePosition += 10;
            lineWidth -= 10;
            
            if (_arrowLocation < buttonView.frame.size.width)
                containsArrow = true;
        }
        
        if (index == (NSInteger)_buttonViews.count - 1)
        {
            lineWidth -= 10;
            
            if (_arrowLocation >= buttonView.frame.origin.x)
                containsArrow = true;
        }
    }*/
}

#pragma mark -

- (void)buttonPressed:(TGMenuButtonView *)buttonView
{
    NSInteger index = -1;
    for (TGMenuButtonView *listButtonView in _buttonViews)
    {
        index++;
        
        if (listButtonView == buttonView)
        {
            buttonView.selected = true;
            
            if (index < (NSInteger)_buttonDescriptions.count)
            {
                NSString *action = [[_buttonDescriptions objectAtIndex:index] objectForKey:@"action"];
                NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
                options[@"action"] = action;
                if (_userInfo != nil)
                    options[@"userInfo"] = _userInfo;
                [_watcherHandle requestAction:@"menuAction" options:options];
            }
            
            if ([self.superview isKindOfClass:[TGMenuContainerView class]])
                [(TGMenuContainerView *)self.superview hideMenu];
            
            break;
        }
    }
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView == _buttonContainer) {
        if (scrollView.contentSize.width > scrollView.bounds.size.width + FLT_EPSILON) {
            CGFloat leftDistance = scrollView.contentOffset.x;
            CGFloat rightDistance = scrollView.contentSize.width - (scrollView.contentOffset.x + scrollView.bounds.size.width);
            _leftPagerButton.alpha = MAX(0.0f, MIN(1.0f, leftDistance / _leftPagerButton.frame.size.width));
            _rightPagerButton.alpha = MAX(0.0f, MIN(1.0f, rightDistance / _rightPagerButton.frame.size.width));
        } else {
            _leftPagerButton.alpha = 0.0f;
            _rightPagerButton.alpha = 0.0f;
        }
    }
}

- (void)pagerButtonPressed:(UIView *)button {
    CGFloat targetOffset = _buttonContainer.contentOffset.x;
    
    if (button == _leftPagerButton) {
        NSInteger page = ((NSInteger)_buttonContainer.contentOffset.x) / ((NSInteger)_buttonContainer.bounds.size.width);
        if (page > 0) {
            targetOffset = (page - 1) * _buttonContainer.bounds.size.width;
        }
    } else if (button == _rightPagerButton) {
        NSInteger page = ((NSInteger)_buttonContainer.contentOffset.x) / ((NSInteger)_buttonContainer.bounds.size.width);
        if (page + 1 < (NSInteger)(_buttonContainer.contentSize.width / _buttonContainer.bounds.size.width)) {
            targetOffset = (page + 1) * _buttonContainer.bounds.size.width;
        }
    }
    
    if (ABS(targetOffset - _buttonContainer.contentOffset.x) > FLT_EPSILON) {
        if (iosMajorVersion() >= 7) {
            [UIView animateWithDuration:0.4 delay:0.0 usingSpringWithDamping:0.8f initialSpringVelocity:0.0f options:0 animations:^{
                _buttonContainer.contentOffset = CGPointMake(targetOffset, 0.0f);
            } completion:nil];
        } else {
            [UIView animateWithDuration:0.2 animations:^{
                _buttonContainer.contentOffset = CGPointMake(targetOffset, 0.0f);
            }];
        }
    }
}

@end

#pragma mark -

@interface TGMenuContainerView ()

@end

@implementation TGMenuContainerView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self != nil)
    {
        _menuView = [[TGMenuView alloc] init];
        [self addSubview:_menuView];
    }
    return self;
}

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView *result = [super hitTest:point withEvent:event];
    if (result == self || result == nil)
    {
        [self hideMenu];
        
        return nil;
    }
    
    return result;
}

- (void)showMenuFromRect:(CGRect)rect
{
    [self showMenuFromRect:rect animated:true];
}

- (void)showMenuFromRect:(CGRect)rect animated:(bool)animated
{
    _isShowingMenu = true;
    _showingMenuFromRect = rect;
    [_menuView showInView:self fromRect:rect animated:animated];
}

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

- (void)hideMenu
{
    if (_isShowingMenu)
    {
        _isShowingMenu = false;
        _showingMenuFromRect = CGRectZero;
        
        [_menuView.watcherHandle requestAction:@"menuWillHide" options:nil];
        
        [_menuView hide:^
        {
            [self removeFromSuperview];
        }];
    }
}

@end
