#import "TGPhotoCropAreaView.h"

#import "TGPhotoCropGridView.h"

#import "UIControl+HitTestEdgeInsets.h"

#import "TGPhotoCropControl.h"

const CGSize TGPhotoCropCornerControlSize = { 44, 44 };
const CGFloat TGPhotoCropEdgeControlSize = 44;

@interface TGPhotoCropAreaView ()
{
    bool _isTracking;
    
    UIImageView *_cornersView;
    
    UIView *_topEdgeHighlight;
    UIView *_leftEdgeHighlight;
    UIView *_rightEdgeHighlight;
    UIView *_bottomEdgeHighlight;
    
    TGPhotoCropControl *_topLeftCornerControl;
    TGPhotoCropControl *_topRightCornerControl;
    TGPhotoCropControl *_bottomLeftCornerControl;
    TGPhotoCropControl *_bottomRightCornerControl;
    
    TGPhotoCropControl *_topEdgeControl;
    TGPhotoCropControl *_leftEdgeControl;
    TGPhotoCropControl *_bottomEdgeControl;
    TGPhotoCropControl *_rightEdgeControl;
    
    TGPhotoCropGridView *_majorGridView;
    TGPhotoCropGridView *_minorGridView;
}

@property (nonatomic, copy) bool(^shouldBeginResizing)(TGPhotoCropControl *sender);
@property (nonatomic, copy) void(^didBeginResizing)(TGPhotoCropControl *sender);
@property (nonatomic, copy) void(^didResize)(TGPhotoCropControl *sender, CGPoint translation);
@property (nonatomic, copy) void(^didEndResizing)(TGPhotoCropControl *sender);

@end

@implementation TGPhotoCropAreaView

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self != nil)
    {
        __weak TGPhotoCropAreaView *weakSelf = self;
        
        self.shouldBeginResizing = ^bool(__unused TGPhotoCropControl *sender)
        {
            __strong TGPhotoCropAreaView *strongSelf = weakSelf;
            if (strongSelf != nil)
            {
                if (strongSelf.shouldBeginEditing != nil)
                    return strongSelf.shouldBeginEditing();
            }
            
            return true;
        };
        
        self.didBeginResizing = ^(__unused TGPhotoCropControl *sender)
        {
            __strong TGPhotoCropAreaView *strongSelf = weakSelf;
            if (strongSelf == nil)
                return;

            strongSelf->_isTracking = true;
        
            if (strongSelf.didBeginEditing != nil)
                strongSelf.didBeginEditing();
            
            if (strongSelf->_lockAspectRatio)
                return;
            
            if (sender == strongSelf->_topEdgeControl)
                strongSelf->_topEdgeHighlight.hidden = false;
            else if (sender == strongSelf->_leftEdgeControl)
                strongSelf->_leftEdgeHighlight.hidden = false;
            else if (sender == strongSelf->_bottomEdgeControl)
                strongSelf->_bottomEdgeHighlight.hidden = false;
            else if (sender == strongSelf->_rightEdgeControl)
                strongSelf->_rightEdgeHighlight.hidden = false;
        };
        
        self.didResize = ^(TGPhotoCropControl *sender, CGPoint translation)
        {
            __strong TGPhotoCropAreaView *strongSelf = weakSelf;
            if (strongSelf == nil)
                return;
            
            [strongSelf handleResizeWithSender:sender translation:translation];
            
            if (strongSelf.areaChanged != nil)
                strongSelf.areaChanged();
        };
        
        self.didEndResizing = ^(TGPhotoCropControl *sender)
        {
            __strong TGPhotoCropAreaView *strongSelf = weakSelf;
            if (strongSelf == nil)
                return;
            
            strongSelf->_isTracking = false;
            
            if (strongSelf.didEndEditing != nil)
                strongSelf.didEndEditing();
            
            if (strongSelf->_lockAspectRatio)
                return;
            
            if (sender == strongSelf->_topEdgeControl)
                strongSelf->_topEdgeHighlight.hidden = true;
            else if (sender == strongSelf->_leftEdgeControl)
                strongSelf->_leftEdgeHighlight.hidden = true;
            else if (sender == strongSelf->_bottomEdgeControl)
                strongSelf->_bottomEdgeHighlight.hidden = true;
            else if (sender == strongSelf->_rightEdgeControl)
                strongSelf->_rightEdgeHighlight.hidden = true;
        };
        
        self.hitTestEdgeInsets = UIEdgeInsetsMake(-16, -16, -16, -16);
        
        _cornersView = [[UIImageView alloc] initWithFrame:CGRectInset(self.bounds, -2, -2)];
        _cornersView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        _cornersView.image = [[UIImage imageNamed:@"PhotoEditorCropCorners"] resizableImageWithCapInsets:UIEdgeInsetsMake(20, 20, 20, 20)];
        [self addSubview:_cornersView];
        
        _topEdgeHighlight = [[UIView alloc] initWithFrame:CGRectMake(0, -1, frame.size.width, 2)];
        _topEdgeHighlight.autoresizingMask = UIViewAutoresizingFlexibleWidth;
        _topEdgeHighlight.backgroundColor = [UIColor whiteColor];
        _topEdgeHighlight.hidden = true;
        [self addSubview:_topEdgeHighlight];
        
        _leftEdgeHighlight = [[UIView alloc] initWithFrame:CGRectMake(-1, 0, 2, frame.size.height)];
        _leftEdgeHighlight.autoresizingMask = UIViewAutoresizingFlexibleHeight;
        _leftEdgeHighlight.backgroundColor = [UIColor whiteColor];
        _leftEdgeHighlight.hidden = true;
        [self addSubview:_leftEdgeHighlight];

        _rightEdgeHighlight = [[UIView alloc] initWithFrame:CGRectMake(frame.size.width - 1, 0, 2, frame.size.height)];
        _rightEdgeHighlight.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
        _rightEdgeHighlight.backgroundColor = [UIColor whiteColor];
        _rightEdgeHighlight.hidden = true;
        [self addSubview:_rightEdgeHighlight];
        
        _bottomEdgeHighlight = [[UIView alloc] initWithFrame:CGRectMake(0, frame.size.height - 1, frame.size.width, 2)];
        _bottomEdgeHighlight.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
        _bottomEdgeHighlight.backgroundColor = [UIColor whiteColor];
        _bottomEdgeHighlight.hidden = true;
        [self addSubview:_bottomEdgeHighlight];
        
        _topEdgeControl = [[TGPhotoCropControl alloc] initWithFrame:CGRectMake(TGPhotoCropCornerControlSize.width / 2,
                                                                               -TGPhotoCropEdgeControlSize / 2,
                                                                               frame.size.width - TGPhotoCropCornerControlSize.width,
                                                                               TGPhotoCropEdgeControlSize)];
        _topEdgeControl.autoresizingMask = UIViewAutoresizingFlexibleWidth;
        _topEdgeControl.hitTestEdgeInsets = UIEdgeInsetsMake(-16, 0, -16, 0);
        [self addSubview:_topEdgeControl];
        
        _leftEdgeControl = [[TGPhotoCropControl alloc] initWithFrame:CGRectMake(-TGPhotoCropEdgeControlSize / 2,
                                                                                TGPhotoCropCornerControlSize.height / 2,
                                                                                TGPhotoCropEdgeControlSize,
                                                                                frame.size.height - TGPhotoCropCornerControlSize.height)];
        _leftEdgeControl.autoresizingMask = UIViewAutoresizingFlexibleHeight;
        _leftEdgeControl.hitTestEdgeInsets = UIEdgeInsetsMake(0, -16, 0, -16);
        [self addSubview:_leftEdgeControl];
        
        _bottomEdgeControl = [[TGPhotoCropControl alloc] initWithFrame:CGRectMake(TGPhotoCropCornerControlSize.width / 2,
                                                                                  frame.size.height - TGPhotoCropEdgeControlSize / 2,
                                                                                  frame.size.width - TGPhotoCropCornerControlSize.width,
                                                                                  TGPhotoCropEdgeControlSize)];
        _bottomEdgeControl.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
        _bottomEdgeControl.hitTestEdgeInsets = UIEdgeInsetsMake(-16, 0, -16, 0);
        [self addSubview:_bottomEdgeControl];
        
        _rightEdgeControl = [[TGPhotoCropControl alloc] initWithFrame:CGRectMake(frame.size.width - TGPhotoCropEdgeControlSize / 2,
                                                                                 TGPhotoCropCornerControlSize.height / 2,
                                                                                 TGPhotoCropEdgeControlSize,
                                                                                 frame.size.height - TGPhotoCropCornerControlSize.height)];
        _rightEdgeControl.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
        _rightEdgeControl.hitTestEdgeInsets = UIEdgeInsetsMake(0, -16, 0, -16);
        [self addSubview:_rightEdgeControl];
        
        _topLeftCornerControl = [[TGPhotoCropControl alloc] initWithFrame:CGRectMake(-TGPhotoCropCornerControlSize.width / 2,
                                                                                     -TGPhotoCropCornerControlSize.height / 2,
                                                                                     TGPhotoCropCornerControlSize.width,
                                                                                     TGPhotoCropCornerControlSize.height)];
        _topLeftCornerControl.hitTestEdgeInsets = UIEdgeInsetsMake(-16, -16, -16, -16);
        [self addSubview:_topLeftCornerControl];
        
        _topRightCornerControl = [[TGPhotoCropControl alloc] initWithFrame:CGRectMake(frame.size.width - TGPhotoCropCornerControlSize.width / 2,
                                                                                      -TGPhotoCropCornerControlSize.height / 2,
                                                                                      TGPhotoCropCornerControlSize.width,
                                                                                      TGPhotoCropCornerControlSize.height)];
        _topRightCornerControl.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
        _topRightCornerControl.hitTestEdgeInsets = UIEdgeInsetsMake(-16, -16, -16, -16);
        [self addSubview:_topRightCornerControl];
        
        _bottomLeftCornerControl = [[TGPhotoCropControl alloc] initWithFrame:CGRectMake(-TGPhotoCropCornerControlSize.width / 2,
                                                                                        frame.size.height - TGPhotoCropCornerControlSize.height / 2,
                                                                                        TGPhotoCropCornerControlSize.width,
                                                                                        TGPhotoCropCornerControlSize.height)];
        _bottomLeftCornerControl.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
        _bottomLeftCornerControl.hitTestEdgeInsets = UIEdgeInsetsMake(-16, -16, -16, -16);
        [self addSubview:_bottomLeftCornerControl];
        
        _bottomRightCornerControl = [[TGPhotoCropControl alloc] initWithFrame:CGRectMake(frame.size.width - TGPhotoCropCornerControlSize.width / 2,
                                                                                         frame.size.height - TGPhotoCropCornerControlSize.height / 2,
                                                                                         TGPhotoCropCornerControlSize.width,
                                                                                         TGPhotoCropCornerControlSize.height)];
        _bottomRightCornerControl.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
        _bottomRightCornerControl.hitTestEdgeInsets = UIEdgeInsetsMake(-16, -16, -16, -16);
        [self addSubview:_bottomRightCornerControl];
        
        for (UIView *view in self.subviews)
        {
            if ([view isKindOfClass:[TGPhotoCropControl class]])
            {
                TGPhotoCropControl *control = (TGPhotoCropControl *)view;
                control.shouldBeginResizing = self.shouldBeginResizing;
                control.didBeginResizing = self.didBeginResizing;
                control.didResize = self.didResize;
                control.didEndResizing = self.didEndResizing;
            }
        }

        _majorGridView = [[TGPhotoCropGridView alloc] initWithMode:TGPhotoCropViewGridModeMajor];
        _majorGridView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        _majorGridView.frame = self.bounds;
        _majorGridView.hidden = true;
        [self addSubview:_majorGridView];
        
        _minorGridView = [[TGPhotoCropGridView alloc] initWithMode:TGPhotoCropViewGridModeMinor];
        _minorGridView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        _minorGridView.frame = self.bounds;
        _minorGridView.hidden = true;
        [self addSubview:_minorGridView];
    }
    return self;
}

- (bool)isTracking
{
    return _isTracking;
}

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)__unused event
{
    UIView *view = [super hitTest:point withEvent:event];
    
    if ([view isKindOfClass:[TGPhotoCropControl class]])
        return view;

    return nil;
}

#pragma mark - Aspect Ratio

- (void)setAspectRatio:(CGFloat)aspectRatio
{
    _aspectRatio = aspectRatio;
}

- (void)setLockAspectRatio:(bool)lockAspectRatio
{
    _lockAspectRatio = lockAspectRatio;
    
    _topEdgeHighlight.hidden = !lockAspectRatio;
    _leftEdgeHighlight.hidden = !lockAspectRatio;
    _rightEdgeHighlight.hidden = !lockAspectRatio;
    _bottomEdgeHighlight.hidden = !lockAspectRatio;
}

#pragma mark - Grid

- (void)setGridMode:(TGPhotoCropViewGridMode)mode
{
    [self setGridMode:mode animated:false];
}

- (void)setGridMode:(TGPhotoCropViewGridMode)gridMode animated:(bool)animated
{
    if (_gridMode == gridMode)
        return;
    
    _gridMode = gridMode;
    
    switch (gridMode)
    {
        case TGPhotoCropViewGridModeMajor:
        {
            [self setGridView:_majorGridView hidden:false animated:animated];
            [self setGridView:_minorGridView hidden:true animated:animated];
        }
            break;
            
        case TGPhotoCropViewGridModeMinor:
        {
            [self setGridView:_majorGridView hidden:true animated:animated];
            [self setGridView:_minorGridView hidden:false animated:animated];
        }
            break;
            
        default:
        {
            [self setGridView:_majorGridView hidden:true animated:animated];
            [self setGridView:_minorGridView hidden:true animated:animated];
        }
            break;
    }
}

- (void)setGridView:(TGPhotoCropGridView *)gridView hidden:(bool)hidden animated:(bool)animated
{
    if (animated)
        [gridView setHidden:hidden animated:true duration:0.2f delay:0.0f];
    else
        gridView.hidden = hidden;
}

#pragma mark - Resize

- (void)handleResizeWithSender:(TGPhotoCropControl *)sender translation:(CGPoint)translation
{
    CGRect rect = self.frame;
    
    if (sender == _topLeftCornerControl)
    {
        rect = CGRectMake(self.frame.origin.x + translation.x,
                          self.frame.origin.y + translation.y,
                          self.frame.size.width - translation.x,
                          self.frame.size.height - translation.y);
        
        if (self.lockAspectRatio)
        {
            CGRect constrainedRect = [self constrainedRectFromRectWithWidth:rect aspectRatio:self.aspectRatio];
            if (ABS(translation.x) < ABS(translation.y))
                constrainedRect = [self constrainedRectFromRectWithHeight:rect aspectRatio:self.aspectRatio];
        
            constrainedRect.origin.x -= constrainedRect.size.width - rect.size.width;
            constrainedRect.origin.y -= constrainedRect.size.height - rect.size.height;
            
            rect = constrainedRect;
        }
    }
    else if (sender == _topRightCornerControl)
    {
        rect = CGRectMake(self.frame.origin.x,
                          self.frame.origin.y + translation.y,
                          self.frame.size.width + translation.x,
                          self.frame.size.height - translation.y);
        
        if (self.lockAspectRatio)
        {
            CGRect constrainedRect = [self constrainedRectFromRectWithWidth:rect aspectRatio:self.aspectRatio];
            if (ABS(translation.x) < ABS(translation.y))
                constrainedRect = [self constrainedRectFromRectWithHeight:rect aspectRatio:self.aspectRatio];
            
            constrainedRect.origin.y -= constrainedRect.size.height - rect.size.height;
            
            rect = constrainedRect;
        }
    }
    else if (sender == _bottomLeftCornerControl)
    {
        rect = CGRectMake(self.frame.origin.x + translation.x,
                          self.frame.origin.y,
                          self.frame.size.width - translation.x,
                          self.frame.size.height + translation.y);
        
        if (self.lockAspectRatio)
        {
            CGRect constrainedRect;
            if (ABS(translation.x) < ABS(translation.y))
                constrainedRect = [self constrainedRectFromRectWithHeight:rect aspectRatio:self.aspectRatio];
            else
                constrainedRect = [self constrainedRectFromRectWithWidth:rect aspectRatio:self.aspectRatio];
            
            constrainedRect.origin.x -= constrainedRect.size.width - rect.size.width;
            
            rect = constrainedRect;
        }
    }
    else if (sender == _bottomRightCornerControl)
    {
        rect = CGRectMake(self.frame.origin.x,
                          self.frame.origin.y,
                          self.frame.size.width + translation.x,
                          self.frame.size.height + translation.y);
        
        if (self.lockAspectRatio)
        {
            if (ABS(translation.x) < ABS(translation.y))
                rect = [self constrainedRectFromRectWithHeight:rect aspectRatio:self.aspectRatio];
            else
                rect = [self constrainedRectFromRectWithWidth:rect aspectRatio:self.aspectRatio];
        }
    }
    else if (sender == _topEdgeControl)
    {
        rect = CGRectMake(self.frame.origin.x,
                          self.frame.origin.y + translation.y,
                          self.frame.size.width,
                          self.frame.size.height - translation.y);
        
        if (self.lockAspectRatio)
            rect = [self constrainedRectFromRectWithHeight:rect aspectRatio:self.aspectRatio];
    }
    else if (sender == _leftEdgeControl)
    {
        rect = CGRectMake(self.frame.origin.x + translation.x,
                          self.frame.origin.y,
                          self.frame.size.width - translation.x,
                          self.frame.size.height);
        
        if (self.lockAspectRatio)
            rect = [self constrainedRectFromRectWithWidth:rect aspectRatio:self.aspectRatio];
    }
    else if (sender == _bottomEdgeControl)
    {
        rect = CGRectMake(self.frame.origin.x,
                          self.frame.origin.y,
                          self.frame.size.width,
                          self.frame.size.height + translation.y);
        
        if (self.lockAspectRatio)
            rect = [self constrainedRectFromRectWithHeight:rect aspectRatio:self.aspectRatio];
    }
    else if (sender == _rightEdgeControl)
    {
        rect = CGRectMake(self.frame.origin.x,
                          self.frame.origin.y,
                          self.frame.size.width + translation.x,
                          self.frame.size.height);
        
        if (self.lockAspectRatio)
            rect = [self constrainedRectFromRectWithWidth:rect aspectRatio:self.aspectRatio];
    }
    
    CGFloat minimumWidth = TGPhotoCropCornerControlSize.width;
    if (rect.size.width < minimumWidth)
        rect.size.width = minimumWidth;
    
    CGFloat minimumHeight = TGPhotoCropCornerControlSize.height;
    if (rect.size.height < minimumHeight)
        rect.size.height = minimumHeight;
    
    if (self.lockAspectRatio)
    {
        CGRect constrainedRect = rect;
        
        if (self.aspectRatio > 1)
        {
            if (rect.size.width <= minimumWidth)
            {
                constrainedRect.size.width = minimumWidth;
                constrainedRect.size.height = constrainedRect.size.width * self.aspectRatio;
            }
        }
        else
        {
            if (rect.size.height <= minimumHeight)
            {
                constrainedRect.size.height = minimumHeight;
                constrainedRect.size.width = constrainedRect.size.height / self.aspectRatio;
            }
        }

        rect = constrainedRect;
    }
    
    self.frame = rect;
}

- (CGRect)constrainedRectFromRectWithWidth:(CGRect)rect aspectRatio:(CGFloat)aspectRatio
{
    CGFloat width = rect.size.width;
    CGFloat height = width * aspectRatio;

    rect.size = CGSizeMake(width, height);
    
    return rect;
}

- (CGRect)constrainedRectFromRectWithHeight:(CGRect)rect aspectRatio:(CGFloat)aspectRatio
{
    CGFloat height = rect.size.height;
    CGFloat width = height / aspectRatio;

    rect.size = CGSizeMake(width, height);
    
    return rect;
}

@end
