//
//  KMPDFSignatureImageView.m
//  PDF Reader
//
//  Created by 丁林圭 on 2018/6/8.
//  Copyright © 2018年 Kdan Mobile. All rights reserved.
//

#import "KMPDFSignatureImageView.h"
#import <Quartz/Quartz.h>
#import "KMImageAccessoryController.h"
#import <PDF_Master-Swift.h>

#define KMSignatureMaxWidth 400
#define KMSignatureMaxHeight 300

@interface KMPDFSignatureImageView()

@property (nonatomic, retain) NSImage * picImage;
@property (nonatomic) IBOutlet NSView *pictureView;
@property (nonatomic) IBOutlet NSTextField *emptyTipLbl;
@property (nonatomic) IBOutlet NSButton *dragButton;
@property (nonatomic) IBOutlet NSImageView *emptyImg;

@property (nonatomic, copy) NSTrackingArea *trackingArea;

@property (nonatomic, strong) NSURL *imageURL;

@end


@implementation KMPDFSignatureImageView

- (void)dealloc {

    [self removeTrackingArea:self.trackingArea];
}

- (id)initWithFrame:(NSRect)frameRect
{
    if (self = [super initWithFrame:frameRect])
    {
        self.wantsLayer = YES;
        self.layer.borderWidth = 1.0;
        self.layer.borderColor = [NSColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.05].CGColor;
        self.layer.backgroundColor = [NSColor colorWithRed:1 green:1 blue:1 alpha:0.9].CGColor;;
        
        [self registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
        
    }
    return self;
}

- (void)awakeFromNib
{
    [super awakeFromNib];
    
    self.emptyTipLbl.stringValue = NSLocalizedString(@"Select image file", nil);
    self.emptyTipLbl.textColor = [NSColor labelColor];
    self.dragButton.wantsLayer = YES;
    [self.dragButton setTitleColorWithColor:[NSColor labelColor] font:nil];
    
    self.pictureView.wantsLayer = YES;
    self.emptyImg.image = [NSImage imageNamed:@"signPicture_nor"];
    
    self.trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds]
                                                 options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways
                                                   owner:self
                                                userInfo:nil];
    [self addTrackingArea:self.trackingArea];
}

- (NSArray *)supportedImageTypes
{
    return [NSArray arrayWithObjects:@"jpg",@"cur",@"bmp",@"jpeg",@"gif",@"png",@"tiff",@"tif",@"ico",@"icns",@"tga",@"psd",@"eps",@"hdr",@"jp2",@"jpc",@"pict",@"sgi",@"pdf", nil];
}

- (void)drawRect:(NSRect)dirtyRect
{
    [super drawRect:dirtyRect];
    if (self.pictureView) {
        
        CGRect rect = NSZeroRect;
        CIImage *imageCIImage = [CIImage imageWithData:self.picImage.TIFFRepresentation];
        NSSize size = [imageCIImage extent].size;
        
        CGFloat scale = MIN((dirtyRect.size.width - 30)/size.width, (dirtyRect.size.height - 30)/size.height);
        if (scale > 1) {
            rect = CGRectMake(0, 0, size.width, size.height);
        } else {
            rect = CGRectMake(0, 0, size.width * scale, size.height *scale);
        }
        [self.picImage drawInRect:CGRectMake((dirtyRect.size.width - rect.size.width)/2,
                                             (dirtyRect.size.height - rect.size.height)/2,
                                             rect.size.width,rect.size.height)
                         fromRect:NSZeroRect
                        operation:NSCompositingOperationSourceOver
                         fraction:1.0];
    }
}

- (void)setClearBackground:(BOOL)clearBackground {
    _clearBackground = clearBackground;
    
    if (self.imageURL && self.imageURL.path.length > 0) {
        [self loadImageViewPath:self.imageURL isRemoveBGColor:self.clearBackground];
    }
}

#pragma mark Public
- (void)clearImage
{
    self.picImage = nil;
    self.imageURL = nil;
    self.pictureView.hidden = self.emptyTipLbl.hidden = NO;
    [self setNeedsDisplay:YES];
    
    if (self.changeSignatureImageCallback) {
        self.changeSignatureImageCallback(YES);
    }
}

- (void)reSelectImage {
    [self buttonItemClick_SelectPhoto:nil];
}

- (NSImage *)signatureImage
{
    CGRect rect = CGRectZero;
    
    if (!self.picImage) {
        return nil;
    } else {
        CIImage *imageCIImage = [CIImage imageWithData:self.picImage.TIFFRepresentation];
        NSSize size = [imageCIImage extent].size;
        CGFloat scale = MIN(KMSignatureMaxWidth/size.width, KMSignatureMaxHeight/size.height);
        if (scale > 1) {
            rect = CGRectMake(0, 0, size.width, size.height);
        } else {
            rect = CGRectMake(0, 0, size.width * scale, size.height *scale);
        }
    }
    
    NSImage *image = [[NSImage alloc] initWithSize:rect.size];
    [image lockFocus];
    [self.picImage drawInRect:rect
             fromRect:NSZeroRect
                    operation:NSCompositingOperationSourceOver
             fraction:1.0];

    [image unlockFocus];
    return image;
}

- (void)loadImageViewPath:(NSURL *)url isRemoveBGColor:(BOOL)isRemove
{
    self.imageURL = url;
    
    NSString * filePath = url.path;

    if ([filePath.pathExtension.lowercaseString isEqualToString:@"pdf"]) {
        PDFDocument *pdf = [[PDFDocument alloc] initWithURL:url];
        if (pdf.isEncrypted) {
            return;
        }
    }
    NSImage *image = [[NSImage alloc] initWithContentsOfFile:filePath];
    
    if (isRemove) {
        NSData *imageData = [image TIFFRepresentation];
        CGImageRef imageRef;
        if (imageData) {
            CGImageSourceRef imageSource = CGImageSourceCreateWithData((CFDataRef)imageData, NULL);
            imageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL);
        }
        
        const int imageWidth = image.size.width;
        const int imageHeight = image.size.height;
        size_t bytesPerRow = imageWidth * 4;
        uint32_t* rgbImageBuf = (uint32_t*)malloc(bytesPerRow * imageHeight);
        
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGContextRef context = CGBitmapContextCreate(rgbImageBuf,
                                                     imageWidth,
                                                     imageHeight,
                                                     8,
                                                     bytesPerRow,
                                                     colorSpace,
                                                     kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast);
        CGContextDrawImage(context, CGRectMake(0, 0, imageWidth, imageHeight), imageRef);
        
        int pixelNum = imageWidth * imageHeight;
        uint32_t* pCurPtr = rgbImageBuf;
        for (int i = 0; i < pixelNum; i++, pCurPtr++) {
            uint8_t* ptr = (uint8_t*)pCurPtr;
            if (ptr[1] > 240 && ptr[2] > 240 && ptr[3] > 240) {
                ptr[0] = 0;
            }
        }
        
        CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, rgbImageBuf, bytesPerRow * imageHeight, nil);
        imageRef = CGImageCreate(imageWidth,
                                 imageHeight,
                                 8,
                                 32,
                                 bytesPerRow,
                                 colorSpace,
                                 kCGImageAlphaLast |kCGBitmapByteOrder32Little,
                                 dataProvider,
                                 NULL,
                                 true,
                                 kCGRenderingIntentDefault);
        CGDataProviderRelease(dataProvider);
        
        NSImage *newImage = nil;
        if (imageRef) {
            NSRect imageRect = NSMakeRect(0.0, 0.0, 0.0, 0.0);
            CGContextRef imageContext = nil;
            
            // Get the image dimensions.
            imageRect.size.height = CGImageGetHeight(imageRef);
            imageRect.size.width = CGImageGetWidth(imageRef);
            
            // Create a new image to receive the Quartz image data.
            newImage = [[NSImage alloc] initWithSize:imageRect.size];
            [newImage lockFocus];
            
            // Get the Quartz context and draw.
            imageContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
            CGContextDrawImage(imageContext, *(CGRect*)&imageRect, imageRef);
            [newImage unlockFocus];
            CGImageRelease(imageRef);
        }
        
        if (newImage) {
            image = newImage;
        }
    }
    
    if (image) {
        self.picImage = image;
        self.pictureView.hidden = self.emptyTipLbl.hidden = YES;
        [self setNeedsDisplay:YES];
    }
}

- (CAGradientLayer *)setGradualChanging {

    CAGradientLayer *gradientLayer = [CAGradientLayer layer];
    gradientLayer.frame = _dragButton.bounds;
    gradientLayer.colors = @[(__bridge id)[NSColor lightGrayColor].CGColor,(__bridge id)[NSColor whiteColor].CGColor];
    gradientLayer.startPoint = CGPointMake(0, 0);
    gradientLayer.endPoint = CGPointMake(1, 1);
    gradientLayer.locations = @[@0,@1];
    return gradientLayer;
}

- (BOOL)isDamageImage:(NSImage *)image imagePath:(NSString *)path {
    NSString *addImageAnnotation = [[[NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[NSBundle mainBundle].bundleIdentifier] stringByAppendingPathComponent:@"addImageAnnotation"];
    if (![[NSFileManager defaultManager] fileExistsAtPath:addImageAnnotation]) {
        [[NSFileManager defaultManager] createDirectoryAtPath:addImageAnnotation withIntermediateDirectories:NO attributes:nil error:nil];
    }
    NSData *data = [image TIFFRepresentation];
    NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:data];
    [imageRep setSize:[image size]];
    NSData *imageData  = nil;
    if ([path.lowercaseString isEqualToString:@"png"]) {
        imageData = [imageRep representationUsingType:NSBitmapImageFileTypePNG properties:@{}];
    } else {
        imageData = [imageRep representationUsingType:NSJPEGFileType properties:@{}];
    }
    
    NSString *rPath = [addImageAnnotation stringByAppendingPathComponent:[[self tagString] stringByAppendingPathExtension:@"png"]];
    if (![imageData writeToFile:rPath atomically:YES]) {
        return YES;
    } else {
        return NO;
    }
}

- (NSString *)tagString {
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.dateFormat    = @"yyMMddHHmmss";
    return [NSString stringWithFormat:@"%@%04d", [dateFormatter stringFromDate:[NSDate date]], rand()%10000];
}


#pragma mark - Button Action
- (IBAction)buttonItemClick_SelectPhoto:(id)sender
{
    NSOpenPanel *openPanel = [NSOpenPanel openPanel];
    
    [openPanel setAllowedFileTypes:[self supportedImageTypes]];
    [openPanel setAllowedFileTypes:[KMImageAccessoryController supportedImageTypes]];
    if ([openPanel respondsToSelector:@selector(setAccessoryViewDisclosed:)]) {
        [openPanel setAccessoryViewDisclosed:YES];
    }
    [openPanel setAllowsMultipleSelection:NO];
    [openPanel beginSheetModalForWindow:[self window] completionHandler:^(NSInteger result) {
        if (result == NSModalResponseOK) {
        
            NSURL *url = [openPanel URL];
            
            //判断PDF文件是否已损坏
            NSString * filePath = url.path;
            if ([filePath.pathExtension.lowercaseString isEqualToString:@"pdf"]) {
                PDFDocument *pdf = [[PDFDocument alloc] initWithURL:url];
                if (!pdf) {
                    NSAlert *alert = [[NSAlert alloc] init];
                    [alert setAlertStyle:NSAlertStyleCritical];
                    [alert setMessageText:[NSString stringWithFormat:@"%@",NSLocalizedString(@"An error occurred while opening this document. The file is damaged and could not be repaired.", nil)]];
                    [alert runModal];
                    return;
                }
            }
            
            NSImage *image = [[NSImage alloc] initWithContentsOfFile:url.path];
            if ([self isDamageImage:image imagePath:url.path]) {
                NSAlert *alert = [[NSAlert alloc] init];
                [alert setAlertStyle:NSAlertStyleCritical];
                [alert setMessageText: [NSString stringWithFormat:NSLocalizedString(@"The file \"%@\" could not be opened.", nil), url.path.lastPathComponent]];
                [alert setInformativeText:NSLocalizedString(@"It may be damaged or use a file format that PDF Reader Pro doesn’t recognize.", nil)];
                [alert addButtonWithTitle:NSLocalizedString(@"Cancel", nil)];
                [alert beginSheetModalForWindow:[NSApp mainWindow] completionHandler:^(NSModalResponse returnCode) {
                        if (returnCode == NSAlertFirstButtonReturn) {

                        }
                }];

                return;
            }
            
            [self loadImageViewPath:url isRemoveBGColor:self.clearBackground];
            if (self.changeSignatureImageCallback) {
                self.changeSignatureImageCallback(YES);
            }
        }
    }];
}

- (void)mouseEntered:(NSEvent *)event {
    [super mouseEntered:event];
    self.emptyImg.image = [NSImage imageNamed:@"signPicture_hover"];
}

- (void)mouseMoved:(NSEvent *)event {
    [super mouseMoved:event];
    
    CGPoint point = [event locationInWindow];
    CGPoint convertPoint = [self.pictureView convertPoint:point fromView:self.window.contentView];
    
    if (CGRectContainsPoint(self.pictureView.bounds, convertPoint)) {
        self.emptyImg.image = [NSImage imageNamed:@"signPicture_hover"];
    } else {
        self.emptyImg.image = [NSImage imageNamed:@"signPicture_nor"];
    }
}

- (void)mouseExited:(NSEvent *)event {
    [super mouseExited:event];

    self.emptyImg.image = [NSImage imageNamed:@"signPicture_nor"];
}

#pragma mark - Drag
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
{
    NSPasteboard *pboard = [sender draggingPasteboard];
    if ([pboard availableTypeFromArray:[NSArray arrayWithObject:NSFilenamesPboardType]]) {
        NSArray *fileNames = [pboard propertyListForType:NSFilenamesPboardType];
        if (fileNames.count == 1) {
            NSArray *supportArray= [self supportedImageTypes];
            NSString* path  = fileNames.firstObject;
            if ([supportArray containsObject:[path.pathExtension lowercaseString]]) {
                return NSDragOperationEvery;
            }
        }
    }
    return NSDragOperationNone;
}

- (BOOL)prepareForDragOperation:(id<NSDraggingInfo>)sender
{
    NSPasteboard *pboard = [sender draggingPasteboard];
    if ([pboard availableTypeFromArray:[NSArray arrayWithObject:NSFilenamesPboardType]]) {
        NSMutableArray *fileNames = [pboard propertyListForType:NSFilenamesPboardType];
        
        if (fileNames.count == 1) {
            NSArray *supportArray= [self supportedImageTypes];
            NSString* path  = fileNames.firstObject;
            
            //判断PDF文件是否已损坏
            NSString * filePath = path;
            if ([filePath.pathExtension.lowercaseString isEqualToString:@"pdf"]) {
                PDFDocument *pdf = [[PDFDocument alloc] initWithURL:[NSURL fileURLWithPath:path]];
                if (!pdf) {
                    NSAlert *alert = [[NSAlert alloc] init];
                    [alert setAlertStyle:NSAlertStyleCritical];
                    [alert setMessageText:[NSString stringWithFormat:@"%@",NSLocalizedString(@"An error occurred while opening this document. The file is damaged and could not be repaired.", nil)]];
                    [alert runModal];
                    return NO;
                }
            }
            if ([supportArray containsObject:[path.pathExtension lowercaseString]]) {
                [self loadImageViewPath:[NSURL fileURLWithPath:path] isRemoveBGColor:self.clearBackground];
                if (self.changeSignatureImageCallback) {
                    self.changeSignatureImageCallback(YES);
                }
            }
        }
    }
    return YES;
}

@end