//
//  KMExtractImageWindowController.swift
//  PDF Reader Pro
//
//  Created by liujiajie on 2023/11/17.
//

import Cocoa

class KMExtractImageWindowController: NSWindowController,PDFConvertObjectDelegate,NSTextFieldDelegate{
    var docPath: String = ""
    var password: String = ""
    var currentPage: Int = 0
    var maskView: KMBookletMaskView?
    
    @IBOutlet var rangeTipLabel: NSTextField!
    @IBOutlet var rangeTextField: NSTextField!
    @IBOutlet var allPageButton: NSButton!
    @IBOutlet var currentPageButton: NSButton!
    @IBOutlet var singlePageButton: NSButton!
    @IBOutlet var doublePageButton: NSButton!
    @IBOutlet var customPageButton: NSButton!
    @IBOutlet var extractImageButton: NSButton!
    @IBOutlet var cancelButton: NSButton!
    @IBOutlet var customTextField: NSTextField!
    @IBOutlet var totalImagesTextField: NSTextField!
    lazy var pdfDocument: CPDFDocument? = {
        var pdfDoc = CPDFDocument(url: URL(fileURLWithPath: self.docPath))
        if (self.password.count > 0){
            pdfDoc?.unlock(withPassword: self.password)
        }
        return pdfDoc
    }()
    var selectPagesIndex: Int = 0
//    var pdfConverter: PDFConvertObject?
    lazy var pdfConverter: PDFConvertObject? = {
        let conerter = PDFConvertObject()
        return conerter
    }()
    @IBOutlet var currentPageTextField: NSTextField!
    @IBOutlet var pageCountTextField: NSTextField!
    @IBOutlet var pdfViewBG: NSView!
    var preViewPDFView: CPDFView!
    
    deinit {
        NotificationCenter.default.removeObserver(self)
        
    }
    override func windowDidLoad() {
        super.windowDidLoad()
        let preView: CPDFView = CPDFView(frame: self.pdfViewBG.bounds)
        self.pdfViewBG.addSubview(preView)
        self.preViewPDFView = preView
        configUI()
    }
    func configUI() {
        if !self.docPath.isEmpty && self.docPath.count > 0 {
            let url = URL(fileURLWithPath: docPath)
            let document = CPDFDocument(url: url)
            if self.password.count > 0 {
                document?.unlock(withPassword: password)
            }
            self.preViewPDFView.document = document
            self.preViewPDFView.autoScales = true
            self.preViewPDFView.layoutDocumentView()
            self.preViewPDFView.go(toPageIndex: self.currentPage, animated: true)
        }
        self.allPageButton.title = NSLocalizedString("All Pages", comment: "")
        self.singlePageButton.title = NSLocalizedString("Odd Pages Only", comment: "")
        self.doublePageButton.title = NSLocalizedString("Even Pages Only", comment: "")
        self.currentPageButton.title = NSLocalizedString("Current Page", comment: "")
        self.extractImageButton.title = NSLocalizedString("Extract", comment: "")
        self.cancelButton.title = NSLocalizedString("Cancel", comment: "")
        self.rangeTextField.placeholderString = NSLocalizedString("e.g. 1,3-5,10", comment: "")
        self.rangeTipLabel.stringValue = NSLocalizedString("Page Range", comment: "")
        
        self.currentPageTextField.stringValue = "\(self.currentPage + 1)"
        self.pageCountTextField.stringValue = "/ \(self.pdfDocument?.pageCount ?? 0)"
        self.customTextField.stringValue = self.pageCountTextField.stringValue
        self.selectPagesIndex = 0
        
        self.rangeTextField.isEnabled = false
        self.customTextField.isEnabled = false
        self.allPageButton.state = NSControl.StateValue.on
        if self.pdfDocument?.pageCount ?? 0 < 2 {
            self.doublePageButton.isEnabled = false
        } else {
            self.doublePageButton.isEnabled = true
        }
        self.preViewPDFView.setDisplay(.singlePage)
        self.preViewPDFView.layoutDocumentView()
        NotificationCenter.default.addObserver(self, selector: #selector(pageChangeNotification(notification:)), name: NSNotification.Name.PDFViewPageChanged, object: self.preViewPDFView)
    }
    func selectCurrentPageBtn() {
        self.customPageButton_Action(self.currentPageButton)
    }
    
    @IBAction func customPageButton_Action(_ sender: NSButton) {
        self.allPageButton.state = NSControl.StateValue.off
        self.currentPageButton.state = NSControl.StateValue.off
        self.singlePageButton.state = NSControl.StateValue.off
        self.doublePageButton.state = NSControl.StateValue.off
        self.customPageButton.state = NSControl.StateValue.off
        sender.state = NSControl.StateValue.on
        self.rangeTextField.isEnabled = false
        self.customTextField.textColor = NSColor.disabledControlTextColor
        self.selectPagesIndex = sender.tag
        if sender.tag == 3 {
            self.rangeTextField.isEnabled = true
            self.customTextField.textColor = NSColor.labelColor
            self.window?.makeFirstResponder(self.rangeTextField)
            if self.rangeTextField.stringValue.isEmpty {
                return
            }
        }
    }
    @IBAction func extractImageButton_Action(_ sender: Any) {
        startExtracting()
    }
    @IBAction func cancleButton_Action(_ sender: Any) {
        self.window?.sheetParent?.endSheet(self.window!)
    }
    @IBAction func nextPage_Action(_ sender: Any) {
        if self.preViewPDFView.canGoToNextPage() {
            self.preViewPDFView.goToNextPage(sender)
        }
        let index = self.preViewPDFView.document.index(for: self.preViewPDFView.currentPage())
        self.currentPageTextField.stringValue = "\(index + 1)"
    }
    @IBAction func previousPage_Action(_ sender: Any) {
        if self.preViewPDFView.canGoToPreviousPage() {
            self.preViewPDFView.goToPreviousPage(sender)
        }
        let index = self.preViewPDFView.document.index(for: self.preViewPDFView.currentPage())
        self.currentPageTextField.stringValue = "\(index + 1)"
    }
    
    override func close() {
        if ((self.window?.isSheet) != nil) {
            self.window?.sheetParent?.endSheet(self.window!)
        } else {
            super.close()
        }
    }
    
    func startExtracting() {
        let indeSet = self.selectIndexSet()
        if indeSet.count == 0 { return }
        let lastPathName = self.pdfDocument?.documentURL.deletingPathExtension().lastPathComponent ?? ""
        let tFileName = (String(format: "%@_Extract Images", lastPathName))
        let outputSavePanel = NSSavePanel()
        outputSavePanel.title = NSLocalizedString("Save as PDF", comment: "")
        outputSavePanel.allowsOtherFileTypes = true
        outputSavePanel.isExtensionHidden = true
        outputSavePanel.canCreateDirectories = true
        outputSavePanel.nameFieldStringValue = tFileName
        outputSavePanel.beginSheetModal(for: self.window!) {(result) in
            if result == NSApplication.ModalResponse.OK {
                self.showWaitting()
                DispatchQueue.main.async {
                    let tDestFile = outputSavePanel.url?.path ?? ""
                    let uniquePath = KMExtractImageWindowController.createDestFolder(path: tDestFile, isUnique: false)
                    self.pdfConverter?.extractResourcesFromPDF(at: self.docPath, pdfPassword: self.password, selectIndexSet: indeSet as IndexSet, destDocPath: uniquePath, moreOptions: nil)
                    self.extractOK(tDestFile)
                }
            }
        }
    }
    func extractOK(_ folder: String) {
        self.hideWaitting()
        self.close()
        if FileManager.default.fileExists(atPath: folder) {
            let workspace = NSWorkspace.shared
            let url = URL(fileURLWithPath: folder)
            workspace.activateFileViewerSelecting([url])
        }
    }
    func selectIndexSet() -> NSMutableIndexSet {
        let pageCount = self.pdfDocument?.pageCount
        let indeSet = NSMutableIndexSet()
        if self.selectPagesIndex == 0 {
            for i in 0..<(pageCount ?? 0) {
                indeSet.add(IndexSet(integer: IndexSet.Element(i)))
            }
        } else if self.selectPagesIndex == 1 {
            for i in 0..<(pageCount ?? 0) {
                if i % 2 == 0 {
                    indeSet.add(IndexSet(integer: IndexSet.Element(i)))
                }
            }
        } else if self.selectPagesIndex == 2 {
            for i in 0..<(pageCount ?? 0) {
                if i % 2 != 0 {
                    indeSet.add(IndexSet(integer: IndexSet.Element(i)))
                }
            }
        } else if self.selectPagesIndex == 4 {
            if let index = self.preViewPDFView.document?.index(for: self.preViewPDFView.currentPage()!) {
                indeSet.add(IndexSet(integer: IndexSet.Element(index)))
            }
        } else {
            let fileAttribute = KMFileAttribute()
            fileAttribute.filePath = self.preViewPDFView.document?.documentURL?.path ?? ""
            fileAttribute.bAllPage = false
            if (self.customPageButton.state == .on){
                fileAttribute.pagesType = .custom
            }
            fileAttribute.pagesString = self.rangeTextField.stringValue
            if fileAttribute.fetchSelectPages().isEmpty {
                let alert = NSAlert()
                alert.alertStyle = .critical
                alert.messageText = "\(fileAttribute.filePath.lastPathComponent) \(NSLocalizedString("Invalid page range or the page number is out of range. Please try again.", comment: ""))"
                alert.runModal()
                return indeSet
            }
            
            for num in fileAttribute.fetchSelectPages() {
                indeSet.add(num-1)
            }
        }
        return indeSet
    }
    class func createDestFolder(path: String, isUnique: Bool) -> String { 
        var ret = true
        var tUniqueName: String? = nil
        let tFileManager = FileManager.default
        if isUnique {
            tUniqueName = getUniqueFilePath(filePath: path)
        } else {
            tUniqueName = path
        }
        
        if !tFileManager.fileExists(atPath: tUniqueName!) {
            do {
                try tFileManager.createDirectory(atPath: tUniqueName!, withIntermediateDirectories: true, attributes: nil)
            } catch {
                ret = false
            }
        }
        
        return tUniqueName!
    }
    class func getUniqueFilePath(filePath: String) -> String { 
        var i = 0
        var isDirectory = ObjCBool(false)
        var uniqueFilePath = filePath
        let filemanager = FileManager.default
        filemanager.fileExists(atPath: uniqueFilePath, isDirectory: &isDirectory)
        
        if isDirectory.boolValue {
            while filemanager.fileExists(atPath: uniqueFilePath) {
                i += 1
                uniqueFilePath = "\(filePath)(\(i))"
            }
        } else {
            while filemanager.fileExists(atPath: uniqueFilePath) {
                i += 1
                let path = "\(filePath.deletingPathExtension)(\(i))"
                uniqueFilePath = path.stringByAppendingPathExtension(filePath.customPathExtension)
            }
        }
        
        return uniqueFilePath
    }
    
    @objc func pageChangeNotification(notification: Notification) {
        self.currentPageTextField.stringValue = self.preViewPDFView.currentPage().label ?? ""
    }
    func controlTextDidEndEditing(_ obj: Notification) {
        if obj.object as? NSTextField == self.currentPageTextField {
            if let intValue = Int(self.currentPageTextField.stringValue), intValue > (self.preViewPDFView.document?.pageCount ?? 0) {
                let alert = NSAlert()
                alert.alertStyle = .critical
                alert.messageText = String(format: "%@%@", self.preViewPDFView.document.documentURL.lastPathComponent.lastPathComponent,KMLocalizedString("Invalid page range or the page number is out of range. Please try again.", nil))
                alert.beginSheetModal(for: NSApp.mainWindow!, completionHandler: nil) 
                return
            }
            self.preViewPDFView.go(to: self.preViewPDFView.document?.page(at: UInt((Int(self.currentPageTextField.stringValue) ?? 0) - 1)))
        } else if obj.object as? NSTextField == self.rangeTextField {
            if !checkPageRangeValidate(self.rangeTextField.stringValue) {
                let alert = NSAlert()
                alert.alertStyle = .critical
                alert.messageText = String(format: "%@%@", self.preViewPDFView.document.documentURL.lastPathComponent.lastPathComponent,KMLocalizedString("Invalid page range or the page number is out of range. Please try again.", nil))
                alert.beginSheetModal(for: NSApp.mainWindow!, completionHandler: nil)
                return
            }
        }
    }
    func checkPageRangeValidate(_ pageRangeString: String) -> Bool { 
        let fileAttribute = KMFileAttribute()
        fileAttribute.filePath = self.preViewPDFView.document?.documentURL?.path ?? ""
        fileAttribute.bAllPage = false
        fileAttribute.pagesString = self.rangeTextField.stringValue
        if fileAttribute.fetchSelectPages().isEmpty || fileAttribute.fetchSelectPages().count < 1{
            return false
        }
        return true
    }
    override func mouseDown(with event: NSEvent) {
        super.mouseDown(with: event)
        self.window?.makeFirstResponder(nil)
    }
    @objc func pageChangeNotification(_ notification: Notification) {
        self.currentPageTextField.stringValue = self.preViewPDFView.currentPage().label ?? ""
    }
    func PDFConvertObject2(_ converter: PDFConvertObject, didEndConversion error: Error?) {
        self.hideWaitting() 
        self.window?.sheetParent?.endSheet(self.window!)
    }
    func showWaitting() { 
        if self.maskView == nil {
            self.maskView = KMBookletMaskView(frame: CGRect(x: 0, y: 0, width: self.window?.frame.size.width ?? 0, height: self.window?.frame.size.height ?? 0))
        }
        self.window?.contentView?.addSubview(self.maskView!)
    }
    func hideWaitting() {
        self.maskView?.removeFromSuperview()
    }
    func beginSheetModal(for window: NSWindow, completionHandler handler: ((NSInteger) -> Void)?) {
        self.window?.beginSheet(window, completionHandler: { returnCode in
            NSApp.endSheet(self.window!, returnCode: NSApplication.ModalResponse.abort.rawValue)
            if let handler = handler {
                handler(returnCode.rawValue)
            }
        })
    }
   
}