//==============================================================================
// This file is part of Master Password.
// Copyright (c) 2011-2017, Maarten Billemont.
//
// Master Password is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Master Password is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You can find a copy of the GNU General Public License in the
// LICENSE file.  Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================

#import "MPAvatarCell.h"

const long MPAvatarAdd = 10000;

@interface MPAvatarCell()

@property(strong, nonatomic) IBOutlet UIImageView *avatarImageView;
@property(strong, nonatomic) IBOutlet UILabel *nameLabel;
@property(strong, nonatomic) IBOutlet UIView *nameContainer;
@property(strong, nonatomic) IBOutlet UIImageView *spinner;
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *nameToCenterConstraint;
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *avatarSizeConstraint;
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *avatarToTopConstraint;
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *avatarRaisedConstraint;
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *keyboardHeightConstraint;

@property(nonatomic, strong) CAAnimationGroup *targetedShadowAnimation;

@property(assign, nonatomic, readwrite) BOOL newUser;
@end

@implementation MPAvatarCell

+ (NSString *)reuseIdentifier {

    return NSStringFromClass( self );
}

#pragma mark - Life cycle

- (void)awakeFromNib {

    [super awakeFromNib];

    self.visible = NO;

    self.nameContainer.layer.cornerRadius = 5;

    self.avatarImageView.layer.cornerRadius = self.avatarImageView.bounds.size.height / 2;
    self.avatarImageView.layer.masksToBounds = NO;
    self.avatarImageView.backgroundColor = [UIColor clearColor];

    [self observeKeyPath:@"bounds" withBlock:^(id from, id to, NSKeyValueChange cause, MPAvatarCell *self) {
        self.contentView.frame = self.bounds;
    }];
    [self observeKeyPath:@"selected" withBlock:^(id from, id to, NSKeyValueChange cause, MPAvatarCell *self) {
        [self updateAnimated:self.superview != nil];
    }];
    [self observeKeyPath:@"highlighted" withBlock:^(id from, id to, NSKeyValueChange cause, MPAvatarCell *self) {
        [self updateAnimated:self.superview != nil];
    }];
    PearlAddNotificationObserver( UIKeyboardWillShowNotification, nil, [NSOperationQueue mainQueue],
            ^(MPAvatarCell *self, NSNotification *note) {
                CGRect keyboardRect = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
                CGFloat keyboardHeight = CGRectGetHeight( self.window.screen.bounds ) - CGRectGetMinY( keyboardRect );
                [self.keyboardHeightConstraint updateConstant:keyboardHeight];
            } );

    CABasicAnimation *toShadowOpacityAnimation = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"];
    toShadowOpacityAnimation.toValue = @0.2f;
    toShadowOpacityAnimation.duration = 0.5f;

    CABasicAnimation *pulseShadowOpacityAnimation = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"];
    pulseShadowOpacityAnimation.fromValue = @0.2f;
    pulseShadowOpacityAnimation.toValue = @0.6f;
    pulseShadowOpacityAnimation.beginTime = 0.5f;
    pulseShadowOpacityAnimation.duration = 2.0f;
    pulseShadowOpacityAnimation.autoreverses = YES;
    pulseShadowOpacityAnimation.repeatCount = MAXFLOAT;

    self.targetedShadowAnimation = [CAAnimationGroup new];
    self.targetedShadowAnimation.animations = @[ toShadowOpacityAnimation, pulseShadowOpacityAnimation ];
    self.targetedShadowAnimation.duration = MAXFLOAT;
    self.avatarImageView.layer.shadowColor = [UIColor whiteColor].CGColor;
    self.avatarImageView.layer.shadowOffset = CGSizeZero;
}

- (void)prepareForReuse {

    [super prepareForReuse];

    self.newUser = NO;
    self.visibility = 0;
    self.mode = MPAvatarModeLowered;
    self.spinnerActive = NO;
}

- (void)dealloc {

    [self removeKeyPathObservers];
    PearlRemoveNotificationObservers();
}

#pragma mark - Properties

- (void)setAvatar:(NSUInteger)avatar {

    _avatar = avatar == MPAvatarAdd? MPAvatarAdd: (avatar + MPAvatarCount) % MPAvatarCount;

    if (self.avatar == MPAvatarAdd) {
        self.avatarImageView.image = [UIImage imageNamed:@"avatar-add"];
        self.name = strl( @"New User" );
        self.newUser = YES;
    }
    else
        self.avatarImageView.image = [UIImage imageNamed:strf( @"avatar-%lu", (unsigned long)self.avatar )];
}

- (NSString *)name {

    return self.nameLabel.text;
}

- (void)setName:(NSString *)name {

    self.nameLabel.text = name;
}

- (void)setVisibility:(CGFloat)visibility {

    [self setVisibility:visibility animated:YES];
}

- (void)setVisibility:(CGFloat)visibility animated:(BOOL)animated {

    if (self.visibility == visibility)
        return;
    _visibility = visibility;

    [self updateAnimated:animated];
}

- (void)setHighlighted:(BOOL)highlighted {

    super.highlighted = highlighted;

    self.avatarImageView.transform = highlighted? CGAffineTransformMakeScale( 1.1f, 1.1f ): CGAffineTransformIdentity;
}

- (void)setMode:(MPAvatarMode)mode {

    [self setMode:mode animated:YES];
}

- (void)setMode:(MPAvatarMode)mode animated:(BOOL)animated {

    if (self.mode == mode)
        return;
    _mode = mode;

    [self updateAnimated:animated];
}

- (void)setSpinnerActive:(BOOL)spinnerActive {

    [self setSpinnerActive:spinnerActive animated:YES];
}

- (void)setSpinnerActive:(BOOL)spinnerActive animated:(BOOL)animated {

    if (self.spinnerActive == spinnerActive)
        return;
    _spinnerActive = spinnerActive;

    CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
    rotate.toValue = @(2 * M_PI);
    rotate.duration = 5.0;

    if (spinnerActive) {
        rotate.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
        rotate.fromValue = @0.0;
        rotate.repeatCount = MAXFLOAT;
    }
    else {
        rotate.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
        rotate.repeatCount = 1;
    }

    [self.spinner.layer removeAnimationForKey:@"rotation"];
    [self.spinner.layer addAnimation:rotate forKey:@"rotation"];

    [self updateAnimated:animated];
}

#pragma mark - Private

- (void)updateAnimated:(BOOL)animated {

    [self.contentView layoutIfNeeded];
    [UIView animateWithDuration:animated? 0.2f: 0 animations:^{
        self.avatarImageView.transform = CGAffineTransformIdentity;
    }];
    [UIView animateWithDuration:animated? 0.5f: 0 delay:0
                        options:UIViewAnimationOptionOverrideInheritedDuration | UIViewAnimationOptionBeginFromCurrentState
                     animations:^{
                         self.visible = YES;

                         if (self.newUser) {
                             if (self.mode == MPAvatarModeLowered)
                                 self.avatar = MPAvatarAdd;
                             else if (self.avatar == MPAvatarAdd)
                                 self.avatar = arc4random() % MPAvatarCount;
                         }

                         self.nameContainer.alpha = self.visibility;
                         self.avatarImageView.alpha = self.visibility * 0.7f + 0.3f;
                         self.avatarImageView.layer.shadowRadius = 15 * self.visibility * self.visibility;

                         switch (self.mode) {
                             case MPAvatarModeLowered: {
                                 [self.avatarSizeConstraint updateConstant:
                                         self.avatarImageView.image.size.height * (self.visibility * 0.3f + 0.7f)];
                                 [self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultLow];
                                 [self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow];
                                 [self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultLow];
                                 self.nameContainer.visible = YES;
                                 self.nameContainer.backgroundColor = [UIColor clearColor];
                                 self.avatarImageView.visible = YES;
                                 break;
                             }
                             case MPAvatarModeRaisedButInactive: {
                                 [self.avatarSizeConstraint updateConstant:
                                         self.avatarImageView.image.size.height * (self.visibility * 0.7f + 0.3f)];
                                 [self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultHigh];
                                 [self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow];
                                 [self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultLow];
                                 self.nameContainer.visible = YES;
                                 self.nameContainer.backgroundColor = [UIColor clearColor];
                                 self.avatarImageView.visible = NO;
                                 break;
                             }
                             case MPAvatarModeRaisedAndActive: {
                                 [self.avatarSizeConstraint updateConstant:
                                         self.avatarImageView.image.size.height * (self.visibility * 0.7f + 0.3f)];
                                 [self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultHigh];
                                 [self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow];
                                 [self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultHigh];
                                 self.nameContainer.visible = YES;
                                 self.nameContainer.backgroundColor = [UIColor blackColor];
                                 self.avatarImageView.visible = YES;
                                 break;
                             }
                             case MPAvatarModeRaisedAndHidden: {
                                 [self.avatarSizeConstraint updateConstant:
                                         self.avatarImageView.image.size.height * (self.visibility * 0.7f + 0.3f)];
                                 [self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultHigh];
                                 [self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow];
                                 [self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultHigh];
                                 self.nameContainer.visible = NO;
                                 self.nameContainer.backgroundColor = [UIColor blackColor];
                                 self.avatarImageView.visible = NO;
                                 break;
                             }
                             case MPAvatarModeRaisedAndMinimized: {
                                 [self.avatarSizeConstraint updateConstant:36];
                                 [self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultLow];
                                 [self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultHigh + 2];
                                 [self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultHigh];
                                 self.nameContainer.visible = NO;
                                 self.nameContainer.backgroundColor = [UIColor blackColor];
                                 self.avatarImageView.visible = YES;
                                 break;
                             }
                         }

                         // Avatar minimized.
                         if (self.mode == MPAvatarModeRaisedAndMinimized)
                             [self.avatarImageView.layer removeAnimationForKey:@"targetedShadow"];
                         else if (![self.avatarImageView.layer animationForKey:@"targetedShadow"])
                             [self.avatarImageView.layer addAnimation:self.targetedShadowAnimation forKey:@"targetedShadow"];

                         // Avatar selection and spinner.
                         if (self.mode != MPAvatarModeRaisedAndMinimized && (self.selected || self.highlighted) && !self.spinnerActive)
                             self.avatarImageView.backgroundColor = self.avatarImageView.tintColor;
                         else
                             self.avatarImageView.backgroundColor = [UIColor clearColor];
                         self.avatarImageView.layer.cornerRadius = self.avatarImageView.bounds.size.height / 2;
                         self.spinner.visible = self.spinnerActive;

                         [self.contentView layoutIfNeeded];
                     } completion:nil];
}

@end