//
//  KMMainDocument.swift
//  PDF Master
//
//  Created by wanjun on 2022/12/6.
//

import Cocoa

typealias KMMainDocumentCloudUploadHanddler = (@escaping(Bool, String)->()) -> ()
@objcMembers class KMMainDocument: CTTabContents {
    var mainViewController: KMMainViewController?
    var homeWindowController: KMHomeWindowController?
    var homeViewController: KMHomeViewController?
    var isNewCreated: Bool = false
    var closedByUserGestureFlag: Bool = false   // 标记 closedByUserGesture 这个状态需要延后存储(如果需要)
    var cloud: Bool = false
    var cloudUploadHanddler: KMMainDocumentCloudUploadHanddler?
    var isUnlockFromKeychain: Bool = false
    private var _saveAsing = false
    
    private var _saveToURL: URL?
    var saveToURL: URL? {
        get {
            return self._saveToURL
        }
    }
    
    weak var watermarkSaveDelegate: AnyObject?
    private var _trackEvents = IndexSet()
    
    override func save(to url: URL, ofType typeName: String, for saveOperation: NSDocument.SaveOperationType, delegate: Any?, didSave didSaveSelector: Selector?, contextInfo: UnsafeMutableRawPointer?) {
        if (self.isNewCreated) {
//            if let data = self.mainViewController, !data.isPDFDocumentEdited && !data.needSave && !self.isDocumentEdited {
                self._km_save(to: url, ofType: typeName, for: saveOperation, delegate: delegate, didSave: didSaveSelector, contextInfo: contextInfo)
                return
//            }
        }
        if (!self.needSaveWatermark()) {
            self._km_save(to: url, ofType: typeName, for: saveOperation, delegate: delegate, didSave: didSaveSelector, contextInfo: contextInfo)
            return
        }
        
        var openAccessoryView = self.watermarkSaveDelegate != nil
        if (openAccessoryView) {
            if let _browser = self.watermarkSaveDelegate as? KMBrowser, _browser.isCloseAllTabViewItem {
                openAccessoryView = false
            }
        }
        
        self._km_saveForWatermark(openAccessoryView: openAccessoryView) { [unowned self] in
            self.trackEvents()
        } callback: { [unowned self] needSave, params in
            if (needSave) {
                self._km_save(to: url, ofType: typeName, for: saveOperation, delegate: delegate, didSave: didSaveSelector, contextInfo: contextInfo)
            } else { // 水印保存
                if (self.watermarkSaveDelegate == nil) {
                    if let data = params.first as? KMResult, data == .cancel {
                        if let shouldClose = params.last as? Bool, shouldClose {
                            DispatchQueue.main.async {
                                self.mainViewController?.browserWindowController?.browser.windowDidBeginToClose()
                            }
                        }
                    } else {
                        DispatchQueue.main.async {
                            self.mainViewController?.browserWindowController?.browser.windowDidBeginToClose()
                        }
                    }
                    return
                }
                if let data = params.first as? KMResult, data == .cancel {
                    if var shouldClose = params.last as? Bool {
                        if let _browser = self.watermarkSaveDelegate as? KMBrowser, _browser.isCloseAllTabViewItem {
                            shouldClose = true
                        }
                        (self.watermarkSaveDelegate as? KMBrowser)?.document(self, shouldClose: shouldClose, contextInfo: nil)
                    }
                } else {
                    (self.watermarkSaveDelegate as? KMBrowser)?.document(self, shouldClose: true, contextInfo: nil)
                }
                self.watermarkSaveDelegate = nil
            }
        }
    }
    
    override func makeWindowControllers() {
        // Returns the storyboard that contains your document window.
        
        if ((self.fileURL?.path) != nil) {
            if !self.fileURL!.path.isPDFValid() {
                let alert = NSAlert()
                alert.alertStyle = .critical
                alert.messageText = NSLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "")
                alert.runModal()
                return
            }
        }
        
        let mainWindow = NSApp.mainWindow
        var currentWindowController: KMBrowserWindowController?
        if mainWindow != nil {
            let windowController = mainWindow!.windowController
            if windowController is KMBrowserWindowController {
                currentWindowController = (windowController as! KMBrowserWindowController)
            } else {
                for window in NSApp.windows {
                    let windowController = window.windowController
                    if windowController is KMBrowserWindowController {
                        currentWindowController = (windowController as! KMBrowserWindowController)
                        break
                    }
                }
            }
        } else {
            for window in NSApp.windows {
                let windowController = window.windowController
                if windowController is KMBrowserWindowController {
                    currentWindowController = (windowController as! KMBrowserWindowController)
                    break
                }
            }
        }
        
        if (currentWindowController == nil) && (self.fileURL != nil) {
            let browser = KMBrowser.init() as KMBrowser
            browser.addHomeTabContents()
            browser.windowController = KMBrowserWindowController.init(browser: browser)
            currentWindowController = browser.windowController as? KMBrowserWindowController
        }
        
        if currentWindowController?.browser == nil && (self.fileURL != nil) {
            let browser: KMBrowser = KMBrowser.init()
            browser.windowController = KMBrowserWindowController.init(browser: browser)
            browser.addHomeTabContents()
            currentWindowController = browser.windowController as? KMBrowserWindowController
            browser.windowController.showWindow(self)
        }
        
        mainViewController = KMMainViewController.init()
        mainViewController?.myDocument = self
        
        if ((self.fileURL?.path) != nil) {
            let pdfDocument = CPDFDocument.init(url: URL(fileURLWithPath: self.fileURL!.path))
            mainViewController?.document = pdfDocument
        }
        
        self.view = mainViewController?.view
        
        if currentWindowController != nil {
            if currentWindowController?.browser != nil {
//                currentWindowController?.browser.add(self, at: Int32()-1, inForeground: true)
//                self.addWindowController(currentWindowController!)
//                mainViewController.browserWindowController = currentWindowController

                let activeBrowser = (currentWindowController?.browser.activeTabContents())! as CTTabContents
                let activeIndex = Int((currentWindowController?.browser.activeTabIndex())!)
                self.addWindowController(currentWindowController!)
                self.mainViewController?.browserWindowController = currentWindowController

                let ishome = activeBrowser.isHome as Bool
                let isfirstTab = (activeIndex == 0)
                if ishome && !isfirstTab {
                    // 替换 document
                    currentWindowController?.browser.replaceTabContents(at: Int32(activeIndex), with: self)
                    // 刷新标签
                    currentWindowController?.browser.updateTabState(at: Int32(activeIndex))
                    
                    // 刷新 home icon
                    if let tabStripController = currentWindowController?.tabStripController {
                        if let view = tabStripController.view(at: UInt(activeIndex)) as? CTTabView {
                            view.controller().isHome = self.isHome
                            view.controller().isNewTab = self.isNewTab
                            view.controller().updateUI()
                        }
                    }
                } else {
                    currentWindowController?.browser.add(self, at: Int32()-1, inForeground: true)
                }
            }
        }
    }
    
    override func showWindows() {
        super.showWindows()
        
        self.setDataFromTmpData()
    }
    
    override func windowControllerDidLoadNib(_ aController: NSWindowController) {
        super.windowControllerDidLoadNib(aController)
        
        self.setDataFromTmpData()
    }
    
    override func save(to url: URL, ofType typeName: String, for saveOperation: NSDocument.SaveOperationType) async throws {
        do {
            try await super.save(to: url, ofType: typeName, for: saveOperation)
        } catch let outError {
            Swift.print(outError)
        }
    }
    
    override func write(to url: URL, ofType typeName: String, for saveOperation: NSDocument.SaveOperationType, originalContentsURL absoluteOriginalContentsURL: URL?) throws {
        try self._km_write(to: url, ofType: typeName, for: saveOperation, originalContentsURL: absoluteOriginalContentsURL)
    }
    
    override func canClose(withDelegate delegate: Any, shouldClose shouldCloseSelector: Selector?, contextInfo: UnsafeMutableRawPointer?) {
        let isPrompt = KMPreferenceManager.shared.closeFileIsPrompt()
        if (isPrompt) {
            super.canClose(withDelegate: delegate, shouldClose: shouldCloseSelector, contextInfo: contextInfo)
            return
        }

        if (self.isNewCreated) {
            self.save(nil)
        } else if (self.isDocumentEdited) {
            self.save(nil)
        } else if (mainViewController != nil) {
            if self.mainViewController!.isPDFDocumentEdited || self.mainViewController!.needSave {
                self.save(nil)
            }
        }

        super.canClose(withDelegate: delegate, shouldClose: shouldCloseSelector, contextInfo: contextInfo)
    }
    
    override func saveAs(_ sender: Any?) {
        if (!self.needSaveWatermark()) {
            self._km_saveAs(sender)
            return
        }
        self._km_saveForWatermark { [unowned self] needSave, _ in
            if (needSave) {
                self._km_saveAs(sender)
            }
        }
    }
    
    override func runModalSavePanel(for saveOperation: NSDocument.SaveOperationType, delegate: Any?, didSave didSaveSelector: Selector?, contextInfo: UnsafeMutableRawPointer?) {
        if (self.isNewCreated) {
//            if let data = self.mainViewController, !data.isPDFDocumentEdited && !data.needSave && !self.isDocumentEdited {
                self._km_runModalSavePanel(for: saveOperation, delegate: delegate, didSave: didSaveSelector, contextInfo: contextInfo)
                return
//            }
        }
        
        if (!self.needSaveWatermark()) {
            self._km_runModalSavePanel(for: saveOperation, delegate: delegate, didSave: didSaveSelector, contextInfo: contextInfo)
            return
        }
        self._km_saveForWatermark { [unowned self] needSave, _ in
            if (needSave) {
                self._km_runModalSavePanel(for: saveOperation, delegate: delegate, didSave: didSaveSelector, contextInfo: contextInfo)
            }
        }
    }
    
    override func save(_ sender: Any?) {
        if (!self.needSaveWatermark()) {
            self._km_save(sender)
            return
        }
        self._km_saveForWatermark { [unowned self] in
            self.trackEvents()
        } callback: { [unowned self] needSave, _ in
            if (needSave) {
                self._km_save(sender)
            }
        }
    }
    
    func saveForWatermark() {
        if (!self.needSaveWatermark()) {
            self._km_save(nil)
            return
        }
        
        self._km_saveForWatermark { [unowned self] in
            self.trackEvents()
        } callback: { [unowned self] needSave, params in
            if (needSave) {
                self._km_save(nil)
            } else { // 水印保存
                if (self.watermarkSaveDelegate == nil) {
                    if let data = params.first as? KMResult, data == .cancel {
                        if let shouldClose = params.last as? Bool, shouldClose {
                            DispatchQueue.main.async {
                                self.mainViewController?.browserWindowController?.browser.windowDidBeginToClose()
                            }
                        }
                    } else {
                        DispatchQueue.main.async {
                            self.mainViewController?.browserWindowController?.browser.windowDidBeginToClose()
                        }
                    }
                    return
                }
                if let data = params.first as? KMResult, data == .cancel {
                    if var shouldClose = params.last as? Bool {
                        if let _browser = self.watermarkSaveDelegate as? KMBrowser, _browser.isCloseAllTabViewItem {
                            shouldClose = true
                        }
                        (self.watermarkSaveDelegate as? KMBrowser)?.document(self, shouldClose: shouldClose, contextInfo: nil)
                    }
                } else {
                    (self.watermarkSaveDelegate as? KMBrowser)?.document(self, shouldClose: true, contextInfo: nil)
                }
                self.watermarkSaveDelegate = nil
            }
        }
    }
    
    override func read(from absoluteURL: URL, ofType typeName: String) throws {
        do {
            try super.read(from: absoluteURL, ofType: typeName)
            updateChangeCount(.changeCleared)
        } catch let outError {
            Swift.print(outError)
        }
    }
    
    override func read(from data: Data, ofType typeName: String) throws {
        // Insert code here to read your document from the given data of the specified type, throwing an error in case of failure.
        // Alternatively, you could remove this method and override read(from:ofType:) instead.  If you do, you should also override isEntireFileLoaded to return false if the contents are lazily loaded.
        
        let pdfDocument = CPDFDocument.init(data: data)
        if pdfDocument == nil {
            throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil)
        }
    }
    
    // MARK: Autosaving
    
    override func close() {
        if self.isActive {
            if browser != nil {
                var activeIndex = 0
                let dex = browser.index(of: self)
                if dex == browser.tabCount() - 1 {
                    activeIndex = Int(browser.tabCount()-2)
                } else {
                    activeIndex = Int(dex + 1)
                }
                let activeContents = browser.tabContents(at: Int32(activeIndex))
                activeContents?.addWindowController(browser.windowController)
            }
        }
        super.close()
    }
    

    // MARK: init
    override init() {
        super.init()
        // Add your subclass-specific initialization here.
        
        NotificationCenter.default.addObserver(self, selector: #selector(pdfChangedNotification(_:)), name: NSNotification.Name.init(rawValue: "CPDFListViewAnnotationsAttributeHasChangeNotification"), object: nil)
//        NotificationCenter.default.addObserver(self, selector: #selector(pdfChangedNotification(_:)), name: NSNotification.Name.init(rawValue: "CPDFViewDocumentChangedNotification"), object: nil)
//        NotificationCenter.default.addObserver(self, selector: #selector(pdfChangedNotification(_:)), name: NSNotification.Name.init(rawValue: "CPDFViewPageChangedNotification"), object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(pdfChangedNotification(_:)), name: NSNotification.Name.init(rawValue: "CPDFListViewDidAddAnnotationNotification"), object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(pdfChangedNotification(_:)), name: NSNotification.Name.init(rawValue: "CPDFListViewDidRemoveAnnotationNotification"), object: nil)
    }

    override init?(baseTabContents baseContents: CTTabContents?) {
        super.init(baseTabContents: baseContents)
        if isHome {
            homeViewController = KMHomeViewController.init()
            homeViewController?.myDocument = self
            self.view = homeViewController?.view
        }
    }
    
    // MARK: Handling User Actions
    
    override var title: String? {
        get {
            if isHome {
                if (self.isNewTab) {
                    return NSLocalizedString("New Tab", comment: "")
                } else {
                    return NSLocalizedString("Home", comment: "")
                }
            } else {
                return fileURL?.lastPathComponent
            }
        }
        set {
            super.title = newValue
        }
    }
    
    func needSaveWatermark() -> Bool {
        if let need = self.mainViewController?.saveWatermarkFlag {
            return need
        }
        return false
    }
    
    // MARK: Private Methods

    func pdfChangedNotification(_ notification: Notification) -> Void {
        if !isHome {
            let mainViewController = mainViewController
            var document: CPDFDocument!
            
            let dic = notification.object as? NSDictionary
            if dic?["object"] is CPDFAnnotation {
                let annotation : CPDFAnnotation = dic?["object"] as? CPDFAnnotation ?? CPDFAnnotation()
                document = annotation.page.document

            } else if dic?["object"] is CPDFListView {
                let pdflistView = notification.object as? CPDFListView
                document = pdflistView?.document
            }
            
            if mainViewController != nil {
                if document == mainViewController!.document {
                    updateChangeCount(.changeDone)
                }
            }
        }
    }
    
    override func updateChangeCount(_ change: NSDocument.ChangeType) {
        let mainWindow = NSApp.mainWindow
        var currentWindowController: KMBrowserWindowController?
        if mainWindow != nil {
            let windowController = mainWindow!.windowController
            if windowController is KMBrowserWindowController {
                currentWindowController = (windowController as! KMBrowserWindowController)
            } else {
                for window in NSApp.windows {
                    let windowController = window.windowController
                    if windowController is KMBrowserWindowController {
                        currentWindowController = (windowController as! KMBrowserWindowController)
                        break
                    }
                }
            }
        } else {
            for window in NSApp.windows {
                let windowController = window.windowController
                if windowController is KMBrowserWindowController {
                    currentWindowController = (windowController as! KMBrowserWindowController)
                    break
                }
            }
        }
        if currentWindowController != nil {
            if currentWindowController?.browser != nil {

                let activeBrowser = (currentWindowController?.browser.activeTabContents())! as CTTabContents
                let activeIndex = Int((currentWindowController?.browser.activeTabIndex())!)
                if self == activeBrowser {
                    super.updateChangeCount(change)
                    return
                }
            }
        }

        super.updateChangeCount(.changeCleared)
    }

    func uploadToCloud(_ callback: (@escaping(Bool, String)->())) {
        guard let handdler = self.cloudUploadHanddler else {
            return
        }
        
        handdler(callback)
    }
    
    func isPDFDocument() -> Bool {
        return true
    }
    
    func setDataFromTmpData() {
        guard let _document = self.mainViewController?.document else {
            return
        }
//        self.tryToUnlockDocument(document!)
        if (_document.permissionsStatus != .owner) {
            var password: NSString? = nil
            let fileId = self.fileId(for: _document)
            if (fileId.isEmpty) {
                return
            }
            self.getPassword(&password, fileId: fileId)
            if (password != nil) {
                self.isUnlockFromKeychain = true
//                document.unlock(withPassword: password! as String)
                self.mainViewController?.password = password as String?
            }
        }
    }
    
    func tryToUnlockDocument(_ document: CPDFDocument) {
        if (document.permissionsStatus != .owner) {
            var password: NSString? = nil
            let fileId = self.fileId(for: document)
            if (fileId.isEmpty) {
                return
            }
            self.getPassword(&password, fileId: fileId)
            if (password != nil) {
                self.isUnlockFromKeychain = true
                document.unlock(withPassword: password! as String)
            }
        }
    }
    
    func km_updateChangeCount(_ change: NSDocument.ChangeType) {
        super.updateChangeCount(change)
    }
    
    func trackEvents() {
        km_synchronized(self) {
            for i in self._trackEvents {
                if let type = KMSubscribeWaterMarkType(rawValue: i) {
                    KMTools.trackEvent(type: type)
                }
            }
        }
        
        self.clearTrackEvents()
    }
    
    func recordTrackEvent(type: KMSubscribeWaterMarkType) {
        if (type == .none) {
            return
        }
        
        km_synchronized(self) {
            self._trackEvents.insert(type.rawValue)
        }
    }
    
    func clearTrackEvents() {
        km_synchronized(self) {
            self._trackEvents.removeAll()
        }
    }
    
    // MARK: - Private Methods
    
    private func _km_write(to url: URL, ofType typeName: String, for saveOperation: NSDocument.SaveOperationType, originalContentsURL absoluteOriginalContentsURL: URL?) throws {
        var success = true
        if !self.isHome {
            if mainViewController != nil {
                if mainViewController?.document != nil {
                    self.mainViewController?.commitEditingIfNeed()
                    
//                    if mainViewController!.document!.isEncrypted {
//                        success = mainViewController!.document!.write(to: url)
//                    } else {
                        if (mainViewController!.needSave) {
                            if let options = self.mainViewController?.secureOptions, !options.isEmpty {
                                success = self.mainViewController!.document!.write(to: url, withOptions: options)
                            } else if let flag = self.mainViewController?.removeSecureFlag, flag {
                                success = self.mainViewController!.document!.writeDecrypt(to: url)
                            } else {
                                success = mainViewController!.document!.write(to: url)
                            }
                        } else {
                            success = mainViewController!.document!.write(to: url)
                        }
//                    }
                    self.mainViewController?.needSave = false
                    self.mainViewController?.clearSecureOptions()
                    self.mainViewController?.clearRemoveSecureFlag()
                }
            }
        } else {
            success = false
        }
        
        if (success && self._saveAsing) {
            if let tabView = self.browser?.windowController?.tabStripController?.activeTabView() as? CTTabView {
                tabView.controller()?.title = url.lastPathComponent
            }
            self._saveAsing = false
        }
        
        if success && isNewCreated && NSDocument.SaveOperationType.saveAsOperation == saveOperation {
            isNewCreated = false
        }
    }
    
    private func _km_saveForWatermark(openAccessoryView: Bool = true, subscribeDidClick: (()->Void)? = nil, callback:@escaping (_ needSave: Bool, _ param: Any...)->Void) {
        Task { @MainActor in
            if await (KMLightMemberManager.manager.canPayFunction() == false) {
                let _ = KMSubscribeWaterMarkWindowController.show(window: NSApp.mainWindow!, isContinue:false, type: .save) {
                    if let _callback = subscribeDidClick {
                        _callback()
                    }
                } completion: { isSubscribeSuccess, isWaterMarkExport, isClose in
                    if (isClose) {
                        callback(false, KMResult.cancel, false)
                        return
                    }
                    
                    if (isSubscribeSuccess) {
                        callback(true)
                        return
                    }
                    
                    if (isWaterMarkExport) {
                        guard let _document = self.mainViewController?.document else {
                            callback(false, KMResult.failure)
                            return
                        }
                        // 提交文本编辑的内容
                        self.mainViewController?.commitEditingIfNeed()
                        DispatchQueue.main.async {
                            NSPanel.savePanel(NSApp.mainWindow!, openAccessoryView, panel:{ panel in
                                if (!self.isNewCreated) {
                                    panel.directoryURL = _document.documentURL.deletingLastPathComponent()
                                }
                                
                                panel.nameFieldStringValue = _document.documentURL.lastPathComponent
                            }) { response, url, isOpen in
                                if (response == .cancel) {
                                    callback(false, KMResult.cancel, true)
                                    return
                                }
                                guard let _url = KMTools.saveWatermarkDocument(document: _document, to: url!, secureOptions: self.mainViewController?.secureOptions, removePWD: self.mainViewController!.removeSecureFlag) else {
                                    callback(false, KMResult.failure)
                                    return
                                }
                                callback(false, KMResult.success)
                                if (isOpen) {
                                    NSDocumentController.shared.km_safe_openDocument(withContentsOf: _url, display: true) { _, _, _ in
                                        
                                    }
                                } else {
                                    NSWorkspace.shared.activateFileViewerSelecting([_url])
                                }
                            }
                        }
                        return
                    }
                    callback(false, KMResult.cancel, false)
                }
                return
            }
            callback(true)
        }
    }
    
    private func _km_save(_ sender: Any?) {
        super.save(sender)
    }
    
    private func _km_save(to url: URL, ofType typeName: String, for saveOperation: NSDocument.SaveOperationType, delegate: Any?, didSave didSaveSelector: Selector?, contextInfo: UnsafeMutableRawPointer?) {
        self._saveToURL = url
        super.save(to: url, ofType: typeName, for: saveOperation, delegate: delegate, didSave: didSaveSelector, contextInfo: contextInfo)
    }
    
    private func _km_saveAs(_ sender: Any?) {
        super.saveAs(sender)

        self._saveAsing = true
    }
    
    private func _km_runModalSavePanel(for saveOperation: NSDocument.SaveOperationType, delegate: Any?, didSave didSaveSelector: Selector?, contextInfo: UnsafeMutableRawPointer?) {
        super.runModalSavePanel(for: saveOperation, delegate: delegate, didSave: didSaveSelector, contextInfo: contextInfo)
    }
}

extension KMMainDocument {
    override func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
        if (menuItem.action == #selector(save(_ :))) {
            if (self.isHome) {
                return false
            }
            if (self.isDocumentEdited) {
                return self.isDocumentEdited
            }
            
            guard let mainVC = self.mainViewController else {
                return false
            }
            return mainVC.isPDFDocumentEdited || mainVC.needSave
        } else if (menuItem.action == #selector(saveAs(_ :))) {
            return !self.isHome
        }
        return super.validateMenuItem(menuItem)
    }
}

extension NSDocument {
    @objc class func isDamage(url: URL) -> Bool {
        // 文件路径是否存在
        if (FileManager.default.fileExists(atPath: url.path) == false) {
            return true
        }
        
        /// PDF 格式文件
        if (url.pathExtension.lowercased() == "pdf") {
            let document = PDFDocument(url: url)
            if (document == nil) {
                return true
            }
            
            if (document!.isLocked) { // 加锁文件不在这里判断
                return false
            }
            
            if (document!.pageCount <= 0) {
                return true
            }
            return false
        }
        
        // 支持的图片格式
        let imageExts = ["jpg","cur","bmp","jpeg","gif","png","tiff","tif","ico","icns","tga","psd","eps","hdr","jp2","jpc","pict","sgi","heic"]
        let isImage = imageExts.contains(url.pathExtension.lowercased())
        if (isImage == false) { // 其他格式目前返回没损坏,后续再补充(如果有需求)
            return false
        }
        
        // 图片格式
        let image = NSImage(contentsOf: url)
        let data = image?.tiffRepresentation
        if (data == nil) {
            return true
        }
        let imageRep = NSBitmapImageRep(data: data!)
        imageRep!.size = image!.size
        var imageData: NSData?
        if (url.pathExtension.lowercased() == "png") {
            imageData = imageRep?.representation(using: .png, properties: [:]) as NSData?
        } else {
            imageData = imageRep?.representation(using: .jpeg, properties: [:]) as NSData?
        }
        if (imageData == nil) {
            return true
        }
        
        let path = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last?.stringByAppendingPathComponent(Bundle.main.bundleIdentifier!)
        if (FileManager.default.fileExists(atPath: path!) == false) {
            try?FileManager.default.createDirectory(atPath: path!, withIntermediateDirectories: false)
        }
        
        var tagString: String = ""
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyMMddHHmmss"
        tagString.append(dateFormatter.string(from: Date()))
        tagString = tagString.appendingFormat("%04d", arc4random()%10000)
        let filePath = path?.appending("/\(tagString).png")
        if (imageData!.write(toFile: filePath!, atomically: true) == false) {
            return true
        }
        
        // 删除临时图片
        try?FileManager.default.removeItem(atPath: filePath!)
        
        return false
    }
    
    @objc class func isDamage(url: URL, needAlertIfDamage need: Bool) -> Bool {
        let result = self.isDamage(url: url)
        if (result == false) {
            return false
        }
        
        if (need == false) {
            return true
        }
        
        let alert = NSAlert()
        alert.messageText = NSLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "")
        alert.runModal()
        return true
    }
}

// MARK: -
// MARK: 保存密码
extension NSDocument {
    func savePasswordInKeychain(_ password: String, _ document: CPDFDocument) {
        if (document.isLocked || password.isEmpty) {
            return
        }
        
        let fileId = self.fileId(for: document)
        if (fileId.isEmpty) {
            return
        }
        
//        let status: SKPasswordStatus =
        let label = "PDF Master: \(self.displayName!)"
        SKKeychain.setPassword(password, item: nil, forService: self.passwordServiceName(), account: fileId, label: label, comment: self.fileURL?.path)
    }
    
    func getPassword(_ password: AutoreleasingUnsafeMutablePointer<NSString?>, fileId: String) {
        let status = SKKeychain.getPassword(password, item: nil, forService: self.passwordServiceName(), account: fileId)
//        if (status == .found) {
            
//        }
    }
    
    fileprivate func fileId(for document: CPDFDocument) -> String {
        return "\(document.documentURL.path.hash)"
    }
    
    private func passwordServiceName() -> String {
        return "PDF Master password"
    }
}