//
//  KMTools.swift
//  PDF Reader Pro
//
//  Created by tangchao on 2023/3/7.
//

import Cocoa

@objc class KMTools: NSObject {
    // MARK: - 获取已打开的文件
    
    @objc class func getOpenDocumentURLs() -> [URL] {
        var files:[URL] = []
        for window in NSApp.windows {
            if ((window.windowController is KMBrowserWindowController) == false) {
                continue
            }
            
            let controller: KMBrowserWindowController = window.windowController as! KMBrowserWindowController
            let model = controller.browser?.tabStripModel
            guard let count = model?.count() else {
                continue
            }
            
            if (count <= 0) {
                continue
            }
            
            for i in 0 ..< count {
                let document = model?.tabContents(at: Int32(i))
//                if (document?.windowControllers == nil || document?.windowControllers.count == 0) {
//                    continue
//                }
                if (document?.fileURL == nil) {
                    continue
                }
                
                if (document?.isHome == nil || document!.isHome) {
                    continue
                }
                
                files.append((document?.fileURL)!)
            }
        }
        return files
    }
    
    // MARK: - 无法区分 [权限+开启] [开启] 这两种情况 请不要使用
    
    private class func isDocumentHasPermissionsPassword(_ url: URL) -> Bool {
        let document = PDFDocument(url: url)
        if (document == nil) {
            return false
        }
        
        if (document?.permissionsStatus == .user) {
            return true
        }
        
        // document?.permissionsStatus == .none
        if (document!.isLocked == false) { // 没有加锁
            return false
        }
        
        // 已加锁 [权限+开启] [开启]
        if (KMTools.hasPermissionsLimit(document!)) { // 有权限限制
            return true
        }
        
        return false
    }
    
    // MARK: - 暂时只处理了复制和打印两项(后续项目需求有新增时,可以再此方法里扩展)
    
    @objc class func hasPermissionsLimit(_ document: PDFDocument) -> Bool {
        if (document.allowsCopying == false) {
            return true
        }
        if (document.allowsPrinting == false) {
            return true
        }
        return false
    }
    
    // MARK: - 打开网页
    
    @objc class func openURL(url: URL?) {
        guard let _url = url else {
            KMPrint("url invalid.")
            return
        }
        NSWorkspace.shared.open(_url)
    }
    
    @objc class func openURL(urlString: String?) {
        guard let _urlString = urlString else {
            KMPrint("url invalid.")
            return
        }
        
        KMTools.openURL(url: URL(string: _urlString))
    }
    
    // MARK: - 查看文件
    @objc class func viewFile(at filepath: String) {
        let ws = NSWorkspace.shared
        let url = URL(fileURLWithPath: filepath)
        ws.activateFileViewerSelecting([url])
    }
    
    // MARK: - 获取 App 版本号
    @objc class func getAppVersion() -> String {
        let infoDictionary = Bundle.main.infoDictionary
        if (infoDictionary == nil) {
            return "1.0.0"
        }
        
        var version = infoDictionary!["CFBundleShortVersionString"]
        if (version != nil && (version is String) && (version as! String).isEmpty == false) {
            return version as! String
        }
        
        version = infoDictionary!["CFBundleVersion"]
        if (version != nil && (version is String) && (version as! String).isEmpty == false) {
            return version as! String
        }
        
        return "1.0.0"
    }
    
    class func getSystemVersion() -> (Int, Int, Int) {
        let versionInfo = ProcessInfo.processInfo.operatingSystemVersion
        return (versionInfo.majorVersion, versionInfo.minorVersion, versionInfo.patchVersion)
    }
    
    @objc class func isDefaultPDFReader() -> Bool {
        let app = LSCopyDefaultRoleHandlerForContentType("pdf" as CFString, LSRolesMask.all)?.takeUnretainedValue()
        if (app == nil) {
            return false
        }
        
        return (app! as String) == Bundle.main.bundleIdentifier!
    }
    
    @objc class func setDefaultPDFReader(_ isOrNo: Bool) -> Bool {
        var bid = "com.apple.Preview"
        if (isOrNo) {
            bid = Bundle.main.bundleIdentifier!
        }
        let status: OSStatus = LSSetDefaultRoleHandlerForContentType(KMTools.UTIforFileExtension("pdf") as CFString, LSRolesMask.all, bid as CFString)
        if (status == 0) {
            return true
        }
        return false
    }
    
    @objc class func UTIforFileExtension(_ exn: String) -> String {
        return (UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, exn as CFString, nil)?.takeUnretainedValue())! as String
    }
    
    // MARK: - 是否全屏
    
    @objc class func isFullScreen(_ window: NSWindow) -> Bool {
        return window.styleMask.contains(.fullScreen)
    }
    
    // MARK: - 文件类型
    
    static let imageExtensions = ["jpg","cur","bmp","jpeg","gif","png","tiff","tif",/*@"pic",*/"ico","icns","tga","psd","eps","hdr","jp2","jpc","pict","sgi","heic"]
    static let pdfExtensions = ["pdf"]
    static let officeExtensions = ["doc", "docx", "xls", "xlsx", "ppt", "pptx"]
    
    @objc class func isImageType(_ exn: String) -> Bool {
        return KMTools.imageExtensions.contains(exn.lowercased())
    }
    
    @objc class func isPDFType(_ exn: String) -> Bool {
        return KMTools.pdfExtensions.contains(exn.lowercased())
    }
    
    @objc class func isOfficeType(_ exn: String) -> Bool {
        return KMTools.officeExtensions.contains(exn.lowercased())
    }
    
    @objc class func getUniqueFilePath(filePath: String) -> String {
        var isDirectory: ObjCBool = false
        var uniqueFilePath = filePath
        let fileManager = FileManager.default
        fileManager.fileExists(atPath: uniqueFilePath, isDirectory: &isDirectory)
        
        var i = 0
        if (isDirectory.boolValue) {
            while fileManager.fileExists(atPath: uniqueFilePath) {
                i += 1
                uniqueFilePath = "\(filePath)(\(i))"
            }
        } else {
            let fileURL = URL(fileURLWithPath: filePath)
            let path = fileURL.deletingPathExtension().path
            while fileManager.fileExists(atPath: uniqueFilePath) {
                i += 1
                uniqueFilePath = "\(path)(\(i)).\(fileURL.pathExtension)"
            }
        }
        return uniqueFilePath
    }
    
    @objc class func getTempFloderPath() -> String? {
        return self.getTempRootPath()?.stringByAppendingPathComponent("KMTemp")
    }
    
    @objc class func getTempRootPath() -> String? {
        return NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last?.stringByAppendingPathComponent(Bundle.main.bundleIdentifier!)
    }
    
    // MARK: - Document isDocumentEdited
    
    @objc class func setDocumentEditedState(window: NSWindow) {
        guard let _document = NSDocumentController.shared.document(for: window) else {
            return
        }
        
        self.setDocumentEditedState(document: _document)
    }
    
    @objc class func setDocumentEditedState(url: URL) {
        guard let _document = NSDocumentController.shared.document(for: url) else {
            return
        }
        
        self.setDocumentEditedState(document: _document)
    }
    
    @objc class func setDocumentEditedState(document: NSDocument) {
        km_synchronized(document) {
            document.updateChangeCount(.changeDone)
        }
    }
    
    @objc class func clearDocumentEditedState(window: NSWindow) {
        guard let _document = NSDocumentController.shared.document(for: window) else {
            return
        }
        
        self.clearDocumentEditedState(document: _document)
    }
    
    @objc class func clearDocumentEditedState(url: URL) {
        guard let _document = NSDocumentController.shared.document(for: url) else {
            return
        }
        
        self.clearDocumentEditedState(document: _document)
    }
    
    @objc class func clearDocumentEditedState(document: NSDocument) {
        km_synchronized(document) {
            document.updateChangeCount(.changeCleared)
        }
    }
    
    // MARK: - 解析 [1-3,5-7]
    
    @objc class func parseIndexSet(indexSet: IndexSet) -> String {
        return self.parseIndexs(indexs: indexSet.sorted())
    }
    
    @objc class func parseIndexs(indexs: [Int]) -> String {
        if (indexs.isEmpty) {
            return ""
        }
        if (indexs.count == 1) {
            return "\(indexs.first!+1)"
        }
        
        var sortArray: [Int] = []
        for i in indexs {
            sortArray.append(i)
        }
        /// 排序 (升序)
        sortArray.sort(){$0 < $1}
        
        var a: Int = 0
        var b: Int = 0
        var result: String?
        for i in sortArray {
            if (result == nil) {
                a = i
                b = i
                result = ""
                continue
            }
            if (i == b+1) {
                b = i
                if (i == sortArray.last) {
                    result?.append(String(format: "%d-%d", a+1,b+1))
                }
            } else {
                if (a == b) {
                    result?.append(String(format: "%d,", a+1))
                } else {
                    result?.append(String(format: "%d-%d,", a+1,b+1))
                }
                a = i
                b = i
                if (i == sortArray.last) {
                    result?.append(String(format: "%d", a+1))
                }
            }
        }
        return result ?? ""
    }
}

// MARK: - PDFReaderPro

let kKMPurchaseProductURLString = "https://www.anyrecover.com/buy-pdf-editor-reader-converter"

extension KMTools {
    // 打开 [快速教学]
    @objc class func openQuickStartStudy() {
        // MARK: -
        // MARK: 内嵌文档需要替换
        var fileName = "Quick Start Guide"
        let fileType = "pdf"
        
        let path = Bundle.main.path(forResource: fileName, ofType: fileType)
        if (path == nil || FileManager.default.fileExists(atPath: path!) == false) {
            KMTools.openURL(url: URL(string: "https://www.pdfreaderpro.com/help"))
            return
        }
        
        let version = KMTools.getAppVersion()
        fileName.append(" v\(version).\(fileType)")
        
        let folderPath = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last?.appending("/\(Bundle.main.bundleIdentifier!)")
        if (FileManager.default.fileExists(atPath: folderPath!) == false) {
            try?FileManager.default.createDirectory(atPath: folderPath!, withIntermediateDirectories: false)
        }
        
        let toPath = "\(folderPath!)/\(fileName)"
        if (FileManager.default.fileExists(atPath: toPath)) {
            try?FileManager.default.removeItem(atPath: toPath)
        }
        try?FileManager.default.copyItem(atPath: path!, toPath: toPath)
        
        NSDocumentController.shared.km_safe_openDocument(withContentsOf: URL(fileURLWithPath: toPath), display: true) { _, _, _ in
            
        }
    }
    
    // 打开 [FAQ] 网站
    @objc class func openFAQWebsite() {
        var tStrUrl: String?
        tStrUrl = "https://www.anyrecover.com/support/"
        KMTools.openURL(urlString: tStrUrl)
    }
    
    // 打开 [更多产品] 网站
    @objc class func openMoreProductWebsite() {
        var tStrUrl: String?
        if KMKdanRemoteConfig.remoteConfig.showHelp_More_RecommendLink() {
    #if VERSION_FREE
            tStrUrl = "https://www.pdfreaderpro.com/product?utm_source=MacAppLite&utm_campaign=ProductLink&utm_medium=PdfProduct"
    #else
            tStrUrl = "https://www.pdfreaderpro.com/product?utm_source=MacApp&utm_campaign=ProductLink&utm_medium=PdfProduct"
    #endif
        } else {
            tStrUrl = "https://apps.apple.com/developer/pdf-technologies-inc/id1263126485"
        }
    #if VERSION_DMG
        tStrUrl = "https://www.pdfreaderpro.com/product?utm_source=MacAppDmg&utm_campaign=ProductLink&utm_medium=PdfProduct"
    #endif
        
        KMTools.openURL(urlString: tStrUrl)
    }
    
    // 打开 [免费 PDF 模板] 网站
    @objc class func openFreePDFTemplatesWebsite() {
        var tStrUrl: String?
    #if VERSION_FREE
    #if VERSION_DMG
        tStrUrl = "https://www.pdfreaderpro.com/templates?utm_source=MacAppDmg&utm_campaign=TemplatesLink&utm_medium=PdfTemplates"
    #else
        tStrUrl = "https://www.pdfreaderpro.com/templates?utm_source=MacAppLite&utm_campaign=TemplatesLink&utm_medium=PdfTemplates"
    #endif
    #else
        tStrUrl = "https://www.pdfreaderpro.com/templates?utm_source=MacApp&utm_campaign=TemplatesLink&utm_medium=PdfTemplates"
    #endif
        KMTools.openURL(urlString: tStrUrl)
    }
    
    // 打开 [ComPDFKit 授权] 网站
    @objc class func openComPDFKitPowerWebsite() {
        KMTools.openURL(url: URL(string: "https://www.compdf.com?utm_source=macapp&utm_medium=pdfmac&utm_campaign=compdfkit-promp"))
    }
    
    // 打开 [官网 下载页] 网站
    // 测试环境 http://test-pdf-pro.kdan.cn:3021/pdf-master-mac-download
    @objc class func openDownloadDMGWebsite() {
        KMTools.openURL(urlString: "https://www.pdfreaderpro.com/pdf-master-mac-download")
    }
    
    @objc class func openPurchaseProductWebsite() {
        KMTools.openURL(urlString: kKMPurchaseProductURLString)
    }
    
    // 意见反馈
    @objc class func feekback() {
        let (major, minor, bugFix) = KMTools.getSystemVersion()
        let versionInfoString = "\(KMTools.getRawSystemInfo()) - \(major).\(minor).\(bugFix)"
        
        let appVersion = KMTools.getAppVersion()
        let appName = KMTools.getAppNameForSupportEmail()
        let subjects = "\(appName) - \(appVersion);\(NSLocalizedString("Feedback", comment: ""));\(versionInfoString)"
        let email = "support@anyrecover.com"
        
        KMMailHelper.newEmail(withContacts: email, andSubjects: subjects)
    }
    
    //
    @objc class func reportBug() {
        let (major, minor, bugFix) = KMTools.getSystemVersion()
        let versionInfoString = "\(KMTools.getRawSystemInfo()) - \(major).\(minor).\(bugFix)"
        
        let appVersion = KMTools.getAppVersion()
        let appName = KMTools.getAppNameForSupportEmail()
        let subjects = "\(appName) - \(appVersion);\(NSLocalizedString("Report a Bug", comment: ""));\(versionInfoString)"
        let email = "support@anyrecover.com"
        
        KMMailHelper.newEmail(withContacts: email, andSubjects: subjects)
    }
    
    //
    @objc class func proposeNewFeature() {
        let (major, minor, bugFix) = KMTools.getSystemVersion()
        let versionInfoString = "\(KMTools.getRawSystemInfo()) - \(major).\(minor).\(bugFix)"
        
        let appVersion = KMTools.getAppVersion()
        let appName = KMTools.getAppNameForSupportEmail()
        let subjects = "\(appName) - \(appVersion);\(NSLocalizedString("Propose a New Feature", comment: ""));\(versionInfoString)"
        let email = "support@anyrecover.com"
        
        KMMailHelper.newEmail(withContacts: email, andSubjects: subjects)
    }
    
    //
    @objc class func reportGeneralQuestions() {
        let (major, minor, bugFix) = KMTools.getSystemVersion()
        let versionInfoString = "\(KMTools.getRawSystemInfo()) - \(major).\(minor).\(bugFix)"
        
        let appVersion = KMTools.getAppVersion()
        let appName = KMTools.getAppNameForSupportEmail()
        let subjects = "\(appName) - \(appVersion);\(NSLocalizedString("General Questions", comment: ""));\(versionInfoString)"
        let email = "support@anyrecover.com"
        
        KMMailHelper.newEmail(withContacts: email, andSubjects: subjects)
    }
    
    @objc class func rateUs() {
#if VERSION_FREE
        iRate.sharedInstance().appStoreID = 919472673
#else
        iRate.sharedInstance().appStoreID = 825459243
#endif
        
        if UserDefaults.standard.bool(forKey: "kUserHaveClickRateUsKey") == false {
            UserDefaults.standard.set(true, forKey: "kUserHaveClickRateUsKey")
            UserDefaults.standard.synchronize()
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: "kUserHaveClickRateUsNotification"), object: self)
    }
        iRate.sharedInstance().openRatingsPageInAppStore()
    }
    
    @objc class func getAppNameForSupportEmail() -> String {
        var tAppName = "PDFull"
    #if VERSION_FREE

    #if VERSION_DMG
        
    #if VERSION_BETA
        tAppName = "PDF Reader Pro Beta"
    #endif
        
        // 桌机版
        if let tManager = VerificationManager.default() {
            let status = tManager.status
            if status == ActivityStatusTrial {
                tAppName = "\(tAppName) Trial"
            } else if status == ActivityStatusVerification {
                tAppName = "\(tAppName) Verification"
            } else if status == ActivityStatusTrialExpire {
                tAppName = "\(tAppName) TrialExpire"
            } else if status == ActivityStatusVerifExpire {
                tAppName = "\(tAppName) VerifExpire"
            }
        }
    #else
        
        // AppStore 免费版本
        tAppName = "PDF Reader Pro Lite"
    #endif
        
    #else
        
        // AppStore 付费版
        tAppName = "PDF Reader Pro Edition"
    #endif
        
        return tAppName
    }
    
    @objc class func getRawSystemInfo() -> String {
        let info = GBDeviceInfo.deviceInfo().rawSystemInfoString
        if (info == nil) {
            return ""
        }
        return info!
    }
    
    @objc class func getAppName() -> String {
        return "PDFull"
    }
    
    @objc class func pageRangeTypeString(pageRange: KMPageRange) -> String {
        switch pageRange {
        case .all:
            return NSLocalizedString("All Pages", comment: "")
        case .current:
            return NSLocalizedString("Current Page", comment: "")
        case .odd:
            return NSLocalizedString("Odd Pages", comment: "")
        case .even:
            return NSLocalizedString("Even Pages", comment: "")
        case .custom:
            return NSLocalizedString("Customize", comment: "")
        case .horizontal:
            return NSLocalizedString("Horizontal Pages", comment: "")
        case .vertical:
            return NSLocalizedString("Vertical Pages", comment: "")
        }
    }
    
    @objc class func pageRangePlaceholderString() -> String {
        return NSLocalizedString("e.g. 1,3-5,10", comment: "")
    }
    
    @objc class func saveWatermarkDocumentToTemp(document: CPDFDocument, secureOptions: [CPDFDocumentWriteOption : Any]? = nil, removePWD: Bool = false) -> URL? {
        // 将文档存入临时目录
        if let data = self.getTempFloderPath(), !FileManager.default.fileExists(atPath: data) {
            try?FileManager.default.createDirectory(atPath: data, withIntermediateDirectories: false)
        }
        guard let filePath = self.getTempFloderPath()?.stringByAppendingPathComponent("temp_saveDocumentFor_temp.pdf") else {
            return nil
        }
        // 清除临时数据
        if (FileManager.default.fileExists(atPath: filePath)) {
            try?FileManager.default.removeItem(atPath: filePath)
        }
        
        return self.saveWatermarkDocument(document: document, to: URL(fileURLWithPath: filePath), secureOptions: secureOptions, removePWD:  removePWD)
    }
    
    @objc class func saveWatermarkDocument(document: CPDFDocument, to url: URL, secureOptions: [CPDFDocumentWriteOption : Any]? = nil, documentAttribute: [CPDFDocumentAttribute : Any]? = nil, removePWD: Bool = false) -> URL? {
        guard let _document = self._saveDocumentForWatermark(document: document) else {
            return nil
        }
        
        // 保存文档
        if let data = secureOptions, !data.isEmpty {
            _document.setDocumentAttributes(documentAttribute)
            _document.write(to: url, withOptions: data)
        } else if (removePWD) {
            _document.writeDecrypt(to: url)
        } else {
            _document.write(to: url)
        }
        // 清除临时数据
        if let _fileUrl = _document.documentURL, FileManager.default.fileExists(atPath: _fileUrl.path) {
            try?FileManager.default.removeItem(atPath: _fileUrl.path)
        }
        
        return url
    }
    
    @objc class func saveWatermarkDocumentForCompress(document: CPDFDocument, to url: URL, imageQuality: Int) -> URL? {
        guard let _document = self._saveDocumentForWatermark(document: document) else {
            return nil
        }
        
//        _document.write(to: _document.documentURL)

        // 保存文档
        let result = _document.writeOptimize(to: url, withOptions: [.imageQualityOption : imageQuality])
        // 清除临时数据
        if let _fileUrl = _document.documentURL, FileManager.default.fileExists(atPath: _fileUrl.path) {
            try?FileManager.default.removeItem(atPath: _fileUrl.path)
        }
        
        if (result) {
            return url
        }
        return nil
    }
    
    @objc class func saveWatermarkDocumentForFlatten(document: CPDFDocument, to url: URL) -> URL? {
        guard let _document = self._saveDocumentForWatermark(document: document) else {
            return nil
        }
        
        // 保存文档
        let result = _document.writeFlatten(to: url)
        // 清除临时数据
        if let _fileUrl = _document.documentURL, FileManager.default.fileExists(atPath: _fileUrl.path) {
            try?FileManager.default.removeItem(atPath: _fileUrl.path)
        }
        
        if (result) {
            return url
        }
        return nil
    }
    
    @objc class func saveDocumentToTemp(document: CPDFDocument, fileID: String, needUnlock: Bool = true) -> URL? {
        // 将文档存入临时目录
        if let data = self.getTempFloderPath(), !FileManager.default.fileExists(atPath: data) {
            if let rootPath = self.getTempRootPath(), !FileManager.default.fileExists(atPath: rootPath) {
                try?FileManager.default.createDirectory(atPath: rootPath, withIntermediateDirectories: false)
            }
            try?FileManager.default.createDirectory(atPath: data, withIntermediateDirectories: false)
        }
        guard let filePath = self.getTempFloderPath()?.stringByAppendingPathComponent("temp_saveDocumentFor\(fileID).pdf") else {
            return nil
        }
        // 清除临时数据
        if (FileManager.default.fileExists(atPath: filePath)) {
            try?FileManager.default.removeItem(atPath: filePath)
        }
        
        document.write(toFile: filePath)
        if (!FileManager.default.fileExists(atPath: filePath)) {
            return nil
        }
        
        guard let _document = CPDFDocument(url: URL(fileURLWithPath: filePath)) else {
            return nil
        }
        if (!needUnlock) {
            return _document.documentURL
        }
        
        // 如果加锁,则去解锁
        if let pwd = document.password, !pwd.isEmpty, _document.isLocked {
            _document.unlock(withPassword: document.password)
        }
        if (_document.isLocked) {
            return nil
        }
        return _document.documentURL
    }
    
    @objc class func trackEvent(type: KMSubscribeWaterMarkType) -> Void {
        if (type == .stamp) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_Stamp", parameters: nil, appTarget: .all)
        } else if (type == .link) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_Link", parameters: nil, appTarget: .all)
        } else if (type == .sign) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_Sign", parameters: nil, appTarget: .all)
        } else if (type == .editText) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_EditText", parameters: nil, appTarget: .all)
        } else if (type == .editImage) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_EditImage", parameters: nil, appTarget: .all)
        } else if (type == .insert) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_Insert", parameters: nil, appTarget: .all)
        } else if (type == .extract) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_Extract", parameters: nil, appTarget: .all)
        } else if (type == .replace) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_Replace", parameters: nil, appTarget: .all)
        } else if (type == .split) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_Split", parameters: nil, appTarget: .all)
        } else if (type == .delete) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_Delete", parameters: nil, appTarget: .all)
        } else if (type == .rotate) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_Rotate", parameters: nil, appTarget: .all)
        } else if (type == .copy) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_Copy", parameters: nil, appTarget: .all)
        } else if (type == .toWord) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_ToWord", parameters: nil, appTarget: .all)
        } else if (type == .toExcel) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_ToExcel", parameters: nil, appTarget: .all)
        } else if (type == .toPPT) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_ToPPT", parameters: nil, appTarget: .all)
        } else if (type == .toRTF) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_ToRTF", parameters: nil, appTarget: .all)
        } else if (type == .toCSV) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_ToCSV", parameters: nil, appTarget: .all)
        } else if (type == .toHTML) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_ToHTML", parameters: nil, appTarget: .all)
        } else if (type == .toText) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_ToText", parameters: nil, appTarget: .all)
        } else if (type == .toImage) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_ToImage", parameters: nil, appTarget: .all)
        } else if (type == .compress) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_Compress", parameters: nil, appTarget: .all)
        } else if (type == .merge) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_Merge", parameters: nil, appTarget: .all)
        } else if (type == .setPassword) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_SetPassword", parameters: nil, appTarget: .all)
        } else if (type == .removePassword) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_RemovePassword", parameters: nil, appTarget: .all)
        } else if (type == .crop) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_Crop", parameters: nil, appTarget: .all)
        } else if (type == .aiTranslate) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_AITranslate", parameters: nil, appTarget: .all)
        } else if (type == .aiRewrite) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_AIRewrite", parameters: nil, appTarget: .all)
        } else if (type == .aiCorrect) {
            KMAnalytics.trackEvent(eventName: "PDFReaderPro_Subscribe_AICorrect", parameters: nil, appTarget: .all)
        }
    }
    
    private static var dateFormatter_: DateFormatter?
    @objc class func timeString(timeDate date: Date) -> String {
        if dateFormatter_ == nil {
            dateFormatter_ = DateFormatter()
        }
        let calendar = Calendar.current
        let nowCmps = calendar.dateComponents([.day, .month, .year], from: Date())
        let currentCmps = calendar.dateComponents([.day, .month, .year], from: date)
        if (currentCmps.year == nowCmps.year) {
            if (currentCmps.month == nowCmps.month && currentCmps.day == nowCmps.day) {
                dateFormatter_?.dateFormat = "HH:mm"
            } else {
                dateFormatter_?.dateFormat = "MM-dd, HH:mm"
            }
        } else {
            dateFormatter_?.dateFormat = "yyyy-MM-dd, HH:mm"
        }
        return dateFormatter_?.string(from: date) ?? ""
    }
    
    @objc class func timeString(timeDate date: Date, formatString: String) -> String {
        if dateFormatter_ == nil {
            dateFormatter_ = DateFormatter()
        }
        let calendar = Calendar.current
        let nowCmps = calendar.dateComponents([.day, .month, .year], from: Date())
        let currentCmps = calendar.dateComponents([.day, .month, .year], from: date)
        dateFormatter_?.dateFormat = formatString
        return dateFormatter_?.string(from: date) ?? ""
    }
    
    @objc class func isFileGreaterThan10MB(atPath filePath: String) -> Bool {
        let fileManager = FileManager.default

        do {
            let fileAttributes = try fileManager.attributesOfItem(atPath: filePath)
            if let fileSize = fileAttributes[.size] as? UInt64 {
                let megabyteSize = fileSize / (1024 * 1024)
                return megabyteSize >= 10
            }
        } catch {
            KMPrint("Error: \(error)")
        }

        return false
    }
    
    // MARK: - Private Methods
    
    @objc fileprivate class func _documentAddWatermark(document: CPDFDocument) -> CPDFDocument? {
        // 添加水印
        let watermark = CPDFWatermark(document: document, type: .image)
        watermark?.image = NSImage(named: "KMImageNameWatermark")
        watermark?.horizontalPosition = .left
        watermark?.verticalPosition = .top
        watermark?.scale = 0.5
        document.addWatermark(watermark)
        // 添加 link注释
        var watermarkAnnoBounds = NSMakeRect(0, 0, 120, 32)
        for i in 0 ..< document.pageCount {
            guard let page = document.page(at: i) else {
                continue
            }

            // 水印注释 frame
            watermarkAnnoBounds.origin.y = page.bounds.size.height-watermarkAnnoBounds.size.height
            // 找到需要删除的水印注释(之前添加)
            var flagAnnos: [CPDFAnnotation] = []
            for anno in page.annotations {
                if let anno_link = anno as? CPDFLinkAnnotation, anno_link.url() == kKMPurchaseProductURLString, anno_link.bounds.equalTo(watermarkAnnoBounds) {
                    flagAnnos.append(anno_link)
                }
            }
            // 删除之前的水印注释
            for anno in flagAnnos {
                page.removeAnnotation(anno)
            }
            // 新增新的水印注释
            let anno = CPDFLinkAnnotation(document: document)
            anno?.bounds = watermarkAnnoBounds
            anno?.setURL(kKMPurchaseProductURLString)
            page.addAnnotation(anno)
        }
        return document
    }
    
    @objc fileprivate class func _saveDocumentForWatermark(document: CPDFDocument) -> CPDFDocument? {
        // 将文档存入临时目录
        guard let _fileUrl = self.saveDocumentToTemp(document: document, fileID: "Watermark") else {
            return nil
        }
        guard let _document = CPDFDocument(url: _fileUrl) else {
            return nil
        }
        
        // 如果加锁,则去解锁
        if let pwd = document.password, !pwd.isEmpty, _document.isLocked {
            _document.unlock(withPassword: pwd)
        }
        
        // 添加水印
        return self._documentAddWatermark(document: _document)
    }
}