//
//  FSTextViewController.m
//  Downloader
//
//  Created by LiDong on 13-3-25.
//  Copyright (c) 2013年 LiDong. All rights reserved.
//

#import "FSTextViewController.h"
#import "FSFileNameViewController.h"
#import "FSFileListViewController.h"
#import "PSTextSettingsViewController.h"
#import "IFNavigationController.h"
#import <sys/xattr.h>

#define kContentOffsetKey @"com.txt.content_offset"

#define kEditableTextLengthLimit SIZE_128_KB
#define kReadableTextLengthLimit SIZE_1_MB

@interface FSTextViewController ()

@end

@implementation FSTextViewController

enum {
    kActionClose = 1,
    kActionSettings,
    kActionPrint
};

- (id)initWithPath:(NSString *)path {
    if (self = [super init]) {
        _path = path;
        _textStyle = [[UITextStyleSettings alloc] initWithPath:path];
        
        NSString *fileName = [_path lastPathComponent];
        
        if (UISettingsShowFileExtensions()) {
            [self setTitle:fileName];
        } else {
            [self setTitle:[fileName stringByDeletingPathExtension]];
        }
        
        _statusBarStyle = UIStatusBarStyleLightContent;
        
        UINavigationItem *navigationItem = [self navigationItem];
        
        UIBarButtonItem *stopItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemStop target:self action:@selector(onClose)];
        
        [navigationItem setLeftBarButtonItem:stopItem];
        _editItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCompose target:self action:@selector(onEdit)];
        _doneItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(onDone)];
        
        [navigationItem setRightBarButtonItem:_editItem];
        
        UIBarButtonItem *actionItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"bar/action.png"] style:UIBarButtonItemStyleDone target:self action:@selector(onAction)];
        UIBarButtonItem *flexibleItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:NULL];
        
        NSArray *toolbarItems = [[NSArray alloc] initWithObjects:actionItem, flexibleItem, _rotationItem, nil];
        
        [self setToolbarItems:toolbarItems];
        
        _textQueue = dispatch_queue_create("com.iFileReader.fs.text", 0);
        
        _keyboardHeight = 216.f;
        
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
    }
    return self;
}

- (void)loadView {
    _contentView = [[UIView alloc] initWithFrame:CGRectPortraitScreen];
    [_contentView setBackgroundColor:UIColorTexturedBackground];
    
    _textView = [[UITextView alloc] initWithFrame:CGRectPortraitScreen];
    [_textView setDelegate:self];
    [_textView setBackgroundColor:UIColorClear];
    [_textView setTextColor:UIColorWhite];
    [_textView setAlwaysBounceVertical:YES];
    [_textView setEditable:NO];
    
    _tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
    [_tapGestureRecognizer setCancelsTouchesInView:NO];
    
    [_contentView addSubview:_textView];
    
    [_editItem setEnabled:NO];
    [_doneItem setEnabled:NO];
    
    _textEncoding = kCFStringEncodingInvalidId;
    
    [self setView:_contentView];
}

- (UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleLightContent;
}

- (void)loadExtendedAttributes {
    NSDictionary *attributes = [theFileManager attributesOfItemAtPath:_path error:NULL];
    NSDictionary *extendAttributes = [attributes valueForKey:NSFileExtendedAttributes];
    
    if (extendAttributes) {
        CGPoint contentOffset = { 0 };
        NSData *offsetData = [extendAttributes valueForKey:kContentOffsetKey];
        
        if (sizeof(CGPoint) == [offsetData length]) {
            memcpy(&contentOffset, [offsetData bytes], sizeof(CGPoint));
            const CGSize contentSize = [_textView contentSize];
            const CGRect rect = { 0, 0, contentSize.width, contentSize.height };
            
            if (CGRectContainsPoint(rect, contentOffset)) {
                [_textView setContentOffset:contentOffset];
            }
        }
    }
}

- (void)loadTextWithEncoding:(const CFStringEncoding)textEncoding {
    _textEncoding = textEncoding;
    
    UIActivityIndicatorView *activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
    
    [activityIndicatorView setHidesWhenStopped:YES];
    [activityIndicatorView setCenter:[_textView center]];
    [activityIndicatorView setAutoresizingMask:UIFlxAllMargins];
    [_contentView addSubview:activityIndicatorView];
    
    [activityIndicatorView startAnimating];
    
    dispatch_async(_textQueue, ^{
        @autoreleasepool {
            const dispatch_queue_t mainQueue = dispatch_get_main_queue();
            NSError *error = nil;
            NSString *content = [[NSString alloc] initWithContentsOfFile:_path encoding:CFStringConvertEncodingToNSStringEncoding(textEncoding) error:&error];
            const NSUInteger contentLength = [content length];
            NSString *text = nil;
            
            if (contentLength <= kReadableTextLengthLimit) {
                text = content;
            } else {
                text = [content substringToIndex:kReadableTextLengthLimit];
            }
            
            dispatch_sync(mainQueue, ^{
                _contentLength = contentLength;
                
                if (error) {
                    UIAlert(LS(@"ERROR"), LS(@"OPEN_TEXT_FAILED_PROMPT"));
                } else {
                    [_textView setText:text];
                    
                    if (kEditableTextLengthLimit > _contentLength) {
                        [_editItem setEnabled:YES];
                        [_doneItem setEnabled:YES];
                        [_textView setEditable:_editing];
                        if (_editing) {
                            [_textView becomeFirstResponder];
                        } else {
                            [_textView addGestureRecognizer:_tapGestureRecognizer];
                        }
                    } else {
                        if (_editing) {
                            [self setEditing:NO animated:NO];
                        }
                    }
                }
                [self performSelector:@selector(loadExtendedAttributes) withObject:nil afterDelay:0];
                [activityIndicatorView stopAnimating];
                [activityIndicatorView removeFromSuperview];
            });
            
        }   //  end @autoreleasepool
    });
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [[self navigationController] setToolbarHidden:NO animated:animated];
    
    const CFStringEncoding newEncoding = [_textStyle encoding];
    
    if (newEncoding != _textEncoding) {
        [self loadTextWithEncoding:newEncoding];
    }
    
    [_textView setFont:[_textStyle font]];
}

- (void)viewWillDisappear:(BOOL)animated {
    [[UIPrintInteractionController sharedPrintController] dismissAnimated:animated];
}

- (void)saveExtendedAttributes {
    const CGPoint contentOffset = [_textView contentOffset];
    NSData *offsetData = [[NSData alloc] initWithBytes:&contentOffset length:sizeof(CGPoint)];
    NSDictionary *extendedAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:offsetData, kContentOffsetKey, nil];
    NSDictionary *attributes = [[NSDictionary alloc] initWithObjectsAndKeys:extendedAttributes, NSFileExtendedAttributes, nil];
    NSError *error = nil;
    
    [theFileManager setAttributes:attributes ofItemAtPath:_path error:&error];
    DLog(@"error: %@", error);
}

- (void)releaseSubviews {
    [self saveExtendedAttributes];
    
    _contentView = nil;
    _textView = nil;
    _tapGestureRecognizer = nil;
}

- (void)layoutWithContentSize:(const CGSize)contentSize {
    CGRect textFrame = { CGPointZero, contentSize };
    
    if (_editing) {
        textFrame.size.height -= (_keyboardHeight - 44);
    }
    [_textView setFrame:textFrame];
}

#pragma mark - UITextViewDelegate

- (void)runFrameAnimation {
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.25];
    [self layoutWithContentSize:self.viewIfLoaded.bounds.size];
    [UIView commitAnimations];
}

- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
    return _editing;
}

- (void)textViewDidBeginEditing:(UITextView *)textView {
    [self runFrameAnimation];
}

- (BOOL)textViewShouldEndEditing:(UITextView *)textView {
    return YES;
}

- (void)textViewDidEndEditing:(UITextView *)textView {
    [self runFrameAnimation];
}

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    const NSUInteger newLegnth = _contentLength + [text length] - range.length;
    
    if (kEditableTextLengthLimit > newLegnth) {
        _contentLength = newLegnth;
        return YES;
    }
    return NO;
}

- (void)textViewDidChange:(UITextView *)textView {
    _textChanged = YES;
}

#pragma mark - Action

- (void)alertSavingWithTag:(const NSInteger)tag {
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:LS(@"SAVE_CHANGES") message:LS(@"SAVE_CHANGES_MESSAGE") delegate:self cancelButtonTitle:LS(@"DISCARD") otherButtonTitles:LS(@"SAVE"), nil];
    
    [alert setTag:tag];
    [alert show];
}

- (void)onAction {
    UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:LS(@"CANCEL") destructiveButtonTitle:nil otherButtonTitles:LS(@"SETTINGS"), LS(@"PRINT"), nil];
    
    [actionSheet showInView:[[self navigationController] view]];
}

- (void)onClose {
    if (_textChanged) {
        [self alertSavingWithTag:kActionClose];
    } else {
        [[self navigationController] dismissViewControllerAnimated:YES completion:NULL];
    }
}

- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
    _editing = editing;
    
    [_textView setEditable:_editing];
    [[self navigationItem] setRightBarButtonItem:(_editing ? _doneItem : _editItem) animated:animated];
    
    if (_editing) {
        [_textView removeGestureRecognizer:_tapGestureRecognizer];
        [_textView becomeFirstResponder];
    } else {
        [_textView addGestureRecognizer:_tapGestureRecognizer];
        [_textView resignFirstResponder];
    }
}

- (void)onEdit {
    [self setEditing:YES animated:YES];
}

- (void)onDone {
    [self doSave];
    [self setEditing:NO animated:YES];
}

- (void)handleSingleTap:(id)sender {
    [self reverseFullScreen];
}

- (void)doPrint {
    UIPrintInteractionController *printController = [UIPrintInteractionController sharedPrintController];
    UISimpleTextPrintFormatter *printFormatter = [[UISimpleTextPrintFormatter alloc]
                                                  initWithText:[_textView text]];
    UIPrintInfo *printInfo = [UIPrintInfo printInfo];
    const UIEdgeInsets contentInsets = { 72.f, 72.f, 72.f, 72.f };
    
    [printInfo setOutputType:UIPrintInfoOutputGeneral];
    [printInfo setJobName:[self title]];
    [printFormatter setStartPage:0];
    [printFormatter setContentInsets:contentInsets];
    [printFormatter setMaximumContentWidth:(72.f * 6.f)];
    [printFormatter setMaximumContentHeight:(72.f * 10.f)];
    [printFormatter setTextAlignment:[_textView textAlignment]];
    [printFormatter setFont:[_textView font]];
    [printController setShowsPageRange:YES];
    [printController setPrintInfo:printInfo];
    [printController setPrintFormatter:printFormatter];
    [printController presentAnimated:YES completionHandler:^(UIPrintInteractionController *printInteractionController, BOOL completed, NSError *error){
    }];
}

- (void)doSettings {
    UIViewController *viewController = [[PSTextSettingsViewController alloc] initWithTextStyle:_textStyle];
    UINavigationController *navigationController = [[IFNavigationController alloc] initWithRootViewController:viewController];
    UINavigationBar *navigationBar = [navigationController navigationBar];
    UIToolbar *toolbar = [navigationController toolbar];
    
    [navigationController setToolbarHidden:YES];
    [toolbar setBarStyle:UIBarStyleDefault];
    [toolbar setTranslucent:NO];
    [navigationBar setBarStyle:UIBarStyleDefault];
    [navigationBar setTranslucent:NO];
    [[self navigationController] presentViewController:navigationController animated:YES completion:NULL];
}

#pragma mark - UIAlertViewDelegate

- (void)doSave {
    FSFileListViewController *fileListViewController = [FSFileListViewController currentFileListViewController];
    
    [fileListViewController beginUpdate];
    
    [_textStyle save];
    
    NSString *content = [_textView text];
    
    dispatch_sync(_textQueue, ^{
        NSError *error = nil;
        const NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(_textEncoding);
        
        [content writeToFile:_path atomically:YES encoding:encoding error:&error];
    });
    _textChanged = NO;
    
    [fileListViewController endUpdate];
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    if (1 == buttonIndex) {
        [self doSave];
    }
    
    const NSInteger tag = [alertView tag];
    
    if (kActionClose == tag) {
        [[self navigationController] dismissViewControllerAnimated:YES completion:NULL];
    } else if (kActionSettings == tag) {
        [self doSettings];
    } else {
        [self doPrint];
    }
}

#pragma mark - Notification

- (void)keyboardWillChangeFrame:(NSNotification *)notification {
    NSDictionary *userInfo = [notification userInfo];
    NSNumber *rectNumber = [userInfo valueForKey:@"UIKeyboardBoundsUserInfoKey"];
    
    if (rectNumber) {
        const CGFloat newHeight = rectNumber.CGRectValue.size.height;
        
        if (fabs(newHeight - _keyboardHeight) >= 0.5f) {
            _keyboardHeight = newHeight;
            [self runFrameAnimation];
        }
    }
}

#pragma mark - UIActionSheetDelegate

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
    if (0 == buttonIndex) {
        if (_textChanged) {
            [self alertSavingWithTag:kActionSettings];
        } else {
            [self doSettings];
        }
    } else if (1 == buttonIndex) {
        if (_textChanged) {
            [self alertSavingWithTag:kActionPrint];
        } else {
            [self doPrint];
        }
    }
}

@end
