//
//  KMOCRPDFWindowController.swift
//  PDF Reader Pro
//
//  Created by liujiajie on 2023/11/14.
//

import Cocoa
import PDFKit

class KMOCRPDFWindowController: NSWindowController, NSWindowDelegate, KMGOCRManagerDelegate, NSPopoverDelegate,NSTextFieldDelegate{
    var resultString: String = ""
    var ocrDictionary: NSMutableDictionary?
    var currentIndexPage: Int = 0
//    {
//        didSet {
//            if PDFView.document.pageCount > currentIndexPage {
//                currentIndexPage = 0
//                self.currentPageLabel.stringValue = "\(currentIndexPage + 1)"
//                //                let page = self.PDFView.document.page(at: UInt(currentIndexPage))
//                self.PDFView.go(toPageIndex: currentIndexPage, animated: true)
//            }
//        }
//    }
    var PDFView: CPDFView!
    
    @IBOutlet var prePdfBGView: NSView!
    @IBOutlet var currentPageLabel: NSTextField!
    @IBOutlet var totalPageLabel: NSTextField!
    
    @IBOutlet var pageLabel: NSTextField!
    @IBOutlet var planLabel: NSTextField!
    
    @IBOutlet var ocrCopyButton: NSButton!
    
    @IBOutlet var pageRangeBox: NSComboBox!
    @IBOutlet var planComboBox: NSPopUpButton!
    
    @IBOutlet var progressIndicator: NSProgressIndicator!
    @IBOutlet var progressControl: NSProgressIndicator!
    @IBOutlet var failedBox: NSBox!
    @IBOutlet var failedLabel: NSTextField!
    
    @IBOutlet var cancelButton: NSButton!
    @IBOutlet var startButton: NSButton!
    
    @IBOutlet var languageLabel: NSTextField!
    @IBOutlet var ocrResultLabel: NSTextField!
    
    @IBOutlet var languageButton: NSButton!
    @IBOutlet var txtTextView: NSTextView!
    
    @IBOutlet var deleteButton: NSButton!
    
    @IBOutlet var emptyBox: NSBox!
    
    @IBOutlet var emptyLabel: NSTextField!
    
    var errorOCRArrays: Array<Any>?
    
    var pageIndexs: Array<Any>?
    
    var  password: String = ""
    var pathFile: String = ""
    
    var pdfDocument: CPDFDocument?
    
    @IBOutlet var saveButton: NSButton!
    @IBOutlet var box1: NSBox!
    @IBOutlet var boxLabel1: NSTextField!
    @IBOutlet var previewLabel: NSTextField!
    @IBOutlet var savePDFButton: NSButton!
    
    var ocrCurrentIndex: Int = 0
    var appleOCRManger: KMGOCRManager?
    var googleOCRManger: KMGOCRManager?
    
    var savedFileName: String = ""
    
    private var _fileAttri: KMFileAttribute?
    
    func getOCRResrultsFolderPath() -> String {
        var path = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last
        path?.append("/")
        path?.append(Bundle.main.bundleIdentifier!)
        if (FileManager.default.fileExists(atPath: path!) == false) {
            try?FileManager.default.createDirectory(atPath: path!, withIntermediateDirectories: false)
        }
        
        path?.append("/")
        path?.append("OCR_Resrults")
        
        return path!
    }
    
    convenience init(cpdfDocument: CPDFDocument, pwd: String?) {
        self.init(windowNibName: "KMOCRPDFWindowController")
        self.pdfDocument = cpdfDocument
        self.password = pwd ?? ""
        let url: URL? = cpdfDocument.documentURL
        let lastPathComponent = url?.deletingPathExtension()
        if let str = lastPathComponent?.lastPathComponent {
            if str.count > 0 {
                self.pathFile = str
            }else {
                self.pathFile = NSLocalizedString("Untitled", comment: "")
            }
        } else {
            self.pathFile = NSLocalizedString("Untitled", comment: "")
        }
        
        self._fileAttri = KMFileAttribute()
        self._fileAttri?.password = self.pdfDocument?.password ?? ""
        if self.pdfDocument?.documentURL != nil && self.pdfDocument?.documentURL.path != nil{
            self._fileAttri?.filePath = self.pdfDocument?.documentURL.path ?? ""
        }else {
            self._fileAttri?.filePath = ""
        }
    }
    
    convenience init(filePath: String, pwd: String?) {
        self.init(windowNibName: "KMOCRPDFWindowController")
        self.password = pwd ?? ""
        let pathExtension = filePath.lastPathComponent.customPathExtension
        if  pathExtension.count > 0{
            if pathExtension.lowercased() == "pdf" {
                pdfDocument = CPDFDocument(url: URL(fileURLWithPath: filePath))
            } else {
                if let image = NSImage(contentsOf: URL(fileURLWithPath: filePath)) {
                    self.pdfDocument = CPDFDocument()
                    _ = pdfDocument?.km_insertPage(image.size, withImage: filePath, at: pdfDocument?.pageCount ?? 0)
                }
            }
        }
        self.pathFile = filePath.lastPathComponent.deletingPathExtension
        
        self._fileAttri = KMFileAttribute()
        self._fileAttri?.password = self.pdfDocument?.password ?? ""
        self._fileAttri?.filePath = self.pdfDocument?.documentURL.path ?? ""
    }
    deinit {
        NotificationCenter.default.removeObserver(self)
        releaseSomething()
    }
    
    func releaseSomething() {
        KMGOCRManager.default().delegate = nil
        appleOCRManger?.cancelRecognition()
        appleOCRManger?.delegate = nil
        googleOCRManger?.cancelRecognition()
        googleOCRManger?.delegate = nil
        self.PDFView.document = nil
    }
    override func windowDidLoad() {
        super.windowDidLoad()
        let preView: CPDFView = CPDFView(frame: self.prePdfBGView.bounds)
        self.prePdfBGView.addSubview(preView)
        self.PDFView = preView
        self.PDFView.setDisplay(.singlePage) //self.displayViewMode = CPDFDisplayViewSinglePageContinuous;
        
        self.pageLabel.stringValue = NSLocalizedString("Page Range", comment: "")
        self.planLabel.stringValue = NSLocalizedString("OCR Plan", comment: "")
        
        self.planComboBox.removeAllItems()
        self.planComboBox.addItems(withTitles: [NSLocalizedString("Plan 1 (Online)", comment: ""), NSLocalizedString("Plan 2 (Offline)", comment: "")])
        let plan = UserDefaults.standard.integer(forKey: "KMOCRCurrentPlanKey")
        if plan == 0 {
            KMGOCRManager.default().ocrType = .google
            self.planComboBox.selectItem(at: 0)
        } else {
            KMGOCRManager.default().ocrType = .apple
            self.planComboBox.selectItem(at: 1)
        }
        self.pageRangeBox.addItems(withObjectValues: [NSLocalizedString("All Pages", comment: ""), NSLocalizedString("Current Page", comment: ""), NSLocalizedString("Odd Pages Only", comment: ""), NSLocalizedString("Even Pages Only", comment: ""), NSLocalizedString("e.g. 1,3-5,10", comment: "")])
        self.pageRangeBox.placeholderString = NSLocalizedString("e.g. 1,3-5,10", comment: "")
        
        self.pageRangeBox.selectItem(at: 0)
        self.pageRangeBox.isEditable = false
        if self.pageRangeBox.indexOfSelectedItem == 4 {
            self.window?.makeFirstResponder(self.pageRangeBox)
            self.pageRangeBox.stringValue = ""
            self.pageRangeBox.isEditable = true
        }
        self.emptyLabel.stringValue = NSLocalizedString("Recognize text from Image-based or Scanned PDF with OCR", comment: "")
        self.failedLabel.stringValue = NSLocalizedString("OCR failed. Please try to change the OCR Plan to \"Plan 2 (Offline)\"", comment: "")
        self.txtTextView.textColor = NSColor.textColor
        self.txtTextView.enclosingScrollView?.autohidesScrollers = true
        self.ocrResultLabel.stringValue = NSLocalizedString("OCR Results", comment: "")
        self.ocrCopyButton?.toolTip = KMLocalizedString("Copy and edit text from documents with OCR.", nil)
        self.deleteButton?.toolTip = NSLocalizedString("Delete", comment: "")
        self.deleteButton?.title = NSLocalizedString("Delete", comment: "")
        self.ocrCopyButton?.title = NSLocalizedString("Copy", comment: "")
        self.errorOCRArrays = []
        self.pageIndexs = []
        self.ocrCopyButton.isEnabled = false
        self.deleteButton.isEnabled = false
        self.saveButton.isEnabled = false
        self.savePDFButton.isEnabled = false
        self.boxLabel1.stringValue = NSLocalizedString("Settings", comment: "")
        self.previewLabel.stringValue = NSLocalizedString("Preview", comment: "")
        
        self.saveButton.title = NSLocalizedString("Save as TXT", comment: "")
        self.savePDFButton.title = NSLocalizedString("Save as PDF", comment: "")
        self.saveButton.toolTip = NSLocalizedString("Export as a searchable PDF or text file.", comment: "")
        self.savePDFButton.toolTip = NSLocalizedString("Export as a searchable PDF or text file.", comment: "")
        
        self.cancelButton.title = NSLocalizedString("Cancel", comment: "")
        self.startButton.title = NSLocalizedString("OCR", comment: "")
        self.languageLabel.stringValue = NSLocalizedString("Select OCR Language:", comment: "")
        
        self.updateLanguageButton((KMGOCRManager.default().selectedLanguages?.value(forKeyPath: KMGOCRLanguageStringKey) as? [String]))

        NotificationCenter.default.addObserver(self, selector: #selector(OCRSelectedLanguagesChangeNotification(notification:)), name: NSNotification.Name("KMOCRSelectedLanguagesChangeNotification"), object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(OCRSelectedPlanChangeNotification(notification:)), name: NSNotification.Name("KMOCRSelectedPlanChangeNotification"), object: nil)
        
        self.progressControl.isHidden = true
        emptyBox.isHidden = false
        failedBox.isHidden = true
        
        self.PDFView.document = self.pdfDocument
        self.PDFView.go(toPageIndex: self.currentIndexPage, animated: false)
        self.PDFView.autoScales = true
        self.reloadPDFData()
        if !(self.pdfDocument?.isLocked ?? false) && ((self.pdfDocument?.unlock(withPassword: self.password)) != nil) {
            
        } else {
            if let docUrl = self.pdfDocument?.documentURL {
                KMBaseWindowController.checkPassword(url: self.pdfDocument!.documentURL, type: .owner) { success, pwd in
                    if success {
                        self.pdfDocument?.unlock(withPassword: pwd)
                        self.password = pwd
                        self.reloadPDFData()
                    } else {
                        self.close()
                    }
                }
            } else {
                KMPrint("document url is nil")
            }
        }
        
        NotificationCenter.default.addObserver(self, selector: #selector(PDFViewDocumentChangedNotification(notification:)), name: NSNotification.Name.CPDFViewPageChanged, object: nil)
    }
    
    func windowShouldClose(_ sender: NSWindow) -> Bool {
        close()
        return true
    }
    
    override func close() {
        releaseSomething()
        if ((self.window?.isSheet) != nil) {
//            self.km_endSheet()
            self.window?.sheetParent?.endSheet(self.window!)
        } else {
            super.close()
        }
    }
    
    func reloadPDFData() { // 隐藏PDFView滑动条
        self.PDFView.documentView()?.enclosingScrollView?.hasVerticalScroller = false
        self.PDFView.documentView()?.enclosingScrollView?.hasHorizontalScroller = false
        let pageCount: Int = Int(self.pdfDocument?.pageCount ?? 0)
        let currentPageIndex = self.pdfDocument?.index(for: self.PDFView.currentPage())
        self.currentPageLabel.stringValue = "\((currentPageIndex ?? 0) + 1)"
        self.totalPageLabel.stringValue = "/ \(pageCount)"
    }
    //MARK: KMOCRSelectedLanguagesChangeNotification
    @objc func OCRSelectedLanguagesChangeNotification(notification: NSNotification) {
        if let selectedLanguages = notification.object as? [String] {
            updateLanguageButton(selectedLanguages)
        }
    }
    
    @objc func OCRSelectedPlanChangeNotification(notification: NSNotification) {
        let plan = UserDefaults.standard.integer(forKey: "KMOCRCurrentPlanKey")
        if plan == 0 {
            self.planComboBox.selectItem(at: 0)
        } else {
            self.planComboBox.selectItem(at: 1)
        }
        KMGOCRManager.default().selectedLanguages = NSMutableArray()
        updateLanguageButton(KMGOCRManager.default().selectedLanguages?.value(forKeyPath: KMGOCRLanguageStringKey) as? [String])
    }
    @objc func PDFViewDocumentChangedNotification(notification: NSNotification) {
        let pageIndex = self.PDFView.currentPageIndex+1
        self.currentPageLabel.stringValue = "\(pageIndex)"
    }
    
    func updateLanguageButton(_ languages: [String]?) {
        if languages?.count ?? 0 < 1 {
            self.languageButton.title = NSLocalizedString("Auto Detection", comment: "")
            return
        }
        var languageName: String? = nil
        if languages?.count ?? 0 > 0 {
            for i in 0..<(languages?.count ?? 0) {
                let language = languages?[i]
                if i == 0 {
                    languageName = language
                } else {
                    languageName = languageName?.appendingFormat(",%@", language ?? "")
                }
            }
        } else {
            languageName = ""
        }
        
        self.languageButton.title = languageName ?? ""
    }
    func imageRep(withSize size: NSSize, scale: CGFloat, drawingHandler: (NSRect) -> Void) -> Any? {
        let bmpImageRep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(size.width * scale), pixelsHigh: Int(size.height * scale), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: .calibratedRGB, bitmapFormat: .alphaFirst, bytesPerRow: 0, bitsPerPixel: 0)
        //        bmpImageRep?.bitmapImageRepByRetaggingWithColorSpace = .sRGB
        bmpImageRep?.size = size
        NSGraphicsContext.saveGraphicsState()
        NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: bmpImageRep!)
        //        drawingHandler(.zero, size)
        drawingHandler(NSRect(origin: NSZeroPoint, size: size))
        NSGraphicsContext.restoreGraphicsState()
        return bmpImageRep
    }
    func bitmapImage(withSize size: NSSize, drawingHandler: (NSRect) -> Void) -> NSImage? {
        let image = NSImage(size: size)
        let scale = KMImageScale
        image.addRepresentation(imageRep(withSize: size, scale: scale, drawingHandler: drawingHandler) as! NSBitmapImageRep)
        return image
    }
    func thumbnail(with page: CPDFPage) -> NSImage? {
        let bounds = page.bounds(for: .cropBox)
        var pageSize = bounds.size
        var scale: CGFloat = 1.0
        var thumbnailSize: NSSize
        var pageRect = NSZeroRect
        var image: NSImage?
        let aSize = pageSize.width
        if page.rotation % 180 == 90 {
            pageSize = NSSize(width: pageSize.height, height: pageSize.width)
        }
        
        if aSize > 0.0 {
            if pageSize.height > pageSize.width {
                thumbnailSize = NSSize(width: round(aSize * pageSize.width / pageSize.height), height: aSize)
            } else {
                thumbnailSize = NSSize(width: aSize, height: round(aSize * pageSize.height / pageSize.width))
            }
            let kKMMaxPixelsLimit = 75000000
            let totalPixelNumber = Int((thumbnailSize.width * KMImageScale) * (thumbnailSize.height * KMImageScale))
            if totalPixelNumber >= kKMMaxPixelsLimit {
                let sizeScale = sqrt(Float(kKMMaxPixelsLimit - 1000) / Float(totalPixelNumber))
                thumbnailSize = NSSize(width: floor(thumbnailSize.width * CGFloat(sizeScale)), height: floor(thumbnailSize.height * CGFloat(sizeScale)))
            }
            scale = max(thumbnailSize.width / pageSize.width, (thumbnailSize.height) / pageSize.height)
        } else {
            thumbnailSize = NSSize(width: pageSize.width, height: pageSize.height)
        }
        
        if thumbnailSize.width.isNaN || thumbnailSize.height.isNaN || thumbnailSize.width == 0.0 || thumbnailSize.height == 0.0 {
            thumbnailSize = NSSize(width: 186.0, height: 256.0)
        }
        
        pageRect.size = thumbnailSize
        
        image = bitmapImage(withSize: thumbnailSize) { rect in
            NSGraphicsContext.current?.imageInterpolation = .high
            
            NSGraphicsContext.saveGraphicsState()
            NSColor.white.setFill()
            pageRect.fill()
            NSGraphicsContext.restoreGraphicsState()
            
            if abs(scale - 1.0) > 0.0 {
                let transform = NSAffineTransform()
                transform.scale(by: scale)
                transform.concat()
            }
            
            page.draw(with: .cropBox, to: (NSGraphicsContext.current?.cgContext as! CGContext))
            
            NSGraphicsContext.current?.imageInterpolation = .default
        }
        
        return image
    }
    func savedName() -> String {
        var resultArrays: Array<Any> = []
        var ocrIndexArrays: Array<Any> = []
        
        let sortedKeys = self.ocrDictionary?.allKeys.sorted(by: {
            ($0 as? String)?.compare($1 as? String ?? "") == .orderedAscending
        })
        for i in 0 ..< (sortedKeys?.count ?? 0) {
            let keyS = sortedKeys?[i]
            ocrIndexArrays.append(keyS as Any)
            resultArrays.append(self.ocrDictionary?[keyS as Any] as Any)
        }
        
        var fileName = self.savedFileName
        if fileName.count > 50 {
            fileName = String(fileName.prefix(50))
        }
        
        if sortedKeys?.count ?? 0 > 1 {
            fileName = "\(self.pathFile) Pages \(fileName) _OCR"
        } else {
            fileName = "\(self.pathFile) Page \(fileName) _OCR"
        }
        
        var returnName = fileName
        switch self.pageRangeBox.indexOfSelectedItem {
        case 0:
            returnName = "\(self.pathFile)_OCR"
        case 2:
            returnName = "\(self.pathFile) Odd_OCR"
        case 3:
            returnName = "\(self.pathFile) Even_OCR"
        default:
            break
        }
        
        return returnName
    }
    func savePDF() {
        var resultArrays: Array<Any> = []
        var ocrIndexArrays: Array<Any> = []
        let sortedKeys = self.ocrDictionary?.allKeys.sorted(by: { ($0 as? String)?.compare($1 as? String ?? "") == .orderedAscending })
        for i in 0 ..< (sortedKeys?.count ?? 0) {
            let keyS = sortedKeys?[i]
            ocrIndexArrays.append(keyS as Any)
            resultArrays.append(self.ocrDictionary?[keyS as Any] as Any)
        }
        
        let fileName = self.savedFileName
        
        let saveAccessCtr = KMSavePanelAccessoryController()
        let outputSavePanel = NSSavePanel()
        outputSavePanel.allowedFileTypes = ["pdf"]
        outputSavePanel.nameFieldStringValue = fileName
        outputSavePanel.accessoryView = saveAccessCtr.view
        outputSavePanel.beginSheetModal(for: self.window!) { [self] (result) in
            if result == .OK {
                
                let savePDFPath = outputSavePanel.url?.path ?? ""
                if !FileManager.default.fileExists(atPath: getOCRResrultsFolderPath()) {
                    try? FileManager.default.createDirectory(atPath: getOCRResrultsFolderPath(), withIntermediateDirectories: false, attributes: nil)
                }
                var imagePath = [Any]()
                for i in 0..<ocrIndexArrays.count {
                    let rPath = (getOCRResrultsFolderPath() as NSString).appendingPathComponent("\(i).png")
                    if let index = ocrIndexArrays[i] as? NSNumber, let page = self.pdfDocument?.page(at: UInt(index.intValue)), let image = self.thumbnail(with: page) {
                        try? image.tiffRepresentation?.write(to: URL(fileURLWithPath: rPath), options: .atomic)
                    }
                    imagePath.append(rPath)
                }
                
                KMGOCRManager.default().createPDFFile(savePDFPath, imagePaths: imagePath, results: resultArrays, scale: KMImageScale)
                if saveAccessCtr.openAutomaticButton.state == .on {
                    self.cancelButtonAction("")
                    NSDocumentController.shared.openDocument(withContentsOf: URL(fileURLWithPath: savePDFPath), display: true, completionHandler: {document,documentWasAlreadyOpen,error in
                        
                    })
                } else {
                    self.viewFileAtFinder(savePDFPath)
                }
            }
        }
    }
    func viewFileAtFinder(_ fileName: String) {
        let workspace = NSWorkspace.shared
        let url = URL(fileURLWithPath: fileName)
        workspace.activateFileViewerSelecting([url])
    }
    func saveText() { 
        let sortedKeys = self.ocrDictionary?.allKeys.sorted(by: { ($0 as? String)?.compare($1 as? String ?? "") == .orderedAscending })
        let fileName = self.savedFileName
        
        let saveAccessCtr = KMSavePanelAccessoryController()
        let outputSavePanel = NSSavePanel()
        outputSavePanel.allowedFileTypes = ["txt"]
        outputSavePanel.nameFieldStringValue = fileName
        outputSavePanel.accessoryView = saveAccessCtr.view
        outputSavePanel.beginSheetModal(for: self.window!) { (result) in
            if result == .OK {
                let outputURL = outputSavePanel.url
                try? self.txtTextView?.string.write(to: outputURL!, atomically: true, encoding: .utf8)
                if saveAccessCtr.openAutomaticButton?.state == .on {
                    NSWorkspace.shared.open(outputURL!)
                } else {
                    self.viewFileAtFinder(outputURL?.path ?? "")
                }
            }
        }
    }
    func fileNameWithNums(_ nums: [NSNumber]) -> String {
        var fileName: String? = nil
        if nums.count > 0 {
            if nums.count == 1 {
                if let num = nums.first {
                    let idx = num.intValue + 1
                    return "\(idx)"
                }
            }
            var sortIndex = NSSet()
            for num in nums {
                let idx = num.intValue + 1
                //            sortIndex.insert(NSNumber(value: idx))
                sortIndex.adding(NSNumber(value: idx))
            }
            let sort = NSSortDescriptor(key: nil, ascending: true)
            let sortDesc = [sort]
            let sortArray = sortIndex.sortedArray(using: sortDesc)
            
            var a = 0
            var b = 0
            if sortArray.count == 1 {
                let num: NSNumber = sortArray.last as! NSNumber
                fileName = "\(num.intValue)"
                return fileName ?? ""
            }
            
            for i in 0 ..< sortArray.count {
                let num = sortArray[i]
                if fileName?.count ?? 0 > 0 {
                    if (num as AnyObject).intValue == b + 1 {
                        b = (num as AnyObject).intValue
                        if (i == sortArray.count - 1)  {
                            fileName = (fileName ?? "") + "\(a)-\(b)"
                        }
                    } else {
                        if a == b {
                            fileName = (fileName ?? "") + "\(a),"
                        } else {
                            fileName = (fileName ?? "") + "\(a)-\(b),"
                        }
                        a = (num as AnyObject).intValue
                        b = (num as AnyObject).intValue
                        if (i == sortArray.count - 1)  {
                            fileName = (fileName ?? "") + "\(a)"
                        }
                    }
                } else {
                    fileName = ""
                    a = (num as AnyObject).intValue
                    b = (num as AnyObject).intValue
                }
            }
            return fileName ?? ""
        }
        return ""
    }
    
    @IBAction func cancelButtonAction(_ sender: Any) {
        if FileManager.default.fileExists(atPath: getOCRResrultsFolderPath()) {
            try? FileManager.default.removeItem(atPath: getOCRResrultsFolderPath())
        }
        KMGOCRManager.default().cancelRecognition()
        self.close()
    }
    @IBAction func startButtonAction(_ sender: Any) {
        self.ocrCurrentIndex = 0
        txtTextView.string = ""
        ocrDictionary = NSMutableDictionary()
        let pdfDocument = self.pdfDocument
        errorOCRArrays?.removeAll()
        pageIndexs?.removeAll()
        if self.pageRangeBox.indexOfSelectedItem == 0 {
            for i in 0..<(pdfDocument?.pageCount ?? 0) {
                pageIndexs?.append(NSNumber(value: i))
            }
        } else if self.pageRangeBox.indexOfSelectedItem == 1 {
            let page = PDFView.currentPage()
            let pageIndex = PDFView.document?.index(for: page)
            pageIndexs?.append(NSNumber(value: pageIndex!))
        } else if self.pageRangeBox.indexOfSelectedItem == 2 {
            for i in 0..<(pdfDocument?.pageCount ?? 0) where i % 2 == 0 {
                pageIndexs?.append(NSNumber(value: i))
            }
        } else if self.pageRangeBox.indexOfSelectedItem == 3 {
            for i in 0..<(pdfDocument?.pageCount ?? 0) where i % 2 != 0 {
                pageIndexs?.append(NSNumber(value: i))
            }
        } else {
            var attribute = self._fileAttri
            if attribute == nil {
                attribute = KMFileAttribute()
                self._fileAttri = attribute
                
                attribute?.password = self.pdfDocument?.password ?? ""
                attribute?.filePath = self.pdfDocument?.documentURL.path ?? ""
            }
//            attribute.pdfDocument = pdfDocument
            
            attribute?.bAllPage = false
            attribute?.pagesType = .custom
            attribute?.pagesString = self.pageRangeBox.stringValue
            let selectPages = attribute?.fetchSelectPages() ?? []
            if selectPages.count > 0 {
                for num in selectPages {
                    pageIndexs?.append(NSNumber(value: num - 1))
                }
            }
        }
        batchesOCR()
    }
    func batchesOCR() { 
        savedFileName = savedName()
        let intervalOCR: UInt = 10
        let selctPageImages: NSMutableArray = NSMutableArray()
        
        for i in 0..<intervalOCR {
            if ocrCurrentIndex + Int(i) >= self.pageIndexs?.count ?? 0 { continue }
            
            autoreleasepool {
                let index = self.pageIndexs?[self.ocrCurrentIndex + Int(i)] as! NSNumber
                let page = self.pdfDocument?.page(at: UInt(index.intValue))
                let img: NSImage = thumbnail(with: page!)!
                let data: NSData = img.tiffRepresentation! as NSData
                selctPageImages.add(data)
            }
        }
        
        if selctPageImages.count < 1 && ocrCurrentIndex == 0 {
            let alert = NSAlert()
            alert.alertStyle = .critical
            alert.messageText = NSLocalizedString("Invalid page range or the page number is out of range. Please try again.", comment: "")
            
            if #available(OSX 10.11, *) {
                alert.beginSheetModal(for: self.window!, completionHandler: nil)
            } else {
                alert.runModal()
            }
        }
        
        if selctPageImages.count < 1 {
            return
        }
        
        if appleOCRManger != nil {
            appleOCRManger?.cancelRecognition()
            appleOCRManger?.delegate = nil
            appleOCRManger = nil
        }
        
        if googleOCRManger != nil {
            googleOCRManger?.cancelRecognition()
            googleOCRManger?.delegate = nil
            googleOCRManger = nil
        }
        
        ocrCopyButton.isEnabled = false
        saveButton.isEnabled = false
        savePDFButton.isEnabled = false
        startButton.isEnabled = false
        deleteButton.isEnabled = false
        progressControl.isHidden = false
        progressControl.startAnimation(nil)
        emptyBox.isHidden = true
        failedBox.isHidden = true
        
        DispatchQueue.main.async {
            let languages = KMGOCRManager.default().selectedLanguages?.value(forKeyPath: KMGOCRLanguageCodeKey)
            if self.planComboBox.indexOfSelectedItem == 0 {
                self.googleOCRManger = KMGOCRManager()
                self.googleOCRManger?.ocrType = .google
                self.googleOCRManger?.delegate = self
                self.googleOCRManger?.recognitionImages((selctPageImages as! [Any]), withLanguages: languages as? [Any])
            } else {
                self.appleOCRManger = KMGOCRManager()
                self.appleOCRManger?.ocrType = .apple
                self.appleOCRManger?.delegate = self
                self.appleOCRManger?.recognitionImages((selctPageImages as! [Any]), withLanguages: languages as? [Any])
            }
        }
    }
    @IBAction func planSelectButtonAction(_ sender: NSPopUpButton) {
        let plan = UserDefaults.standard.integer(forKey: "KMOCRCurrentPlanKey")
        if plan != sender.indexOfSelectedItem {
            KMGOCRManager.default().selectedLanguages = NSMutableArray()
            updateLanguageButton(KMGOCRManager.default().selectedLanguages?.value(forKeyPath: KMGOCRLanguageStringKey) as? [String])
        }
        UserDefaults.standard.set(sender.indexOfSelectedItem, forKey: "KMOCRCurrentPlanKey")
        UserDefaults.standard.synchronize()
        if self.planComboBox.indexOfSelectedItem == 0 {
            KMGOCRManager.default().ocrType = .google
        } else {
            KMGOCRManager.default().ocrType = .apple
        }
        NotificationCenter.default.post(name: NSNotification.Name("KMOCRSelectedPlanChangeNotification"), object: nil)
    }
    @IBAction func languageButtonAction(_ sender: Any) {
        let popover = NSPopover()
        popover.delegate = self
        popover.contentViewController = KMLanguageViewController(nibName: "KMLanguageViewController", bundle: Bundle.main)
        popover.animates = true
        popover.behavior = .transient
        popover.show(relativeTo: (sender as! NSView).bounds, of: sender as! NSView, preferredEdge: .minX)
    }
    @IBAction func helpButtonAction(_ sender: Any) {
        let helpController = NSViewController()
        let textView = NSTextView(frame: NSRectToCGRect(NSMakeRect(0, 0, 300.0, 50.0)))
        textView.backgroundColor = NSColor.clear
        textView.isEditable = false
        textView.layer?.cornerRadius = 6
        let tStrAuto = NSLocalizedString("Choose automatic language detection for better OCR results.", comment: "")
        textView.alignment = .justified
        textView.string = "\n\(tStrAuto)"
        helpController.view = textView
        let popover = NSPopover()
        popover.delegate = self
        popover.contentViewController = helpController
        popover.animates = true
        popover.behavior = .transient
        popover.show(relativeTo: (sender as! NSView).bounds, of: sender as! NSView, preferredEdge: .minY)
    }
    @IBAction func buttonItemClick_CopyTxt(_ sender: NSButton) {
        let pasteboard = NSPasteboard.general
        pasteboard.clearContents()
        let str: NSPasteboardWriting = self.txtTextView.string as NSPasteboardWriting
        pasteboard.writeObjects([str])
        let _ = CustomAlertView.alertView(message: NSLocalizedString("Copy successful!", comment: ""), fromView: sender.superview!, withStyle: .black)
    }
    @IBAction func buttonItemClick_Delete(_ sender: NSButton) {
        ocrCopyButton.isEnabled = false
        saveButton.isEnabled = false
        savePDFButton.isEnabled = false
        deleteButton.isEnabled = false
        emptyBox.isHidden = false
        failedBox.isHidden = true
        resultString = ""
        txtTextView.string = ""
        ocrDictionary = NSMutableDictionary()
    }
    @IBAction func boxItemClicked_PageRange(_ sender: NSButton) {
        if 4 != pageRangeBox.indexOfSelectedItem {
            self.window?.makeFirstResponder(self)
            pageRangeBox.isEditable = false
        } else {
            pageRangeBox.stringValue = ""
            pageRangeBox.isEditable = true
            self.window?.makeFirstResponder(pageRangeBox)
        }
    }
    
    @IBAction func nextButtonAction(_ sender: NSButton) {
        self.PDFView.goToNextPage(nil)
        self.reloadPDFData()
    }
    @IBAction func previousButtonAction(_ sender: NSButton) {
        self.PDFView.goToPreviousPage(nil)
        self.reloadPDFData()
    }
    @IBAction func buttonClicked_SaveButton(_ sender: NSButton) {
        self.saveText()
    }
    @IBAction func savePDFButtonAction(_ sender: NSButton) {
        self.savePDF()
    }
    func controlTextDidEndEditing(_ notification: Notification) {
        guard let textField = notification.object as? NSTextField else { return }
        if textField == currentPageLabel {
            let index = Int(currentPageLabel.stringValue) ?? 0
            let pageCount = pdfDocument?.pageCount
            let currentPageIndex = pdfDocument?.index(for: PDFView.currentPage())
            if index > 0 && index <= pageCount ?? 0 {
                PDFView.go(to: pdfDocument?.page(at: UInt(index-1))!)
                reloadPDFData()
            } else {
                currentPageLabel.stringValue = "\((currentPageIndex ?? 0)+1)"
            }
        }
    }
    func controlTextDidChange(_ notification: Notification) {
        guard let textField = notification.object as? NSTextField else { return }
        if textField == currentPageLabel {
            let string = textField.formatter?.string(for: NSNumber(value: Int(textField.stringValue) ?? 0))
            textField.stringValue = string ?? ""
        }
    }
    func popoverDidClose(_ notification: Notification) {
        
    }
    
    func gocrManagerDidStartOCR(_ manager: KMGOCRManager!) {
        
    }
    //MARK: KMGOCRManagerDelegate
    func gocrManagerDidFinishOCR(_ manager: KMGOCRManager!) {
        self.batchesOCR()
    }
    func gocrManager(_ manager: KMGOCRManager!, didCancelOCRImageAt index: Int) {
        
    }
    func gocrManager(_ manager: KMGOCRManager!, didStartOCRImageAt index: Int) {
        DispatchQueue.main.async {
            self.pageRangeBox.isEnabled = false
            self.languageButton.isEnabled = false
            self.planComboBox.isEnabled = false
        }
    }
    func gocrManager(_ manager: KMGOCRManager!, didFinishOCRImageAt index: Int, results: [KMGOCRResult]!) {
        self.dealWithResults(results, OCRImageAtIndex: index)
    }
    func gocrManager(_ manager: KMGOCRManager!, didFailureOCRImageAt index: Int, error: Error!) {
        let pagenum = self.pageIndexs?[index] as! NSNumber
        if (error != nil) {
            self.errorOCRArrays?.append(pagenum)
        }
        self.dealWithResults([], OCRImageAtIndex: index)
    }
    
    func dealWithResults(_ rlts: [KMGOCRResult]?, OCRImageAtIndex index: Int) {
        if index >= self.pageIndexs?.count ?? 0 {
            return
        }
        
        let key = self.pageIndexs?[self.ocrCurrentIndex] as! NSNumber
        
        if ocrDictionary == nil {
            ocrDictionary = NSMutableDictionary()
        }
        
        ocrDictionary?.setObject(rlts as Any, forKey: key)
        
        let sortedKeys = self.ocrDictionary?.allKeys.sorted(by: { ($0 as! NSNumber).compare($1 as! NSNumber) == .orderedAscending })
        var textString = ""
        
        for key in sortedKeys! {
            let results: Array<KMGOCRResult> = self.ocrDictionary?.object(forKey: key) as! Array<KMGOCRResult>
            var rStr = ""
            if results.count > 0 {
                rStr = results[0].text
            }
            if textString.count > 0 {
                textString += "\n\n"
            }
            textString += String(format: NSLocalizedString("Page %ld", comment: ""), (key as! NSNumber).intValue + 1)
            textString += "\n"
            textString += rStr
        }
        
        self.txtTextView.string = textString
        self.resultString = textString
        
        self.ocrCurrentIndex += 1
        
        if self.ocrCurrentIndex >= (self.pageIndexs?.count ?? 0) - 1 {
            self.progressControl.stopAnimation(nil)
            self.progressControl.isHidden = true
            self.saveButton.isEnabled = true
            self.savePDFButton.isEnabled = true
            self.ocrCopyButton.isEnabled = true
            self.deleteButton.isEnabled = true
            self.startButton.isEnabled = true
            DispatchQueue.main.async {
                self.pageRangeBox.isEnabled = true
                self.languageButton.isEnabled = true
                self.planComboBox.isEnabled = true
            }
            if appleOCRManger != nil {
                appleOCRManger?.cancelRecognition()
                appleOCRManger?.delegate = nil
                appleOCRManger = nil
            }
            
            if googleOCRManger != nil {
                googleOCRManger?.cancelRecognition()
                googleOCRManger?.delegate = nil
                googleOCRManger = nil
            }
            
            KMGOCRManager.default().delegate = nil
            
            if self.errorOCRArrays?.count ?? 0 < 1 {
                
            } else if self.errorOCRArrays?.count == self.pageIndexs?.count {
                if KMGOCRManager.default().ocrType == .google {
                    self.failedLabel.stringValue = NSLocalizedString("OCR failed.Please try to change the OCR Plan to \"Plan 2 (Offline)\"", comment: "")
                    self.failedBox.isHidden = false
                } else {
                    let alert = NSAlert()
                    alert.alertStyle = NSAlert.Style.critical
                    alert.messageText = ""
                    if #available(macOS 10.15, *) {
                        alert.informativeText = NSLocalizedString("Unable to perform OCR on this document. Please try again later.", comment: "")
                    } else {
                        alert.informativeText = NSLocalizedString("OCR failed, please try again. Note: OCR Plan 2(Offline) is supported in macOS 10.15+.", comment: "")
                        self.failedLabel.stringValue = NSLocalizedString("OCR failed, please try again. Note: OCR Plan 2(Offline) is supported in macOS 10.15+.", comment: "")
                        self.failedBox.isHidden = false
                    }
                    alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
                    let response = alert.runModal()
                    if response == NSApplication.ModalResponse.alertFirstButtonReturn {
                        
                    }
                }
            } else {
                var contextString = String(format: "%@", NSLocalizedString("Some problems occurred during the last operation:", comment: ""))
                contextString += "\n"
                
                if self.errorOCRArrays?.count ?? 0 > 1 {
                    contextString += NSLocalizedString("Pages", comment: "")
                } else {
                    contextString += NSLocalizedString("Page", comment: "")
                }
                if self.errorOCRArrays?.count ?? 0 > 0 {
                    contextString += String(format: ": %@", self.fileNameWithNums(self.errorOCRArrays as! Array<NSNumber>))
                }
                
                let alert = NSAlert()
                alert.alertStyle = NSAlert.Style.critical
                alert.messageText = NSLocalizedString("Completed", comment: "")
                alert.informativeText = contextString
                alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
                let response = alert.runModal()
                if response == NSApplication.ModalResponse.alertFirstButtonReturn {
                    
                }
            }
        }
    }
    
    
}