//
//  KMBatchOperateLeftViewController.swift
//  PDF Reader Pro
//
//  Created by kdanmobile on 2023/10/26.
//

import Cocoa

let KMBatchDragType = "KMBatchDragType"

class KMBatchOperateLeftViewController: NSViewController,NSTableViewDelegate,NSTableViewDataSource{
    
    @IBOutlet var selectFileButton: KMLongerButton!
    
    @IBOutlet var deleteFileButton: NSButton!
    
    @IBOutlet var tableView: NSTableView!
    
    @IBOutlet var indexTableColumn: NSTableColumn!
    
    @IBOutlet var fileNameTableColumn: NSTableColumn!
    
    @IBOutlet var pageRangeTableColumn: NSTableColumn!
    
    @IBOutlet var sizeTableColumn: NSTableColumn!
    
    @IBOutlet var stateTableColumn: NSTableColumn!
    
    @IBOutlet var DPIColumn: NSTableColumn!
    
    @IBOutlet var dimensionsTableColumn: NSTableColumn!
    
    @IBOutlet var headerOperateView: NSView!
    
    @IBOutlet var showInFinderMenuItem: NSMenuItem!
    
    @IBOutlet var deleteMenuItem: NSMenuItem!
    
    @IBOutlet var blankView: KMBlankView!
    
    var files: [KMBatchOperateFile] = []
    var type: KMBatchOperationType?
    var lockFilePathArr: NSMutableArray?
    var lockFileIndex: Int = 0
    var popOver: NSPopover?
    var progressInt: Int = 0
    
    deinit {
        NotificationCenter.default.removeObserver(self)
        DistributedNotificationCenter.default().removeObserver(self)
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self.tableView!, selector: #selector(self.reloadData), name: NSNotification.Name(kNeedChangePageRangeNotification), object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(imageToPDFSuccessNotification(aNotification:)), name: NSNotification.Name("KMBatchOperateImageToPDFSuccessNotification"), object: nil)
        DistributedNotificationCenter.default.addObserver(self, selector: #selector(themeChanged(notification:)), name: NSNotification.Name("AppleInterfaceThemeChangedNotification"), object: nil)
        
        for i in 0..<self.tableView.tableColumns.count {
            let column = self.tableView.tableColumns[i]
            column.headerCell = KMTableHeaderCell(textCell: column.title)
        }
        
        self.deleteFileButton.addHoverEffect = true
        
        self.indexTableColumn.resizingMask =  []
        self.fileNameTableColumn.resizingMask = .autoresizingMask
        self.pageRangeTableColumn.resizingMask =  []
        self.sizeTableColumn.resizingMask =  []
        self.stateTableColumn.resizingMask =  []
        self.DPIColumn.resizingMask =  []
        self.dimensionsTableColumn.resizingMask =  []
        self.tableView.moveColumn(5, toColumn: 2)
        
        self.indexTableColumn.title = "  \(NSLocalizedString("Index", comment: ""))"
        self.fileNameTableColumn.title = NSLocalizedString("File Name", comment: "")
        self.pageRangeTableColumn.title = NSLocalizedString("Page Range", comment: "")
        self.sizeTableColumn.title = NSLocalizedString("Size", comment: "")
        self.stateTableColumn.title = NSLocalizedString("Status", comment: "")
        self.DPIColumn.title = NSLocalizedString("DPI", comment: "")
        self.dimensionsTableColumn.title = NSLocalizedString("Dimensions", comment: "")
        
        self.DPIColumn.isHidden = true
        self.tableView.intercellSpacing = CGSize(width: 0, height: 0)
        self.tableView.backgroundColor = KMAppearance.Layout.bgColor()
        self.tableView.allowsColumnReordering = false
        self.tableView.allowsMultipleSelection = true
        self.tableView.enclosingScrollView?.borderType = .noBorder
        
        self.headerOperateView.wantsLayer = true
        
        self.tableView.registerForDraggedTypes([NSPasteboard.PasteboardType.string,NSPasteboard.PasteboardType.fileURL]) //[KMBatchDragType,NSFilenamesPboardType]
        self.lockFilePathArr = NSMutableArray()
        self.lockFileIndex = 0
        self.progressInt = 0
        
        self.selectFileButton.title = " " + NSLocalizedString("Add Files", comment: "")
        self.selectFileButton.wantsLayer = true
        self.selectFileButton.layer?.borderWidth = 1.0
        self.selectFileButton.layer?.borderColor = KMAppearance.Interactive.m0Color().cgColor
        self.selectFileButton.layer?.cornerRadius = 1.0
        self.selectFileButton.setTitleColor(KMAppearance.Layout.mColor())
        self.selectFileButton.containerViewController = self
        
        self.showInFinderMenuItem.title = NSLocalizedString("Show in Finder", comment: "")
        self.deleteMenuItem.title = NSLocalizedString("Delete", comment: "")
        self.blankView.wantsLayer = true
        self.blankView.layer?.backgroundColor = NSColor.clear.cgColor
        self.blankView.titleLabel.stringValue = NSLocalizedString("Select Files", comment: "")
        self.blankView.imageView.isHidden = true
        self.blankView.addButton.isHidden = false
        self.blankView.secondTitleLabel.stringValue = NSLocalizedString("Drop files here or Click Add Files at upper left corner. You can drag files to reorder as you need.", comment: "")
        self.blankView.mouseActionCallBack = { [weak self] mouseType in
            guard let self = self else { return }
            if mouseType == .mouseEnter {
                self.blankView.imageView.image = NSImage(named: "KMImageNameEmptyListHov")
            } else if mouseType == .mouseExit {
                self.blankView.imageView.image = NSImage(named: "KMImageNameEmptyListNor")
            } else if mouseType == .mouseDown {
                self.blankView.imageView.image = NSImage(named: "KMImageNameEmptyListPre")
                self.chooseFile()
            } else if mouseType == .mouseUp {
                self.blankView.imageView.image = NSImage(named: "KMImageNameEmptyListHov")
            }
        }
        updateViewColor()
    }
    @objc func reloadData() {
        if Thread.isMainThread {
            tableView.reloadData()
        } else {
            DispatchQueue.main.async {
                self.tableView.reloadData()
            }
        }
    }
    
    @objc func imageToPDFSuccessNotification(aNotification: Notification) {
        guard let dict = aNotification.userInfo, let isSuccess = dict["isSuccess"] as? Bool else { return }
        if isSuccess {
            progressInt = 1
        } else {
            progressInt = -1
        }
        
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
    }
    @objc func themeChanged(notification: Notification) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: {
            self.updateViewColor()
        })
    }
    
    func updateViewColor() {
        self.view.wantsLayer = true
        if KMAppearance.isDarkMode() {
            self.headerOperateView.layer?.backgroundColor = NSColor(red: 0.055, green: 0.067, blue: 0.078, alpha: 1).cgColor
        } else {
            self.headerOperateView.layer?.backgroundColor = NSColor(red: 0.922, green: 0.925, blue: 0.941, alpha: 1).cgColor
        }
    }
    
    func chooseFile() {
#if VERSION_FREE
        if KMMemberInfo.shared.isMemberAllFunction == false {
            if files.count >= 1 {
                let winC = KMProductCompareWC.shared
                if type == .CreatePDF {
                    winC.kEventName = "Onbrd_ImagetoPDF_BuyNow"
                }
                KMMemberInfo.shared.advancedFunctionUsage(type: .batch)
                return
            }
        }
#endif
        self.progressInt = 0
        let panel = NSOpenPanel() 
        if type == .CreatePDF {
            panel.allowedFileTypes = KMImageToPDFMethod.supportedImageTypes()
        } else {
            panel.allowedFileTypes = ["pdf", "PDF"]
        }
        if KMMemberInfo.shared.isMemberAllFunction {
            panel.allowsMultipleSelection = true
            panel.canChooseDirectories = true
        }
        panel.canChooseFiles = true
#if VERSION_FREE
#else
        panel.message = NSLocalizedString("To select multiple files press cmd ⌘ button on keyboard and click on the target files one by one.", comment: "")
#endif
        panel.beginSheetModal(for: self.view.window!) {
            (result) in
            if result.rawValue == NSApplication.ModalResponse.OK.rawValue {
                let addArray = NSMutableArray()
                for fileURL in panel.urls {
                    let filePath = fileURL.path
                    var isDirectory = ObjCBool(false)
                    FileManager.default.fileExists(atPath: filePath, isDirectory: &isDirectory)
                    if isDirectory.boolValue {
                        let containFiles = self.fetchAvailableFiles(in: filePath)
                        addArray.addObjects(from: containFiles)
                    } else {
                        
                        let typeIdentifier =
                              UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, filePath.customPathExtension as CFString, nil)
                        let TypeCFString = typeIdentifier!.takeRetainedValue() as String
                        if self.type == .CreatePDF {
                            if UTTypeConformsTo(TypeCFString as CFString, kUTTypeImage) {
                                addArray.add(filePath)
                            }
                        } else {
                            if UTTypeConformsTo(TypeCFString as CFString, kUTTypePDF) {
                                addArray.add(filePath)
                            }
                        }
                    }
                }
                self.addFilesToList(addArray: addArray)
            }
        }
    }
    func fetchAvailableFiles(in folderPath: String) -> [String] {
        let array = NSMutableArray()
        let subFileArray = (FileManager.default.subpaths(atPath: folderPath)! as NSArray).mutableCopy() as? NSMutableArray
        for i in 0..<subFileArray!.count {
            if let path = (folderPath as NSString).appendingPathComponent(subFileArray!.object(at: i) as! String) as String? {
                if let UTTypeString = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, path.customPathExtension as CFString, nil)?.takeRetainedValue() as String? {
                    let TypeCFString = UTTypeString as CFString
                    if self.type == .CreatePDF {
                        if UTTypeConformsTo(TypeCFString, kUTTypeImage) {
                            array.add(path)
                        }
                    } else {
                        if UTTypeConformsTo(TypeCFString, kUTTypePDF) {
                            array.add(path)
                        }
                    }
                }
            }
        }
        return array as! [String]
    }
    func addFilesToList(addArray: NSMutableArray) {
        self.lockFilePathArr!.removeAllObjects()
        self.lockFileIndex = 0
        for i in 0..<addArray.count {
            let filePath = addArray[i] as! String
            let UTTypeString = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, filePath.customPathExtension as CFString, nil)!.takeRetainedValue() as String
            let TypeCFString = UTTypeString as CFString
            if UTTypeConformsTo(TypeCFString, kUTTypePDF) {
                let document = CPDFDocument(url: URL(fileURLWithPath: filePath))
                if document?.isLocked == true {
                    var isContaint = false
                    for file in self.files {
                        if (file as AnyObject).filePath == filePath {
                            isContaint = true
                            break
                        }
                    }
                    if !isContaint {
                        self.lockFilePathArr!.add(filePath)
                    }
                } else {
                    let file = KMBatchOperateFile(filePath: addArray[i] as! String, type: self.type!)
                    if !self.files.contains(file) {
                        self.files.append(file)
                    }
                }
            } else {
                let file = KMBatchOperateFile(filePath: addArray[i] as! String, type: self.type!)
                if !self.files.contains(file) {
                    self.files.append(file)
                }
            }
        }
        self.tableView.reloadData()
        if self.lockFilePathArr!.count > 0 {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                self.openPasswordWindow()
            }
        }
    }
    func openPasswordWindow() {
        
        if lockFilePathArr!.count > lockFileIndex {
            let filePath = lockFilePathArr![lockFileIndex] as! String
            KMBaseWindowController.checkPassword(url: URL(fileURLWithPath: filePath), type: .owner) { [unowned self] success, resultPassword in
                self.closePwd()
                if !resultPassword.isEmpty {
                    let file = KMBatchOperateFile(filePath: filePath, type: self.type!)
                    file.password = resultPassword
                    self.files.append(file)
                    self.tableView.reloadData()
                }
                self.lockFileIndex += 1
                if self.lockFilePathArr?.count ?? 0 > self.lockFileIndex {
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                        self.openPasswordWindow()
                    }
                } else {
                    self.tableView.reloadData()
                }
            }
        }
    }
    func closePwd() {
        self.km_endSheet()
    }
    
    func chooseFileFromCamera() {
        self.progressInt = 0
        let vc = KMDeviceBrowserWindowController.shared
        vc.type = .camera
        vc.importCameraFileCallback = { [weak self](url: NSURL) -> Void in
            self?.addFilesToList(addArray: [url.path!])
        }
        vc.showWindow(nil)
    }
    func chooseFileFromScanner() {
        self.progressInt = 0
        let vc = KMDeviceBrowserWindowController.shared
        vc.type = .scanner
        vc.importScannerFileCallback = { [weak self](url: NSURL) -> Void in
            self?.addFilesToList(addArray: [url.path!])
        }
        vc.showWindow(nil)
    }
    
    @IBAction func buttonClicked_SelectFile(_ sender: Any) {
        
    }
    
    
    @IBAction func blankViewAddFileAction(_ sender: Any) {
        self.chooseFile()
    }
    
    @IBAction func buttonClicked_DeleteFile(_ sender: Any) {
        let set = self.tableView.selectedRowIndexes
        let newArr: NSMutableArray = NSMutableArray.init(array: self.files)
        let arr = newArr.objects(at: set)
        if arr.count > 0 {
            newArr.removeObjects(in: arr)
            self.files = newArr as! [KMBatchOperateFile]
            self.tableView.reloadData()
        } else {
//            if KMAlertWindowController.needShowRemoveAllFilesHint() {
                let alert = NSAlert()
                alert.alertStyle = .critical
                alert.messageText = NSLocalizedString("Clear All Recents", comment: "")+"?"
                alert.addButton(withTitle: NSLocalizedString("Delete", comment: ""))
                alert.addButton(withTitle: NSLocalizedString("Cancel", comment: ""))
                alert.beginSheetModal(for: self.view.window!) {[weak self] response in
                    if response == NSApplication.ModalResponse.alertFirstButtonReturn {
                        self?.files.removeAll()
                        self?.tableView.reloadData()
                    }
                }
//            } else {
//                self.files.removeAll()
//                self.tableView.reloadData()
//            }
        }
    }
    func fetchAvailableFilesInFolder(_ folderPath: String) -> [String] {
        var array: [String] = []
        let subFileArray = FileManager().subpaths(atPath: folderPath)
        for i in 0..<subFileArray!.count {
            let path = folderPath.stringByAppendingPathComponent(subFileArray![i])
            let TypeCFString = KMTools.UTIforFileExtension(path.customPathExtension) as CFString
            if self.type == .CreatePDF {
                if UTTypeConformsTo(TypeCFString, kUTTypeImage) {
                    array.append(path)
                }
            } else {
                if UTTypeConformsTo(TypeCFString, kUTTypePDF) {
                    array.append(path)
                }
            }
//            UTTypeString?.release()
        }
        return array
    }
    func folderContainAvailableFile(_ folderPath: String) -> Bool {
        var containFile = false
        guard let subFileArray = FileManager.default.subpaths(atPath: folderPath) else {
            return containFile
        }
        for i in 0..<subFileArray.count {
            let path = folderPath.stringByAppendingPathComponent(subFileArray[i] )
            let TypeCFString = KMTools.UTIforFileExtension(path.customPathExtension) as CFString
            if type == .CreatePDF {
                if UTTypeConformsTo(TypeCFString, kUTTypeImage) {
                    containFile = true
                }
            } else {
                if UTTypeConformsTo(TypeCFString, kUTTypePDF) {
                    containFile = true
                }
            }
//            UTTypeString?.release()
            if containFile {
                break
            }
        }
        return containFile
    }
    func switchToOperateType(_ type: KMBatchOperationType) {
        self.type = type
        self.indexTableColumn.isHidden = false
        self.fileNameTableColumn.isHidden = false
        self.pageRangeTableColumn.isHidden = false
        self.sizeTableColumn.isHidden = false
        self.stateTableColumn.isHidden = false
        self.DPIColumn.isHidden = true
        self.dimensionsTableColumn.isHidden = true
        if type == .Compress || type == .AddPassword || type == .RemovePassword || type == .RemoveWatermark || type == .RemoveBackground || type == .RemoveHeaderFooter || type == .RemoveBates || type == .CreatePDF {
            self.pageRangeTableColumn.isHidden = true
        } else {
            self.pageRangeTableColumn.isHidden = false
        }
        
        self.selectFileButton.isImageToPDF = type == .CreatePDF
        if type == .CreatePDF {
            self.pageRangeTableColumn.isHidden = false
            self.pageRangeTableColumn.title = NSLocalizedString("Dimensions", comment: "")
        }
        
        for i in 0..<self.files.count {
            let file = self.files[i]
            file.currentOperateType = type
        }
        self.tableView.sizeToFit()
        self.tableView.reloadData()
    }
    
    @IBAction func menuItem_ShowInFinder(_ sender: Any) {
        let row = self.tableView.clickedRow
        let file: KMBatchOperateFile = self.files[row]
        if file.currentOperateInfo?.status == .Success {
            NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: file.currentOperateInfo!.outPutPath!)])
        }else {
            NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: file.filePath)])
        }
    }
    
    @IBAction func menuItem_Delete(_ sender: Any) {
        let row = self.tableView.clickedRow
        self.files.remove(at: row)
        self.tableView.reloadData()
    }
  
    
    func addOpendFile() {
        let documentArray = NSDocumentController.shared.documents
        var pdfArray = NSMutableArray()
        for i in 0..<documentArray.count {
            let document = documentArray[i]
            let path: String = document.fileURL?.path ?? ""
            let UTTypeString = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, path.customPathExtension as CFString, nil)?.takeRetainedValue() as String?
            let TypeCFString = UTTypeString as CFString?
            if UTTypeConformsTo(TypeCFString!, kUTTypePDF) {
                pdfArray.add(path as Any)
            } else {
            }
        }
        if KMMemberInfo.shared.isMemberAllFunction == false {
            if self.files.count < 1 {
                pdfArray = NSMutableArray(array: [pdfArray.firstObject as Any])
            } else {
                KMMemberInfo.shared.advancedFunctionUsage(type: .batch)
                return
            }
        }
        addFilesToList(addArray: pdfArray)
    }
    func numberOfRows(in tableView: NSTableView) -> Int {
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "KMBatchFilesCountNotification"), object: self.files, userInfo: [kObjectKey : self])
        self.deleteFileButton.isEnabled = self.files.count > 0
        self.blankView.isHidden = self.files.count > 0
        return self.files.count;
    }
    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
        let identifier = tableColumn?.identifier
        let file = self.files[row]
      
        if identifier?.rawValue == "index" {
            let cellView = KMBatchTableCellView(type: .Size)
            _ = row + 1
            cellView.textField?.stringValue = String(format: "%d", row + 1);
            return cellView;
        } else if identifier?.rawValue == "pageRange"{
            if (file.currentOperateType == .CreatePDF) {
                let cellView = KMBatchTableCellView(type: .Size)
                
                if (file.fileType == .Image) {
                    let image = NSImage(contentsOfFile: file.filePath)
                    cellView.textField?.stringValue = String(Int(image?.size.width ?? 0)) + "x" + String(Int(image?.size.height ?? 0))
                }
             
                return cellView;
            } else {
                let cellView = KMBatchTableCellView(type: .PageRange)
                cellView.updateInterface(file)
                return cellView;
            }
        } else if identifier?.rawValue == "status"{
            let cellView = KMBatchTableCellView(type: .Status)
            if (file.currentOperateType == .CreatePDF) {
                cellView.updateInterface(file: file, progress: file.progress ?? 0)
            } else {
                cellView.updateInterface(file: file, progress: file.progress ?? 0)
            }
            cellView.removeFileCallBack = { [weak self] file in
                self?.files.removeObject(file)
                self?.tableView.reloadData()
            }
            return cellView;
        } else if identifier?.rawValue == "size"{
            let cellView = KMBatchTableCellView(type: .Size)
            cellView.updateInterface(file)
            return cellView;
        } else if identifier?.rawValue == "fileName"{
            let cellView = KMBatchTableCellView(type: .FileName)
            cellView.updateInterface(file)
            let rowView: KMBatchTableRowView = tableView.rowView(atRow: row, makeIfNecessary: true) as! KMBatchTableRowView
            if ((file.error) != nil) {
                rowView.backgroundColor = KMAppearance.Status.errBGColor();
            }
            return cellView;
        } else if identifier?.rawValue == "dpi"{
            let cellView = KMBatchTableCellView(type: .DPI)
            cellView.updateInterface(file)
            return cellView;
        } else if identifier?.rawValue == "dimensions"{
            let cellView = KMBatchTableCellView(type: .Size)
            
            if (file.fileType == .Image) {
                let image = NSImage(contentsOfFile: file.filePath)
                cellView.textField?.stringValue = String(Int(image?.size.width ?? 0)) + "x" + String(Int(image?.size.height ?? 0))
            }
         
            return cellView;
        }
        return nil;
    }
    func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
        let file = self.files[row]
        if self.type == .CreatePDF {
            if (file.error != nil) {
                return 64
            } else {
                return 40
            }
        } else {
            if file.fileType == .PDF {
                if (file.error != nil) {
                    return 64
                } else {
                    return 40
                }
            } else {
                return 0.0000001
            }
        }
    }
    func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
        let rowView = KMBatchTableRowView()
        return rowView
    }
    func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool {
        let indexSetData = try? NSKeyedArchiver.archivedData(withRootObject: rowIndexes, requiringSecureCoding: true)
        pboard.declareTypes([NSPasteboard.PasteboardType.string], owner: self)
        pboard.setData(indexSetData, forType: NSPasteboard.PasteboardType(rawValue: KMBatchDragType) )
        return true
    }
    func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int, proposedDropOperation dropOperation: NSTableView.DropOperation) -> NSDragOperation {
        var isCanDrag = false
        var result: NSDragOperation = []
        let pboard = info.draggingPasteboard
        if pboard.availableType(from: [.fileURL]) != nil {
            guard let pbItems = pboard.pasteboardItems else {
                return NSDragOperation(rawValue: 0)
            }
            var hasValidFile = false
            
            for item in pbItems {
                guard let data = item.string(forType: .fileURL), let _url = URL(string: data) else {
                    continue
                }
                var isDirectory: ObjCBool = false
                let fileExists = FileManager.default.fileExists(atPath: _url.path, isDirectory: &isDirectory)
                if fileExists && isDirectory.boolValue {
                    let containFile = folderContainAvailableFile(_url.path)
                    if containFile {
                        isCanDrag = true
                        break
                    }
                } else {
                    if let UTType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, _url.pathExtension as CFString, nil)?.takeRetainedValue() as String? {
                        if self.type == .CreatePDF {
                            if UTTypeConformsTo(UTType as CFString, kUTTypeImage) {
                                isCanDrag = true
                            }
                        } else {
                            if UTTypeConformsTo(UTType as CFString, kUTTypePDF) {
                                isCanDrag = true
                            }
                        }
                    }
                    if isCanDrag {
                        break
                    }
                }
            }
            if isCanDrag {
                result = .copy
            }
            return result
        } else {
            return .move
        }
    }
    func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableView.DropOperation) -> Bool {
        let pboard = info.draggingPasteboard
        if pboard.availableType(from: [.init(KMBatchDragType)]) != nil {
            guard let rowData = pboard.data(forType: .init(KMBatchDragType)),
                  let rowIndexes = NSKeyedUnarchiver.unarchiveObject(with: rowData) as? NSIndexSet else { return false }
            let backUpArray = self.files
            var referenceIndex = -1
            rowIndexes.enumerate(options: .reverse, using: { (idx, stop) in
                let sortFile = backUpArray[idx]
                if referenceIndex < 0 {
                    if idx > row {
                        self.files.remove(at: idx)
                        self.files.insert(sortFile, at: row)
                    } else if idx < row {
                        if row > self.files.count {
                            self.files.remove(at: idx)
                            self.files.append(sortFile)
                        } else {
                            self.files.remove(at: idx)
                            self.files.insert(sortFile, at: row - 1)
                        }
                    }
                    referenceIndex = self.files.firstIndex(of: sortFile) ?? -1
                } else {
                    let currentIndex = self.files.firstIndex(of: sortFile) ?? -1
                    if currentIndex > referenceIndex {
                        self.files.remove(at: currentIndex)
                        self.files.insert(sortFile, at: referenceIndex)
                    } else {
                        referenceIndex -= 1
                        self.files.remove(at: currentIndex)
                        self.files.insert(sortFile, at: referenceIndex)
                    }
                }
            })
            self.tableView.reloadData()
            return true
        } else if pboard.availableType(from: [.fileURL]) != nil {
            if (pboard.pasteboardItems == nil) {
                
                return true
            }
           
            let allFilesArray = NSMutableArray()
            for item in pboard.pasteboardItems! {
                let fileURL = item.string(forType: .fileURL)
                if (fileURL == nil) {
                    continue
                }
                let path = URL.init(string: fileURL!)
                if (path == nil) {
                    continue
                }
                var isFolder = ObjCBool(false)
                FileManager.default.fileExists(atPath: path!.path, isDirectory: &isFolder)
                if isFolder.boolValue {
                    let containFiles = fetchAvailableFilesInFolder(path!.path)
                    allFilesArray.addObjects(from: containFiles)
                } else {
                    allFilesArray.add(path!.path)
                }
            }
            var insertArray = NSMutableArray()
            lockFilePathArr?.removeAllObjects()
            lockFileIndex = 0
            for i in 0..<allFilesArray.count {
                let filePath: String = allFilesArray[i] as! String
                
                if filePath.hasSuffix(".pdf") || filePath.hasSuffix(".PDF") {
                    let document = CPDFDocument(url: URL(fileURLWithPath: filePath))
                    if let pdf = CPDFDocument(url: URL(fileURLWithPath: filePath)) {
                        if !pdf.allowsPrinting || !pdf.allowsCopying {
                            let alert = NSAlert()
                            alert.alertStyle = .critical
                            alert.messageText = NSLocalizedString("This is a secured document. Editing is not permitted.", comment: "")
                            alert.runModal()
                            continue
                        } else if document?.isLocked ?? false {
                            lockFilePathArr?.add(filePath)
                        } else {
                            let file = KMBatchOperateFile(filePath: filePath, type: self.type!)
                            if !(self.files.contains(file) ) {
                                insertArray.add(file)
                            }
                        }
                    }
                } else {
                    let file = KMBatchOperateFile(filePath: filePath, type: self.type!)
                    if !(self.files.contains(file) ) {
                        insertArray.add(file)
                    }
                }
            }
            if KMMemberInfo.shared.isMemberAllFunction == false {
                if self.files.count < 1 && insertArray.count > 0 {
                    let firstObject = insertArray.firstObject
                    insertArray.removeAllObjects()
                    insertArray.add(firstObject as Any)
                } else {
                    KMMemberInfo.shared.advancedFunctionUsage(type: .batch)
                    return false
                }
            }
            for i in 0..<insertArray.count {
                self.files.insert(insertArray[i] as! KMBatchOperateFile, at: row + i)
            }
            self.tableView.reloadData()
            if lockFilePathArr!.count > 0 {
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                    self.openPasswordWindow()
                }
            }
            return true
        }
        return false
    }
    func switchToOperateType(_ operateType: KMBatchOperationType, files: [KMBatchOperateFile]) {
        switchToOperateType(operateType)
        self.files = files 
        self.tableView.reloadData()
    }
    func checkNeedPasswordSwitchToOperateType(_ operateType: KMBatchOperationType, files: [KMBatchOperateFile]) {
        switchToOperateType(operateType)
        var arr: [String] = []
        for i in 0..<files.count {
            let file = files[i]
            arr.append(file.filePath)
        }
        
        self.files = files
        self.files.removeAll()
        addFilesToList(addArray: NSMutableArray.init(array: arr))
        self.tableView.reloadData()
    }
    func reloadFile(_ file: KMBatchOperateFile) {
        var rowIndexSet = IndexSet()
        for i in 0..<self.files.count {
            if file.filePath == self.files[i].filePath {
                rowIndexSet.insert(i)
                break
            }
        }
        var columnIndexSet = IndexSet()
        for i in 0..<self.tableView.numberOfColumns {
            let identifier = self.tableView.tableColumns[i].identifier
            if identifier.rawValue == "status" {
                columnIndexSet.insert(i)
                break
            }
        }
        
        if Thread.isMainThread {
            self.tableView.reloadData(forRowIndexes: rowIndexSet, columnIndexes: columnIndexSet)
        } else {
            DispatchQueue.main.async {
                self.tableView.reloadData(forRowIndexes: rowIndexSet, columnIndexes: columnIndexSet)
            }
        }
    }
    func refreshConvertProgress(_ progress: CGFloat, file: KMBatchOperateFile) {
        self.tableView.reloadData()
    }
    func reloadConvertInterface(withType type: KMConvertWithPDFType) {
        if type == .WordAdvance || type == .WordStandard || type == .Excel || type == .PowerPoint || type == .RTF || type == .CSV || type == .HTML || type == .Text || type == .Json {
            self.DPIColumn.isHidden = true
        } else {
            self.DPIColumn.isHidden = false
        }
        self.tableView.reloadData()
    }
}

extension KMBatchOperateLeftViewController: NSMenuDelegate, NSMenuItemValidation{
    func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
        let action = menuItem.action
        if action == #selector(menuItem_ShowInFinder(_:)) || action == #selector(menuItem_Delete(_:)) {
            if tableView.clickedRow == -1 {
                return false
            }
            return true
        }
        return true
    }
}