/*
 Copyright 2016 OpenMarket Ltd
 Copyright 2017 Vector Creations Ltd
 Copyright 2018 New Vector Ltd
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
 http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

#import "MXKDeviceView.h"

#import "NSBundle+MatrixKit.h"

#import "MXKConstants.h"

#import "MXKSwiftHeader.h"

static NSAttributedString *verticalWhitespace = nil;

@interface MXKDeviceView ()
{
    /**
     The displayed device
     */
    MXDevice *mxDevice;
    
    /**
     The matrix session.
     */
    MXSession *mxSession;
    
    /**
     The current alert
     */
    UIAlertController *currentAlert;
    
    /**
     Current request in progress.
     */
    MXHTTPOperation *mxCurrentOperation;
}
@end

@implementation MXKDeviceView

+ (UINib *)nib
{
    // Check whether a nib file is available
    NSBundle *mainBundle = [NSBundle mxk_bundleForClass:self.class];
    
    NSString *path = [mainBundle pathForResource:NSStringFromClass([self class]) ofType:@"nib"];
    if (path)
    {
        return [UINib nibWithNibName:NSStringFromClass([self class]) bundle:mainBundle];
    }
    return [UINib nibWithNibName:NSStringFromClass([MXKDeviceView class]) bundle:[NSBundle mxk_bundleForClass:[MXKDeviceView class]]];
}

- (void)awakeFromNib
{
    [super awakeFromNib];
    
    // Add tap recognizer to discard the view on bg view tap
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onBgViewTap:)];
    [tap setNumberOfTouchesRequired:1];
    [tap setNumberOfTapsRequired:1];
    [tap setDelegate:self];
    [self.bgView addGestureRecognizer:tap];
    
    // Localize string
    [_cancelButton setTitle:[VectorL10n ok] forState:UIControlStateNormal];
    [_cancelButton setTitle:[VectorL10n ok] forState:UIControlStateHighlighted];
    
    [_renameButton setTitle:[VectorL10n rename] forState:UIControlStateNormal];
    [_renameButton setTitle:[VectorL10n rename] forState:UIControlStateHighlighted];
    
    [_deleteButton setTitle:[VectorL10n delete] forState:UIControlStateNormal];
    [_deleteButton setTitle:[VectorL10n delete] forState:UIControlStateHighlighted];
}

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    // Scroll to the top the text view content
    self.textView.contentOffset = CGPointZero;
}

#pragma mark - Override MXKView

-(void)customizeViewRendering
{
    [super customizeViewRendering];
    
    _defaultTextColor = [UIColor blackColor];
    
    // Add shadow on added view
    _containerView.layer.cornerRadius = 5;
    _containerView.layer.shadowOffset = CGSizeMake(0, 1);
    _containerView.layer.shadowOpacity = 0.5f;
}

#pragma mark -

- (void)removeFromSuperviewDidUpdate:(BOOL)isUpdated
{
    if (currentAlert)
    {
        [currentAlert dismissViewControllerAnimated:NO completion:nil];
        currentAlert = nil;
    }
    
    if (mxCurrentOperation)
    {
        [mxCurrentOperation cancel];
        mxCurrentOperation = nil;
    }
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(dismissDeviceView:didUpdate:)])
    {
        [self.delegate dismissDeviceView:self didUpdate:isUpdated];
    }
    else
    {
        [self removeFromSuperview];
    }
}

- (instancetype)initWithDevice:(MXDevice*)device andMatrixSession:(MXSession*)session
{
    self = [[[self class] nib] instantiateWithOwner:nil options:nil].firstObject;
    if (self)
    {
        mxDevice = device;
        mxSession = session;
        
        [self setTranslatesAutoresizingMaskIntoConstraints: NO];
        
        if (mxDevice)
        {
            // Device information
            NSMutableAttributedString *deviceInformationString = [[NSMutableAttributedString alloc]
                                                                  initWithString:[VectorL10n deviceDetailsTitle]
                                                                  attributes:@{NSForegroundColorAttributeName : _defaultTextColor,
                                                                               NSFontAttributeName: [UIFont boldSystemFontOfSize:15]}];
            [deviceInformationString appendAttributedString:[MXKDeviceView verticalWhitespace]];
            
            [deviceInformationString appendAttributedString:[[NSMutableAttributedString alloc]
                                                             initWithString:[VectorL10n deviceDetailsName]
                                                             attributes:@{NSForegroundColorAttributeName : _defaultTextColor,
                                                                          NSFontAttributeName: [UIFont boldSystemFontOfSize:14]}]];
            [deviceInformationString appendAttributedString:[[NSMutableAttributedString alloc]
                                                             initWithString:device.displayName.length ? device.displayName : @""
                                                             attributes:@{NSForegroundColorAttributeName : _defaultTextColor,
                                                                          NSFontAttributeName: [UIFont systemFontOfSize:14]}]];
            [deviceInformationString appendAttributedString:[MXKDeviceView verticalWhitespace]];
            
            [deviceInformationString appendAttributedString:[[NSMutableAttributedString alloc]
                                                             initWithString:[VectorL10n deviceDetailsIdentifier]
                                                             attributes:@{NSForegroundColorAttributeName : _defaultTextColor,
                                                                          NSFontAttributeName: [UIFont boldSystemFontOfSize:14]}]];
            [deviceInformationString appendAttributedString:[[NSMutableAttributedString alloc]
                                                             initWithString:device.deviceId
                                                             attributes:@{NSForegroundColorAttributeName : _defaultTextColor,
                                                                          NSFontAttributeName: [UIFont systemFontOfSize:14]}]];
            [deviceInformationString appendAttributedString:[MXKDeviceView verticalWhitespace]];
            
            [deviceInformationString appendAttributedString:[[NSMutableAttributedString alloc]
                                                      initWithString:[VectorL10n deviceDetailsLastSeen]
                                                      attributes:@{NSForegroundColorAttributeName : _defaultTextColor,
                                                                   NSFontAttributeName: [UIFont boldSystemFontOfSize:14]}]];
            
            NSDate *lastSeenDate = [NSDate dateWithTimeIntervalSince1970:device.lastSeenTs/1000];
            
            NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
            [dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:[[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0]]];
            [dateFormatter setDateStyle:NSDateFormatterShortStyle];
            [dateFormatter setTimeStyle:NSDateFormatterShortStyle];
            [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
            
            NSString *lastSeen = [VectorL10n deviceDetailsLastSeenFormat:device.lastSeenIp :[dateFormatter stringFromDate:lastSeenDate]];
            
            [deviceInformationString appendAttributedString:[[NSMutableAttributedString alloc]
                                                      initWithString:lastSeen
                                                      attributes:@{NSForegroundColorAttributeName : _defaultTextColor,
                                                                   NSFontAttributeName: [UIFont systemFontOfSize:14]}]];
            [deviceInformationString appendAttributedString:[MXKDeviceView verticalWhitespace]];
            
            self.textView.attributedText = deviceInformationString;
        }
        else
        {
            _textView.text = nil;
        }
        
        // Hide potential activity indicator
        [_activityIndicator stopAnimating];
    }
    
    return self;
}

- (void)dealloc
{
    mxDevice = nil;
    mxSession = nil;
}

+ (NSAttributedString *)verticalWhitespace
{
    if (verticalWhitespace == nil)
    {
        verticalWhitespace = [[NSAttributedString alloc] initWithString:@"\n\n" attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:4]}];
    }
    return verticalWhitespace;
}

#pragma mark - Actions

- (IBAction)onBgViewTap:(UITapGestureRecognizer*)sender
{
    [self removeFromSuperviewDidUpdate:NO];
}

- (IBAction)onButtonPressed:(id)sender
{
    if (sender == _cancelButton)
    {
        [self removeFromSuperviewDidUpdate:NO];
    }
    else if (sender == _renameButton)
    {
        [self renameDevice];
    }
    else if (sender == _deleteButton)
    {
        [self deleteDevice];
    }
}

#pragma mark -

- (void)renameDevice
{
    if (!self.delegate)
    {
        // Ignore
        MXLogDebug(@"[MXKDeviceView] Rename device failed, delegate is missing");
        return;
    }
    
    // Prompt the user to enter a device name.
    [currentAlert dismissViewControllerAnimated:NO completion:nil];
    __weak typeof(self) weakSelf = self;
    
    currentAlert = [UIAlertController alertControllerWithTitle:[VectorL10n deviceDetailsRenamePromptTitle]
                                                       message:[VectorL10n deviceDetailsRenamePromptMessage] preferredStyle:UIAlertControllerStyleAlert];

    [currentAlert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
        
        textField.secureTextEntry = NO;
        textField.placeholder = nil;
        textField.keyboardType = UIKeyboardTypeDefault;
        if (weakSelf)
        {
            typeof(self) self = weakSelf;
            textField.text = self->mxDevice.displayName;
        }
    }];
    
    [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
                                              style:UIAlertActionStyleDefault
                                            handler:^(UIAlertAction * action) {
                                                
                                                if (weakSelf)
                                                {
                                                    typeof(self) self = weakSelf;
                                                    self->currentAlert = nil;
                                                }
                                                
                                            }]];
    
    [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n ok]
                                                     style:UIAlertActionStyleDefault
                                                   handler:^(UIAlertAction * action) {
                                                       
                                                       if (weakSelf)
                                                       {
                                                           typeof(self) self = weakSelf;
                                                           NSString *text = [self->currentAlert textFields].firstObject.text;
                                                           self->currentAlert = nil;
                                                           
                                                           [self.activityIndicator startAnimating];
                                                           
                                                           self->mxCurrentOperation = [self->mxSession.matrixRestClient setDeviceName:text forDeviceId:self->mxDevice.deviceId success:^{
                                                               
                                                               if (weakSelf)
                                                               {
                                                                   typeof(self) self = weakSelf;
                                                                   
                                                                   self->mxCurrentOperation = nil;
                                                                   [self.activityIndicator stopAnimating];
                                                                   
                                                                   [self removeFromSuperviewDidUpdate:YES];
                                                               }
                                                               
                                                           } failure:^(NSError *error) {
                                                               
                                                               if (weakSelf)
                                                               {
                                                                   typeof(self) self = weakSelf;
                                                                   
                                                                   // Notify MatrixKit user
                                                                   NSString *myUserId = self->mxSession.myUser.userId;
                                                                   [[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification object:error userInfo:myUserId ? @{kMXKErrorUserIdKey: myUserId} : nil];
                                                                   
                                                                   self->mxCurrentOperation = nil;
                                                                   
                                                                   MXLogDebug(@"[MXKDeviceView] Rename device (%@) failed", self->mxDevice.deviceId);
                                                                   
                                                                   [self.activityIndicator stopAnimating];
                                                                   
                                                                   [self removeFromSuperviewDidUpdate:NO];
                                                               }
                                                               
                                                           }];
                                                       }
                                                       
                                                   }]];
    
    [self.delegate deviceView:self presentAlertController:currentAlert];
}

- (void)deleteDevice
{
    if (!self.delegate)
    {
        // Ignore
        MXLogDebug(@"[MXKDeviceView] Delete device failed, delegate is missing");
        return;
    }
    
    // Get an authentication session to prepare device deletion
    [self.activityIndicator startAnimating];
    
    mxCurrentOperation = [mxSession.matrixRestClient getSessionToDeleteDeviceByDeviceId:mxDevice.deviceId success:^(MXAuthenticationSession *authSession) {
        
        self->mxCurrentOperation = nil;

        // Check whether the password based type is supported
        BOOL isPasswordBasedTypeSupported = NO;
        for (MXLoginFlow *loginFlow in authSession.flows)
        {
            if ([loginFlow.type isEqualToString:kMXLoginFlowTypePassword] || [loginFlow.stages indexOfObject:kMXLoginFlowTypePassword] != NSNotFound)
            {
                isPasswordBasedTypeSupported = YES;
                break;
            }
        }
        
        if (isPasswordBasedTypeSupported && authSession.session)
        {
            // Prompt for a password
            [self->currentAlert dismissViewControllerAnimated:NO completion:nil];
            
            __weak typeof(self) weakSelf = self;
            
            // Prompt the user before deleting the device.
            self->currentAlert = [UIAlertController alertControllerWithTitle:[VectorL10n deviceDetailsDeletePromptTitle] message:[VectorL10n deviceDetailsDeletePromptMessage] preferredStyle:UIAlertControllerStyleAlert];
            
            
            [self->currentAlert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
                
                textField.secureTextEntry = YES;
                textField.placeholder = nil;
                textField.keyboardType = UIKeyboardTypeDefault;
            }];
            
            [self->currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
                                                             style:UIAlertActionStyleDefault
                                                           handler:^(UIAlertAction * action) {
                                                               
                                                               if (weakSelf)
                                                               {
                                                                   typeof(self) self = weakSelf;
                                                                   self->currentAlert = nil;
                                                                   [self.activityIndicator stopAnimating];
                                                               }
                                                               
                                                           }]];
            
            [self->currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n submit]
                                                             style:UIAlertActionStyleDefault
                                                           handler:^(UIAlertAction * action) {
                                                               
                                                               if (weakSelf)
                                                               {
                                                                   typeof(self) self = weakSelf;
                                                                   UITextField *textField = [self->currentAlert textFields].firstObject;
                                                                   self->currentAlert = nil;
                                                                   
                                                                   NSString *userId = self->mxSession.myUser.userId;
                                                                   NSDictionary *authParams;
                                                                   
                                                                   // Sanity check
                                                                   if (userId)
                                                                   {
                                                                       authParams = @{@"session":authSession.session,
                                                                                      @"user": userId,
                                                                                      @"password": textField.text,
                                                                                      @"type": kMXLoginFlowTypePassword};
                                                                       
                                                                   }
                                                                   
                                                                   self->mxCurrentOperation = [self->mxSession.matrixRestClient deleteDeviceByDeviceId:self->mxDevice.deviceId authParams:authParams success:^{
                                                                       
                                                                       if (weakSelf)
                                                                       {
                                                                           typeof(self) self = weakSelf;
                                                                           
                                                                           self->mxCurrentOperation = nil;
                                                                           [self.activityIndicator stopAnimating];
                                                                           
                                                                           [self removeFromSuperviewDidUpdate:YES];
                                                                       }
                                                                       
                                                                   } failure:^(NSError *error) {
                                                    
                                                                       if (weakSelf)
                                                                       {
                                                                           typeof(self) self = weakSelf;
                                                                           
                                                                           // Notify MatrixKit user
                                                                           NSString *myUserId = self->mxSession.myUser.userId;
                                                                           [[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification object:error userInfo:myUserId ? @{kMXKErrorUserIdKey: myUserId} : nil];
                                                                           
                                                                           self->mxCurrentOperation = nil;
                                                                           
                                                                           MXLogDebug(@"[MXKDeviceView] Delete device (%@) failed", self->mxDevice.deviceId);
                                                                           
                                                                           [self.activityIndicator stopAnimating];
                                                                           
                                                                           [self removeFromSuperviewDidUpdate:NO];
                                                                       }
                                                                       
                                                                   }];
                                                               }
                                                               
                                                           }]];
            
            [self.delegate deviceView:self presentAlertController:self->currentAlert];
        }
        else
        {
            MXLogDebug(@"[MXKDeviceView] Delete device (%@) failed, auth session flow type is not supported", self->mxDevice.deviceId);
            [self.activityIndicator stopAnimating];
        }
        
    } failure:^(NSError *error) {
        
        self->mxCurrentOperation = nil;
        
        MXLogDebug(@"[MXKDeviceView] Delete device (%@) failed, unable to get auth session", self->mxDevice.deviceId);
        [self.activityIndicator stopAnimating];
        
        // Notify MatrixKit user
        NSString *myUserId = self->mxSession.myUser.userId;
        [[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification object:error userInfo:myUserId ? @{kMXKErrorUserIdKey: myUserId} : nil];
    }];
}

@end
