#import "TGPhotoStickersView.h"

#import "TGAppDelegate.h"

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

#import "TGDocumentMediaAttachment.h"
#import "TGStickersSignals.h"
#import "TGMaskStickersSignals.h"

#import "TGModernButton.h"
#import "TGStickerKeyboardTabPanel.h"

#import "TGPhotoStickersCollectionView.h"
#import "TGPhotoStickersCollectionLayout.h"
#import "TGPhotoStickersSectionHeader.h"
#import "TGPhotoStickersSectionHeaderView.h"
#import "TGStickerCollectionViewCell.h"

#import "TGItemPreviewController.h"
#import "TGStickerItemPreviewView.h"

#import "TGRecentMaskStickersSignal.h"

const CGFloat TGPhotoStickersPreloadInset = 160.0f;
const CGFloat TGPhotoStickersViewMargin = 19.0f;

typedef enum {
    TGPhotoStickersViewSectionMasks = 0,
    TGPhotoStickersViewSectionGeneric = 1
} TGPhotoStickersViewSection;

@interface TGPhotoStickersView () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UIGestureRecognizerDelegate>
{
    id<SDisposable> _stickerPacksDisposable;
    
    TGPhotoStickersViewSection _section;
    
    NSArray *_genericStickerPacks;
    NSArray *_maskStickerPacks;
    NSArray *_recentDocumentsOriginal;
    NSArray *_recentDocumentsSorted;
    NSArray *_recentStickers;
    NSArray *_recentMasks;
    NSDictionary *_packReferenceToPack;
    
    bool _ignoreSetSection;
    
    UIView *_dimView;
    UIView *_blurView;
    UIImageView *_backgroundView;
    
    UIView *_wrapperView;
    UISegmentedControl *_segmentedControl;
    TGModernButton *_cancelButton;
    
    TGStickerKeyboardTabPanel *_tabPanel;
    UIView *_separatorView;
    
    UIView *_collectionWrapperView;
    TGPhotoStickersCollectionView *_collectionView;
    UICollectionViewFlowLayout *_collectionLayout;
    UIView *_headersView;
    
    UIPanGestureRecognizer *_panRecognizer;
    
    CGFloat _masksContentOffset;
    CGFloat _stickersContentOffset;
    
    __weak TGItemPreviewController *_previewController;
}
@end

@implementation TGPhotoStickersView

@synthesize interfaceOrientation = _interfaceOrientation;

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self != nil)
    {
        _masksContentOffset = FLT_MAX;
        _stickersContentOffset = FLT_MAX;
        
        bool compact = TGAppDelegateInstance.rootController.currentSizeClass == UIUserInterfaceSizeClassCompact;
        if (compact)
        {
            if (iosMajorVersion() >= 8)
            {
                _blurView = [[UIVisualEffectView alloc] initWithEffect:nil];
            }
            else
            {
                _blurView = [[UIToolbar alloc] init];
                _blurView.alpha = 0.0f;
                ((UIToolbar *)_blurView).barStyle = UIBarStyleBlackTranslucent;
            }
            [self addSubview:_blurView];
        }
        else
        {
            _interfaceOrientation = UIInterfaceOrientationPortrait;
            
            _backgroundView = [[UIImageView alloc] init];
            _backgroundView.alpha = 0.98f;
            _backgroundView.image = [TGTintedImage([UIImage imageNamed:@"PaintPopupCenterBackground"], UIColorRGB(0xf7f7f7)) resizableImageWithCapInsets:UIEdgeInsetsMake(32.0f, 32.0f, 32.0f, 32.0f)];
            [self addSubview:_backgroundView];
        }
        
        _wrapperView = [[UIView alloc] initWithFrame:self.bounds];
        _wrapperView.clipsToBounds = true;
        [self addSubview:_wrapperView];
        
        _segmentedControl = [[UISegmentedControl alloc] initWithFrame:CGRectMake(0, 0, 0, 29.0f)];
        
        TGStickerKeyboardViewStyle stickersStyle = TGStickerKeyboardViewPaintStyle;
        if (compact)
        {
            _wrapperView.alpha = 0.0f;
            _wrapperView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
            
            stickersStyle = TGStickerKeyboardViewPaintDarkStyle;
            
            _cancelButton = [[TGModernButton alloc] init];
            _cancelButton.exclusiveTouch = true;
            _cancelButton.titleLabel.font = TGSystemFontOfSize(17.0f);
            [_cancelButton setTitle:TGLocalized(@"Common.Cancel") forState:UIControlStateNormal];
            [_cancelButton setTitleColor:UIColorRGB(0xafb2b1)];
            [_cancelButton addTarget:self action:@selector(cancelButtonPressed) forControlEvents:UIControlEventTouchUpInside];
            [_cancelButton sizeToFit];
            [_wrapperView addSubview:_cancelButton];
            
            [_segmentedControl setBackgroundImage:TGTintedImage([UIImage imageNamed:@"ModernSegmentedControlBackground.png"], UIColorRGB(0xafb2b1)) forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
            [_segmentedControl setBackgroundImage:TGTintedImage([UIImage imageNamed:@"ModernSegmentedControlSelected.png"], UIColorRGB(0xafb2b1)) forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
            [_segmentedControl setBackgroundImage:TGTintedImage([UIImage imageNamed:@"ModernSegmentedControlSelected.png"], UIColorRGB(0xafb2b1)) forState:UIControlStateSelected | UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
            [_segmentedControl setBackgroundImage:[UIImage imageNamed:@"PaintSegmentedControlHighlighted.png"] forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
            [_segmentedControl setDividerImage:TGTintedImage([UIImage imageNamed:@"ModernSegmentedControlDivider.png"], UIColorRGB(0xafb2b1)) forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
            [_segmentedControl setTitleTextAttributes:@{UITextAttributeTextColor: UIColorRGB(0xafb2b1), UITextAttributeTextShadowColor: [UIColor clearColor], UITextAttributeFont: TGSystemFontOfSize(13)} forState:UIControlStateNormal];
            [_segmentedControl setTitleTextAttributes:@{UITextAttributeTextColor: [UIColor blackColor], UITextAttributeTextShadowColor: [UIColor clearColor], UITextAttributeFont: TGSystemFontOfSize(13)} forState:UIControlStateSelected];
        }
        else
        {
            [_segmentedControl setBackgroundImage:[UIImage imageNamed:@"ModernSegmentedControlBackground.png"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
            [_segmentedControl setBackgroundImage:[UIImage imageNamed:@"ModernSegmentedControlSelected.png"] forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
            [_segmentedControl setBackgroundImage:[UIImage imageNamed:@"ModernSegmentedControlSelected.png"] forState:UIControlStateSelected | UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
            [_segmentedControl setBackgroundImage:[UIImage imageNamed:@"ModernSegmentedControlHighlighted.png"] forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
            [_segmentedControl setDividerImage:[UIImage imageNamed:@"ModernSegmentedControlDivider.png"] forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
            [_segmentedControl setTitleTextAttributes:@{UITextAttributeTextColor: TGAccentColor(), UITextAttributeTextShadowColor: [UIColor clearColor], UITextAttributeFont: TGSystemFontOfSize(13)} forState:UIControlStateNormal];
            [_segmentedControl setTitleTextAttributes:@{UITextAttributeTextColor: [UIColor whiteColor], UITextAttributeTextShadowColor: [UIColor clearColor], UITextAttributeFont: TGSystemFontOfSize(13)} forState:UIControlStateSelected];
        }
        
        [_segmentedControl insertSegmentWithTitle:TGLocalized(@"Paint.Masks") atIndex:0 animated:false];
        [_segmentedControl insertSegmentWithTitle:TGLocalized(@"Paint.Stickers") atIndex:1 animated:false];
        [_segmentedControl setSelectedSegmentIndex:0];
        [_segmentedControl addTarget:self action:@selector(segmentedControlChanged) forControlEvents:UIControlEventValueChanged];
        [_wrapperView addSubview:_segmentedControl];
        
        __weak TGPhotoStickersView *weakSelf = self;
        _tabPanel = [[TGStickerKeyboardTabPanel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, frame.size.width, 45.0f) style:stickersStyle];
        _tabPanel.currentStickerPackIndexChanged = ^(NSUInteger index)
        {
            __strong TGPhotoStickersView *strongSelf = weakSelf;
            if (strongSelf != nil)
                [strongSelf scrollToSection:index];
        };
        [_wrapperView addSubview:_tabPanel];
        
        CGFloat thickness = TGIsRetina() ? 0.5f : 1.0f;
        _separatorView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, thickness)];
        _separatorView.backgroundColor = UIColorRGB(0xafb2b1);
        //[_wrapperView addSubview:_separatorView];
        
        _collectionWrapperView = [[UIView alloc] init];
        _collectionWrapperView.clipsToBounds = true;
        [_wrapperView addSubview:_collectionWrapperView];
        
        _collectionLayout = [[TGPhotoStickersCollectionLayout alloc] init];
        _collectionView = [[TGPhotoStickersCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:_collectionLayout];
        _collectionView.delegate = self;
        _collectionView.dataSource = self;
        _collectionView.backgroundColor = [UIColor clearColor];
        _collectionView.opaque = false;
        _collectionView.showsHorizontalScrollIndicator = false;
        _collectionView.showsVerticalScrollIndicator = false;
        _collectionView.alwaysBounceVertical = true;
        _collectionView.delaysContentTouches = false;
        _collectionView.contentInset = UIEdgeInsetsMake(TGPhotoStickersPreloadInset - TGPhotoStickersSectionHeaderHeight, 0.0f, TGPhotoStickersPreloadInset, 0.0f);
        [_collectionView registerClass:[TGStickerCollectionViewCell class] forCellWithReuseIdentifier:@"TGStickerCollectionViewCell"];
        if (!compact)
            _collectionView.headerTextColor = UIColorRGB(0x787878);
        [_collectionWrapperView addSubview:_collectionView];
        
        _headersView = [[UIView alloc] init];
        _headersView.userInteractionEnabled = false;
        [_wrapperView addSubview:_headersView];
        _collectionView.headersParentView = _headersView;
        
        UILongPressGestureRecognizer *tapRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleStickerPress:)];
        tapRecognizer.minimumPressDuration = 0.25;
        [_collectionView addGestureRecognizer:tapRecognizer];
        
        _panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleStickerPan:)];
        _panRecognizer.delegate = self;
        _panRecognizer.cancelsTouchesInView = false;
        [_collectionView addGestureRecognizer:_panRecognizer];

        _stickerPacksDisposable = [[[SSignal combineSignals:@[[TGMaskStickersSignals stickerPacks], [TGStickersSignals stickerPacks], [TGRecentMaskStickersSignal recentStickers]]] deliverOn:[SQueue mainQueue]] startWithNext:^(NSArray *masksAndStickers)
        {
            NSDictionary *masks = masksAndStickers[0];
            NSDictionary *stickers = masksAndStickers[1];
            NSArray *recentStickers = masksAndStickers[2];
            
            NSMutableArray *filteredPacks = [[NSMutableArray alloc] init];
            for (TGStickerPack *pack in stickers[@"packs"])
            {
                if ([pack.packReference isKindOfClass:[TGStickerPackIdReference class]] && !pack.hidden)
                    [filteredPacks addObject:pack];
            }
            
            NSMutableArray *filteredMaskPacks = [[NSMutableArray alloc] init];
            for (TGStickerPack *pack in masks[@"packs"])
            {
                if ([pack.packReference isKindOfClass:[TGStickerPackIdReference class]] && !pack.hidden)
                    [filteredMaskPacks addObject:pack];
            }
            
            NSArray *sortedStickerPacks = filteredPacks;
            NSArray *sortedMaskStickerPacks = filteredMaskPacks;
            
            NSMutableArray *reversed = [[NSMutableArray alloc] init];
            for (id item in sortedStickerPacks)
            {
                [reversed addObject:item];
            }
            
            NSMutableArray *reversedMasks = [[NSMutableArray alloc] init];
            for (id item in sortedMaskStickerPacks)
            {
                [reversedMasks addObject:item];
            }
            
            __strong TGPhotoStickersView *strongSelf = weakSelf;
            if (strongSelf != nil) {
                if (![strongSelf->_genericStickerPacks isEqual:reversed] || ![strongSelf->_maskStickerPacks isEqual:reversedMasks]) {
                    [strongSelf setStickerPacks:reversed maskStickerPacks:reversedMasks recentDocuments:recentStickers];
                }
                
                [self updateCurrentSection];
            }
        }];
    }
    return self;
}

- (CGSize)sizeThatFits:(CGSize)__unused size
{
    return CGSizeMake(375.0f + TGPhotoStickersViewMargin * 2.0f, 568.0f + TGPhotoStickersViewMargin * 2.0f);
}

- (void)setSeparatorHidden:(bool)hidden animated:(bool)animated
{
    if ((hidden && _separatorView.alpha < 1.0f - FLT_EPSILON) || (!hidden && _separatorView.alpha > FLT_EPSILON))
        return;
    
    if (animated)
    {
        [UIView animateWithDuration:0.2 animations:^
        {
            _separatorView.alpha = hidden ? 0.0f : 1.0f;
        }];
    }
    else
    {
        _separatorView.alpha = hidden ? 0.0f : 1.0f;
    }
}

#pragma mark - 

- (void)handleStickerPress:(UILongPressGestureRecognizer *)recognizer
{
    if (recognizer.state == UIGestureRecognizerStateBegan)
    {
        CGPoint point = [recognizer locationInView:_collectionView];
        
        for (NSIndexPath *indexPath in [_collectionView indexPathsForVisibleItems])
        {
            TGStickerCollectionViewCell *cell = (TGStickerCollectionViewCell *)[_collectionView cellForItemAtIndexPath:indexPath];
            if (CGRectContainsPoint(cell.frame, point))
            {
                TGViewController *parentViewController = _parentViewController;
                if (parentViewController != nil)
                {
                    TGStickerItemPreviewView *previewView = [[TGStickerItemPreviewView alloc] initWithFrame:CGRectZero];
                    if ((NSInteger)TGScreenSize().height == 736)
                        previewView.eccentric = false;
                    
                    TGItemPreviewController *controller = [[TGItemPreviewController alloc] initWithParentController:parentViewController previewView:previewView];
                    _previewController = controller;
                    
                    __weak TGPhotoStickersView *weakSelf = self;
                    controller.sourcePointForItem = ^(id item)
                    {
                        __strong TGPhotoStickersView *strongSelf = weakSelf;
                        if (strongSelf == nil)
                            return CGPointZero;
                        
                        for (TGStickerCollectionViewCell *cell in strongSelf->_collectionView.visibleCells)
                        {
                            if ([cell.documentMedia isEqual:item])
                            {
                                NSIndexPath *indexPath = [strongSelf->_collectionView indexPathForCell:cell];
                                if (indexPath != nil)
                                    return [strongSelf->_collectionView convertPoint:cell.center toView:nil];
                            }
                        }
                        
                        return CGPointZero;
                    };
                    
                    TGDocumentMediaAttachment *sticker = [self documentAtIndexPath:indexPath];
                    TGStickerPack *stickerPack = [self stickerPackAtIndexPath:indexPath];
                    NSArray *associations = _section == TGPhotoStickersViewSectionGeneric ? stickerPack.stickerAssociations : nil;
                    [previewView setSticker:sticker associations:associations];
                    
                    [cell setHighlightedWithBounce:true];
                }
                
                break;
            }
        }
    }
    else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled)
    {
        TGItemPreviewController *controller = _previewController;
        [controller dismiss];
        
        for (TGStickerCollectionViewCell *cell in [_collectionView visibleCells])
            [cell setHighlightedWithBounce:false];
    }
}

- (void)handleStickerPan:(UIPanGestureRecognizer *)gestureRecognizer
{
    if (_previewController != nil && gestureRecognizer.state == UIGestureRecognizerStateChanged)
    {
        TGStickerItemPreviewView *previewView = (TGStickerItemPreviewView *)_previewController.previewView;
        
        CGPoint point = [gestureRecognizer locationInView:_collectionView];
        CGPoint relativePoint = [gestureRecognizer locationInView:self];
        
        if (CGRectContainsPoint(CGRectOffset(_collectionView.frame, 0, TGPhotoStickersPreloadInset), relativePoint))
        {
            for (NSIndexPath *indexPath in [_collectionView indexPathsForVisibleItems])
            {
                TGStickerCollectionViewCell *cell = (TGStickerCollectionViewCell *)[_collectionView cellForItemAtIndexPath:indexPath];
                if (CGRectContainsPoint(cell.frame, point))
                {
                    TGDocumentMediaAttachment *document = [self documentAtIndexPath:indexPath];
                    TGStickerPack *stickerPack = [self stickerPackAtIndexPath:indexPath];
                    NSArray *associations = _section == TGPhotoStickersViewSectionGeneric ? stickerPack.stickerAssociations : nil;
                    if (document != nil)
                        [previewView setSticker:document associations:associations];
                    [cell setHighlightedWithBounce:true];
                }
                else
                {
                    [cell setHighlightedWithBounce:false];
                }
            }
        }
    }
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    if (gestureRecognizer == _panRecognizer || otherGestureRecognizer == _panRecognizer)
        return true;
    
    return false;
}

#pragma mark - 

- (void)setStickerPacks:(NSArray *)stickerPacks maskStickerPacks:(NSArray *)maskStickerPacks recentDocuments:(NSArray *)recentDocuments
{
    _genericStickerPacks = stickerPacks;
    _maskStickerPacks = maskStickerPacks;
    
    _recentDocumentsSorted = recentDocuments;
    _recentDocumentsOriginal = recentDocuments;
    
    [self updateRecentDocuments];
    
    [_collectionView reloadData];
    
    [_tabPanel setStickerPacks:_section == TGPhotoStickersViewSectionMasks ? _maskStickerPacks : _genericStickerPacks showRecent:_section == TGPhotoStickersViewSectionMasks ? (_recentStickers.count != 0) : (_recentMasks.count != 0) showGifs:false showTrendingFirst:false showTrendingLast:false];
}

- (void)updateRecentDocuments
{
    NSMutableArray *recentStickers = [[NSMutableArray alloc] init];
    NSMutableArray *recentMasks = [[NSMutableArray alloc] init];
    NSMutableDictionary *packReferenceToPack = [[NSMutableDictionary alloc] init];
    
    for (TGStickerPack *pack in _genericStickerPacks) {
        if (pack.packReference != nil) {
            packReferenceToPack[pack.packReference] = pack;
        }
    }
    
    for (TGStickerPack *pack in _maskStickerPacks) {
        if (pack.packReference != nil) {
            packReferenceToPack[pack.packReference] = pack;
        }
    }
    
    for (TGDocumentMediaAttachment *document in _recentDocumentsSorted) {
        for (id attribute in document.attributes) {
            if ([attribute isKindOfClass:[TGDocumentAttributeSticker class]]) {
                if (((TGDocumentAttributeSticker *)attribute).packReference != nil) {
                    TGStickerPack *pack = packReferenceToPack[((TGDocumentAttributeSticker *)attribute).packReference];
                    if (pack != nil) {
                        if (pack.isMask) {
                            [recentMasks addObject:document];
                        } else {
                            [recentStickers addObject:document];
                        }
                    }
                }
                break;
            }
        }
    }
    
    if (recentStickers.count > 20) {
        [recentStickers removeObjectsInRange:NSMakeRange(20, recentStickers.count - 20)];
    }
    
    if (recentMasks.count > 20) {
        [recentMasks removeObjectsInRange:NSMakeRange(20, recentMasks.count - 20)];
    }
    
    _recentStickers = recentStickers;
    _recentMasks = recentMasks;
    _packReferenceToPack = packReferenceToPack;
}

#pragma mark -

- (void)cancelButtonPressed
{
    [self dismissWithCompletion:nil];
}

- (void)scrollToSection:(NSUInteger)section
{
    _ignoreSetSection = false;
    
    [_tabPanel setCurrentStickerPackIndex:section animated:false];
    
    NSArray *recentDocuments = _section == TGPhotoStickersViewSectionMasks ? _recentMasks : _recentStickers;
    NSArray *stickerPacks = _section == TGPhotoStickersViewSectionMasks ? _maskStickerPacks : _genericStickerPacks;
    
    if (section == 0)
    {
        if (recentDocuments.count != 0)
        {
            _ignoreSetSection = true;
            [_collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0] atScrollPosition:UICollectionViewScrollPositionTop animated:true];
        }
        else
        {
            _ignoreSetSection = true;
            [_collectionView setContentOffset:CGPointMake(0.0f, -_collectionView.contentInset.top) animated:true];
        }
    }
    else
    {
        if (section == 1 && recentDocuments.count == 0) {
            _ignoreSetSection = true;
            [_collectionView setContentOffset:CGPointMake(0.0f, -_collectionView.contentInset.top) animated:true];
        } else if (((TGStickerPack *)stickerPacks[section - 1]).documents.count != 0) {
            UICollectionViewLayoutAttributes *attributes = [_collectionView layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
            
            CGFloat verticalOffset = attributes.frame.origin.y - [self collectionView:_collectionView layout:_collectionLayout minimumLineSpacingForSectionAtIndex:section];
            CGFloat effectiveInset = 0.0f;
            if (verticalOffset < _collectionView.contentOffset.y)
                effectiveInset = _collectionView.contentInset.top + TGPhotoStickersSectionHeaderHeight;
            else
                effectiveInset = TGPhotoStickersPreloadInset;
            
            effectiveInset -= 8.0f;
            
            CGFloat contentOffset = verticalOffset - effectiveInset;
            if (contentOffset > _collectionView.contentSize.height - _collectionView.frame.size.height + _collectionView.contentInset.bottom) {
                contentOffset = _collectionView.contentSize.height - _collectionView.frame.size.height + _collectionView.contentInset.bottom;
            }
            
            _ignoreSetSection = true;
            [_collectionView setContentOffset:CGPointMake(0.0f, contentOffset) animated:true];
        }
    }
}

- (void)updateCurrentSection
{
    NSArray *layoutAttributes = [_collectionLayout layoutAttributesForElementsInRect:CGRectMake(0.0f, _collectionView.contentOffset.y - 45.0f + TGPhotoStickersPreloadInset + 7.0f, _collectionView.frame.size.width, _collectionView.frame.size.height - 45.0f - TGPhotoStickersPreloadInset - 7.0f)];
    NSInteger minSection = INT_MAX;
    for (UICollectionViewLayoutAttributes *attributes in layoutAttributes)
    {
        minSection = MIN(attributes.indexPath.section, minSection);
    }
    if (minSection != INT_MAX)
        [_tabPanel setCurrentStickerPackIndex:minSection animated:true];
}

#pragma mark -

- (void)present
{
    self.userInteractionEnabled = true;
    
    if (TGAppDelegateInstance.rootController.currentSizeClass == UIUserInterfaceSizeClassCompact)
    {
        void (^changeBlock)(void) = ^
        {
            if (iosMajorVersion() >= 8)
                ((UIVisualEffectView *)_blurView).effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
            else
                _blurView.alpha = 1.0f;
            _wrapperView.alpha = 1.0f;
        };
        
        [UIView animateWithDuration:0.22 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:changeBlock completion:nil];
    }
    else
    {
        self.alpha = 0.0f;
        
        self.layer.rasterizationScale = TGScreenScaling();
        self.layer.shouldRasterize = true;
        
        [UIView animateWithDuration:0.2 animations:^
        {
            self.alpha = 1.0f;
        } completion:^(__unused BOOL finished)
        {
            self.layer.shouldRasterize = false;
        }];
    }
}

- (void)dismissWithCompletion:(void (^)(void))completion
{
    self.userInteractionEnabled = false;
    
    if (TGAppDelegateInstance.rootController.currentSizeClass == UIUserInterfaceSizeClassCompact)
    {
        void (^changeBlock)(void) = ^
        {
            if (iosMajorVersion() >= 8)
                ((UIVisualEffectView *)_blurView).effect = nil;
            else
                _blurView.alpha = 0.0f;
            _wrapperView.alpha = 0.0f;
        };
        
        [UIView animateWithDuration:0.22 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:changeBlock completion:^(__unused BOOL finished)
        {
            if (self.dismissed != nil)
                self.dismissed();
            
            if (completion != nil)
                completion();
        }];
    }
    else
    {
        self.layer.rasterizationScale = TGScreenScaling();
        self.layer.shouldRasterize = true;
        
        [UIView animateWithDuration:0.2 animations:^
        {
            self.alpha = 0.0f;
        } completion:^(__unused BOOL finished)
        {
            if (self.dismissed != nil)
                self.dismissed();
            
            if (completion != nil)
                completion();
        }];
    }
}

- (void)dismissWithSnapshotView:(UIView *)outSnapshotview startPoint:(CGPoint)startPoint targetFrame:(CGRect)targetFrame targetRotation:(CGFloat)targetRotation completion:(void (^)(void))completion
{
    [self dismissWithCompletion:^
    {
        for (UICollectionViewCell *cell in _collectionView.visibleCells)
            cell.hidden = false;
    }];
    
    [self.outerView addSubview:outSnapshotview];
    outSnapshotview.center = startPoint;
    
    UIView *inSnapshotView = [outSnapshotview snapshotViewAfterScreenUpdates:false];
    inSnapshotView.center = [self.outerView convertPoint:startPoint toView:self.targetView];
    [self.targetView addSubview:inSnapshotView];
    
    CGAffineTransform inTransform = CGAffineTransformInvert(self.targetView.transform);
    inTransform = CGAffineTransformConcat(inTransform, CGAffineTransformInvert(self.targetView.superview.transform));
    inSnapshotView.transform = inTransform;
    
    CGFloat targetScale = targetFrame.size.width / outSnapshotview.frame.size.width * 0.985f;
    CGAffineTransform targetTransform = CGAffineTransformScale(outSnapshotview.transform, targetScale, targetScale);
    targetTransform = CGAffineTransformRotate(targetTransform, targetRotation);
    
    CGAffineTransform middleTransform = CGAffineTransformScale(targetTransform, 1.17f, 1.17f);
    
    [UIView animateWithDuration:0.35 delay:0.0f options:UIViewAnimationOptionCurveEaseInOut animations:^
    {
        CGPoint targetPoint = TGPaintCenterOfRect(targetFrame);
        outSnapshotview.center = targetPoint;
        inSnapshotView.center = [self.outerView convertPoint:targetPoint toView:self.targetView];
    } completion:nil];
    
    [UIView animateWithDuration:0.2 animations:^
    {
        outSnapshotview.transform = middleTransform;
        inSnapshotView.transform = CGAffineTransformConcat(middleTransform, inTransform);
    } completion:^(__unused BOOL finished)
    {
        [UIView animateWithDuration:0.15 delay:0.0f options:UIViewAnimationOptionCurveEaseOut animations:^
        {
            outSnapshotview.transform = targetTransform;
            inSnapshotView.transform = CGAffineTransformConcat(targetTransform, inTransform);
            outSnapshotview.alpha = 0.0f;
        } completion:^(__unused BOOL finished)
        {
            [outSnapshotview removeFromSuperview];
            [inSnapshotView removeFromSuperview];
            
            if (completion != nil)
                completion();
        }];
    }];
}
#pragma mark - 

- (TGStickerPack *)stickerPackAtIndexPath:(NSIndexPath *)indexPath
{
    if (_section == TGPhotoStickersViewSectionMasks) {
        if (indexPath.section == 0)
        {
            TGDocumentMediaAttachment *document = [self documentAtIndexPath:indexPath];
            id<TGStickerPackReference> packReference = document.stickerPackReference;
            if (packReference != nil) {
                return _packReferenceToPack[packReference];
            }
        }
        else
        {
            return _maskStickerPacks[indexPath.section - 1];
        }
    } else {
        if (indexPath.section == 0)
        {
            TGDocumentMediaAttachment *document = [self documentAtIndexPath:indexPath];
            id<TGStickerPackReference> packReference = document.stickerPackReference;
            if (packReference != nil) {
                return _packReferenceToPack[packReference];
            }
        }
        else
        {
            return _genericStickerPacks[indexPath.section - 1];
        }
    }
    return nil;
}

- (TGDocumentMediaAttachment *)documentAtIndexPath:(NSIndexPath *)indexPath
{
    if (_section == TGPhotoStickersViewSectionMasks) {
        if (indexPath.section == 0)
            return _recentMasks[indexPath.item];
        else
            return ((TGStickerPack *)_maskStickerPacks[indexPath.section - 1]).documents[indexPath.item];
    } else {
        if (indexPath.section == 0)
            return _recentStickers[indexPath.item];
        else
            return ((TGStickerPack *)_genericStickerPacks[indexPath.section - 1]).documents[indexPath.item];
    }
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    TGStickerCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TGStickerCollectionViewCell" forIndexPath:indexPath];
    [cell setDocumentMedia:[self documentAtIndexPath:indexPath]];
    
    return cell;
}

- (void)collectionView:(UICollectionView *)__unused collectionView setupSectionHeaderView:(TGPhotoStickersSectionHeaderView *)sectionHeaderView forSectionHeader:(TGPhotoStickersSectionHeader *)sectionHeader
{
    NSString *title = TGLocalized(@"Paint.RecentStickers");
    
    if (sectionHeader.index > 0)
    {
        if (_section == TGPhotoStickersViewSectionMasks) {
            TGStickerPack *stickerPack = _maskStickerPacks[sectionHeader.index - 1];
            title = stickerPack.title;
        } else {
            TGStickerPack *stickerPack = _genericStickerPacks[sectionHeader.index - 1];
            title = stickerPack.title;
        }
    }
    
    [sectionHeaderView setTitle:title];
}

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)__unused collectionView
{
    if (_section == TGPhotoStickersViewSectionMasks) {
        return 1 + _maskStickerPacks.count;
    } else {
        return 1 + _genericStickerPacks.count;
    }
}

- (NSInteger)collectionView:(UICollectionView *)__unused collectionView numberOfItemsInSection:(NSInteger)section
{
    if (_section == TGPhotoStickersViewSectionMasks) {
        if (section == 0) {
            return (NSInteger)_recentMasks.count;
        } else {
            return ((TGStickerPack *)_maskStickerPacks[section - 1]).documents.count;
        }
    } else {
        if (section == 0) {
            return (NSInteger)_recentStickers.count;
        } else {
            return ((TGStickerPack *)_genericStickerPacks[section - 1]).documents.count;
        }
    }
}

- (CGSize)collectionView:(UICollectionView *)__unused collectionView layout:(UICollectionViewLayout*)__unused collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)__unused indexPath
{
    return CGSizeMake(62.0f, 62.0f);
}

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)__unused collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    CGFloat sideInset = (collectionView.frame.size.width < 330.0f) ? 3.0f : 15.0f;
    CGFloat bottomInset = (section == [self numberOfSectionsInCollectionView:collectionView] - 1) ? 14.0f : 0.0f;

    NSArray *recent = (_section == TGPhotoStickersViewSectionMasks) ? _recentMasks : _recentStickers;
    if (section == 0 && recent.count == 0)
        return UIEdgeInsetsMake(0, 0, 0, 0);
    
    return UIEdgeInsetsMake(TGPhotoStickersSectionHeaderHeight, sideInset, bottomInset, sideInset);
}

- (CGFloat)collectionView:(UICollectionView *)__unused collectionView layout:(UICollectionViewLayout*)__unused collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)__unused section
{
    return 7.0f;
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)__unused collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)__unused section
{
    return (collectionView.frame.size.width < 330.0f) ? 0.0f : 4.0f;
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    TGStickerCollectionViewCell *cell = (TGStickerCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath];
    if ([cell isEnabled])
    {
        [cell setDisabledTimeout];
        
        if (_section == TGPhotoStickersViewSectionMasks) {
            TGDocumentMediaAttachment *document = [self documentAtIndexPath:indexPath];
            
            if (self.stickerSelected != nil)
                self.stickerSelected(document, [cell.superview convertPoint:cell.center toView:self.outerView], self, [cell snapshotViewAfterScreenUpdates:false]);
        } else {
            TGDocumentMediaAttachment *document = [self documentAtIndexPath:indexPath];
            if (self.stickerSelected != nil)
                self.stickerSelected(document, [cell.superview convertPoint:cell.center toView:self.outerView], self, [cell snapshotViewAfterScreenUpdates:false]);
        }
        
        cell.hidden = true;
    }
}

#pragma mark - 

- (void)scrollViewDidScroll:(UIScrollView *)__unused scrollView
{
    if (!_ignoreSetSection)
        [self updateCurrentSection];
}

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)__unused scrollView
{
    _ignoreSetSection = false;
    [self updateCurrentSection];
}

- (void)scrollViewWillBeginDragging:(UIScrollView *)__unused scrollView
{
    _ignoreSetSection = false;
    [self updateCurrentSection];
}

#pragma mark -

- (void)layoutSubviews
{
    CGRect bounds = self.bounds;
    bool compact = TGAppDelegateInstance.rootController.currentSizeClass == UIUserInterfaceSizeClassCompact;
    if (compact)
    {
        CGRect previousRect = _blurView.frame;
        _blurView.frame = self.bounds;
        
        if (!CGRectEqualToRect(previousRect, _blurView.frame))
            [_collectionLayout invalidateLayout];
        
        _segmentedControl.frame = CGRectMake(12.0f, 12.0f, self.frame.size.width - 17.0f * 2 - _cancelButton.frame.size.width, _segmentedControl.frame.size.height);
    }
    else
    {
        _wrapperView.frame = CGRectMake(0.0f, 0.0f, self.bounds.size.width, self.bounds.size.height - TGPhotoStickersViewMargin);
        _backgroundView.frame = CGRectMake(TGPhotoStickersViewMargin, TGPhotoStickersViewMargin, self.frame.size.width - TGPhotoStickersViewMargin * 2, self.frame.size.height - TGPhotoStickersViewMargin * 2 + 13.0f);
        
        bounds = CGRectInset(bounds, TGPhotoStickersViewMargin, TGPhotoStickersViewMargin);
        
        _segmentedControl.frame = CGRectMake(bounds.origin.x + 12.0f, bounds.origin.y + 12.0f, bounds.size.width - 24.0f, _segmentedControl.frame.size.height);
    }
    
    if (compact)
    {
        _cancelButton.frame = CGRectMake(bounds.origin.x + bounds.size.width - _cancelButton.frame.size.width - 11.0f, bounds.origin.y + 4.0f, _cancelButton.frame.size.width, 44.0f);
    }
    
    _tabPanel.frame = CGRectMake(bounds.origin.x, bounds.origin.y + 50.0f, bounds.size.width, _tabPanel.frame.size.height);
    
    _collectionWrapperView.frame = CGRectMake(bounds.origin.x, CGRectGetMaxY(_tabPanel.frame) + TGPhotoStickersSectionHeaderHeight - 8.0f, bounds.size.width, bounds.size.height - CGRectGetMaxY(_tabPanel.frame) + bounds.origin.y - TGPhotoStickersSectionHeaderHeight + 8.0f);
    _collectionView.frame = CGRectMake(0.0f, -TGPhotoStickersPreloadInset + 8.0f, _collectionWrapperView.frame.size.width, _collectionWrapperView.frame.size.height + 2 * TGPhotoStickersPreloadInset);
    _headersView.frame = [_collectionWrapperView convertRect:_collectionView.frame toView:_wrapperView];
    
    CGFloat thickness = TGIsRetina() ? 0.5f : 1.0f;
    _separatorView.frame = CGRectMake(bounds.origin.x, bounds.origin.y + 143.0f - thickness, bounds.size.width, thickness);
}

- (void)segmentedControlChanged
{
    int index = (int)_segmentedControl.selectedSegmentIndex;
    TGPhotoStickersViewSection section = (TGPhotoStickersViewSection)index;
    
    if (section == TGPhotoStickersViewSectionMasks)
        _stickersContentOffset = _collectionView.contentOffset.y;
    else
        _masksContentOffset = _collectionView.contentOffset.y;
    
    if (section != _section) {
        _section = section;
        
        [_tabPanel setStickerPacks:_section == TGPhotoStickersViewSectionMasks ? _maskStickerPacks : _genericStickerPacks showRecent:_section == TGPhotoStickersViewSectionMasks ? (_recentMasks.count != 0) : (_recentStickers.count != 0) showGifs:false showTrendingFirst:false showTrendingLast:false];
        [_collectionView reloadData];
        
        [self updateCurrentSection];
        
        CGPoint contentOffset = CGPointMake(0, -_collectionView.contentInset.top);
        if (section == TGPhotoStickersViewSectionMasks && fabs(_masksContentOffset - FLT_MAX) > FLT_EPSILON)
            contentOffset = CGPointMake(0, _masksContentOffset);
        else if (section == TGPhotoStickersViewSectionGeneric && fabs(_stickersContentOffset - FLT_MAX) > FLT_EPSILON)
            contentOffset = CGPointMake(0, _stickersContentOffset);
        [_collectionView setContentOffset:contentOffset];
    }
}

@end
