//
//  KMMergeViewController.swift
//  PDF Master
//
//  Created by tangchao on 2022/11/23.
//

import Cocoa
import PDFKit
import CoreGraphics

class KMMergePage: CPDFPage {
    var drawingPage: CPDFPage!
    
//    override func draw(with box: PDFDisplayBox) {
//        super.draw(with: box)
//
//        let context: CGContext = NSGraphicsContext.current?.graphicsPort as! CGContext
//        let pageSize = bounds(for: .cropBox).size
//
//        drawPageWithContext(context: context, page: self.drawingPage, pageSize: pageSize)
//    }
    
    override func draw(with box: CPDFDisplayBox, to context: CGContext!) {
        super.draw(with: box, to: context)
        let pageSize = bounds(for: .cropBox).size
        
        drawPageWithContext(context: context, page: self.drawingPage, pageSize: pageSize)
    }
    
    func drawPageWithContext(context: CGContext, page: CPDFPage, pageSize: NSSize) {
        var originalSize = page.bounds(for: .cropBox).size
        
        /// 如果page的旋转角度为90,或者270,宽高交换
        if ((page.rotation % 180) != 0) {
            originalSize = NSSize(width: originalSize.height, height: originalSize.width)
        }
        
        let wRadio: CGFloat = pageSize.width/originalSize.width
        let hRadio: CGFloat = pageSize.height/originalSize.height
        let radio = min(wRadio, hRadio)
        
        context.saveGState()
        var xTransform: CGFloat = (pageSize.width-originalSize.width * radio) / 2
        var yTransform: CGFloat = (pageSize.height-originalSize.height * radio) / 2
        context.translateBy(x: xTransform, y: yTransform)
        context.scaleBy(x: radio, y: radio)
        
        page.draw(with: .cropBox, to: context)
        page.transform(context, for: .cropBox)
        
        
//        var contextRef: CGContextRef = context
    }
}

class KMMergeTestWindow: NSWindow {
    
    private var mergeController: KMMergeViewController!
    
    override init(contentRect: NSRect, styleMask style: NSWindow.StyleMask, backing backingStoreType: NSWindow.BackingStoreType, defer flag: Bool) {
        super.init(contentRect: contentRect, styleMask: style, backing: backingStoreType, defer: flag);
        
        isReleasedWhenClosed = false
        
        let controller: KMMergeViewController = KMMergeViewController()
        contentView?.addSubview(controller.view)
        controller.view.frame = CGRect(x: 0, y: 0, width: contentRect.size.width, height: contentRect.size.height)
        mergeController = controller
    }
    
}

protocol KMMergeViewController_collectionView_delegate : NSObjectProtocol {
    func collection_menu(for event: NSEvent) -> NSMenu?
}

class KMMergeViewController_collectionView: NSCollectionView {
    
    weak var myDelegate: KMMergeViewController_collectionView_delegate!
    
    override func menu(for event: NSEvent) -> NSMenu? {
        guard let myDelegate = self.myDelegate else {
            return super.menu(for: event)
        }
        
        return myDelegate.collection_menu(for: event)
        
//        return super.menu(for: event)
    }
}

class KMMergeViewController: NSViewController {

    @IBOutlet weak var titleBar: NSBox!
    @IBOutlet weak var contentBox: NSBox!
    
    private var titleBarView: KMMergeTitleBar?
    private var scrollView: NSScrollView?
    private var contentionView: KMMergeViewController_collectionView?
    
    private var zoomScale: CGFloat = 0
    private var zoomMinScale: CGFloat = 0.5
    private var zoomMaxScale: CGFloat = 8
    
    private lazy var dataArray: [KMMergeFileModel] = []
    private lazy var deleteArray: [Int] = []
    
    private var dragedIndexPaths: [IndexPath] = []
    private let localForDraggedTypes = NSPasteboard.PasteboardType(rawValue: "localForDraggedTypes")
    
    private var pageRangeWindowController: KMPageRangePickerWindowController!
    private var mergeSettingWindowController: KMMergeSettingWindowController!
    
    private var outPDFDocument = CPDFDocument()
    
    private var lockedFiles: [URL] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        initDefaultValue()
        initSubViews()
    }
    
    /**
     * MARK: - 初始化值
     */
    func initDefaultValue() {
        titleBar.titlePosition = NSBox.TitlePosition.noTitle
        titleBar.contentViewMargins = NSSize.zero
        titleBar.boxType = NSBox.BoxType.custom
        titleBar.borderWidth = 0
        
        zoomScale = 0
    }
    
    func initSubViews() {
        let titleBarView_: KMMergeTitleBar = KMMergeTitleBar()
        titleBar.contentView?.addSubview(titleBarView_)
        titleBarView_.frame = NSMakeRect(0, 0, NSWidth(titleBar.bounds), NSHeight(titleBar.bounds))
        titleBarView_.autoresizingMask = NSView.AutoresizingMask(rawValue: 18)
        titleBarView_.delegate = self
        titleBarView_.wantsLayer = true
        titleBarView_.layer?.backgroundColor = NSColor.white.cgColor
        titleBarView = titleBarView_
        titleBarView?.setDeleteItemEnable(enable: false)
        titleBarView?.setPageRangeComboBoxHidden(isHidden: true)
        
        titleBarView_.itemClick = {
            [self] (itemIndex: KMMergeTitleBarButtonID) -> () in
            switch itemIndex {
            case .add:
                self.showAddMenu()
                break
            case .delete:
                for index in deleteArray {
                    if index < dataArray.count {
                        dataArray.remove(at: index)
                    }
                }
                deleteArray.removeAll()
                self.titleBarView?.setDeleteItemEnable(enable: false)
                self.contentionView?.reloadData()
                break
            case .zoomOut:
                if zoomScale > zoomMaxScale {
                    titleBarView?.setZoomItemEnable(zoomIn: false, enable: false)
                    return
                }
                
                titleBarView?.setZoomItemEnable(zoomIn: true, enable: true)
                zoomScale += 0.5
                
                contentionView?.reloadData()
                break
            case .zoomIn:
                if zoomScale < zoomMinScale {
                    titleBarView?.setZoomItemEnable(zoomIn: true, enable: false)
                    return
                }
                
                titleBarView?.setZoomItemEnable(zoomIn: false, enable: true)
                zoomScale -= 0.5
                contentionView?.reloadData()
                break
            case .merge:
                if dataArray.count == 0 {
                    let alert = NSAlert()
                    alert.messageText = NSLocalizedString("没有文件", comment: "")
                    alert.runModal()
                    
                    return
                }
                
                let windowController = KMMergeSettingWindowController.init(windowNibName: "KMMergeSettingWindowController")
                self.view.window?.beginSheet(windowController.window!)
                mergeSettingWindowController = windowController
                windowController.odd_even_mergeComboBox.isEnabled = dataArray.count == 2
                
                windowController.cancelClick = {
                    [self] (window: NSWindow) -> () in
                    
                    self.view.window?.endSheet(window)
                }
                
                windowController.mergeClick = {
                    [self] (windowController: NSWindowController) -> () in
                    
                    if mergeSettingWindowController.odd_even_mergeComboBox.state == .on { /// 奇偶数穿插合并
                        let document = CPDFDocument()
                        outPDFDocument = document
                        
                        mergeActionForOddEven()
                        
                        let panel = NSSavePanel()
                        panel.nameFieldStringValue = "[新文件].pdf"
                        let button = NSButton.init(checkboxWithTitle: "保存后打开文档", target: nil, action: nil)
                        button.state = .on
                        panel.accessoryView = button
                        panel.isExtensionHidden = true
                        let response = panel.runModal()
                        if response == .OK {
                            let url = panel.url
                            let result = outPDFDocument!.write(to: panel.url!)
                            if result {
                                if button.state == .on { /// 开启文档

                                } else {
                                    NSWorkspace.shared.openFile(url!.path)
                                }
                            }
                        }
                    } else { /// 正常合并
                        let document = CPDFDocument()
                        outPDFDocument = document
                        
                        mergeAction()
                        let panel = NSSavePanel()
                        panel.nameFieldStringValue = "[新文件].pdf"
                        let button = NSButton.init(checkboxWithTitle: "保存后打开文档", target: nil, action: nil)
                        button.state = .on
                        panel.accessoryView = button
                        panel.isExtensionHidden = true
                        let response = panel.runModal()
                        if response == .OK {
                            let url = panel.url
                            let result = document!.write(to: panel.url!)
                            if result {
                                if button.state == .on { /// 开启文档

                                } else {
                                    NSWorkspace.shared.openFile(url!.path)
                                }
                            }
                        }
                    }
                    
                    self.view.window?.endSheet(windowController.window!)
                }
                break
            case .cancel:
                if dataArray.count == 0 {
                    self.view.window?.close()
                } else {
                    let alert = NSAlert()
                    alert.messageText = NSLocalizedString("关闭将不会保存当前操作", comment: "")
                    alert.addButton(withTitle: NSLocalizedString("关闭", comment: ""))
                    alert.addButton(withTitle: NSLocalizedString("取消", comment: ""))
                    let response = alert.runModal()
                    if response == .alertFirstButtonReturn {
                        self.view.window?.close()
                    }
                }
 
                break
            }
        }
        titleBarView_.pageRangeClick = {
            [self] (index: Int, pageString: String) -> () in
            let model = self.titleBarView?.model
            if index == 0 {
                model?.pageRange = .all
                model?.updateChildPageRange(pageRange: .all)
            } else if index == 1 {
                model?.pageRange = .oddPages
                model?.updateChildPageRange(pageRange: .oddPages)
            } else if index == 2 {
                model?.pageRange = .evenPages
                model?.updateChildPageRange(pageRange: .evenPages)
            } else if index == 3 {
                if !isValidPagesString(pagesString: pageString) {
                    let alert = NSAlert()
                    alert.alertStyle = .warning
                    alert.messageText = NSLocalizedString("Invalid page range or the page number is out of range. Please try again.", comment: "")
                    alert.runModal()
                    return
                }
                
                model?.pageRangeString = pageString
                model?.updateChildPageRange(pageRange: .custom)
                
                let pageNumbers = findSelectPage(fileModel: model!)
                for i in 0 ... (model?.pages.count)!-1 {
                    let pageModel = model?.pages[i]
                    if pageNumbers .contains(Int(pageModel!.pageID)+1) {
                        pageModel!.selected = true
                    } else {
                        pageModel!.selected = false
                    }
                }
                
            }
            
            self.contentionView?.reloadData()
        }
        
        let scrollView_ = NSScrollView()
        contentBox.contentView?.addSubview(scrollView_)
        scrollView_.frame = NSMakeRect(0, 0, NSWidth(contentBox.bounds), NSHeight(contentBox.bounds))
        scrollView_.autoresizingMask = NSView.AutoresizingMask(rawValue: 18)
        scrollView = scrollView_
        

        let layout = NSCollectionViewFlowLayout()
        layout.sectionInset = NSEdgeInsetsMake(20, 20, 20, 20)
        layout.minimumLineSpacing = 0
        layout.minimumInteritemSpacing = 2
        
        let contentionView_ = KMMergeViewController_collectionView()
        contentionView_.autoresizingMask = NSView.AutoresizingMask(rawValue: 18)
        contentionView_.collectionViewLayout = layout
        contentionView_.dataSource = self
        contentionView_.delegate = self
        contentionView_.register(KMMergeCollectionViewItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier(rawValue: "CellID"))
        contentionView_.register(KMMergeCollectionPageViewItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier(rawValue: "PageCellID"))
        contentionView_.registerForDraggedTypes([localForDraggedTypes])
        
        scrollView?.documentView = contentionView_
        contentionView = contentionView_
        contentionView?.isSelectable = true
        contentionView?.allowsMultipleSelection = true
        contentionView?.myDelegate = self
        contentionView?.reloadData()
    }
    
    func mergeActionForOddEven() {
        if (dataArray.count <= 1) {
            return
        }
        
        var rootPDFOutlineArray: [CPDFOutline] = []
        var pdfDocument = outPDFDocument
        
        var mergeOutline: Bool = true
        for fileModel in dataArray {
            if fileModel.pageRange != .all {
                mergeOutline = false
            }
            
            var pdfOutlineArray: [CPDFOutline] = []
            if (fileModel.document.outlineRoot != nil) {
                rootPDFOutlineArray.append(fileModel.document.outlineRoot())
                fetchAllChildren(outline: fileModel.document.outlineRoot(), containers: &pdfOutlineArray)
                pdfOutlineArray.removeObject(fileModel.document.outlineRoot())
            } else {
                var rootOutline = CPDFOutline()
                fileModel.document.setOutlineRoot(rootOutline)
                if fileModel.document.outlineRoot() != nil {
                    rootPDFOutlineArray.append(fileModel.document.outlineRoot())
                }
            }
            
            for outline in pdfOutlineArray {
                /// 这段代码主要是调用他的getter方法;outline显示正确
                outline.destination?.page().document.dataRepresentation()
            }
        }
        
        let oddDocument = dataArray.first?.document
        let oddCount: Int = Int(oddDocument!.pageCount)
        let evenDocument = dataArray.last?.document!
        let evenCount: Int = Int(evenDocument!.pageCount)
        let count = min(oddCount-1, evenCount-1)
        for i in 0 ... count {
            pdfDocument!.insertPageObject((oddDocument?.page(at: UInt(i)))!, at: pdfDocument!.pageCount)
            pdfDocument!.insertPageObject((evenDocument?.page(at: UInt(i)))!, at: pdfDocument!.pageCount)
        }
        
        if oddCount > evenCount {
            for i in count ... oddCount-1 {
                pdfDocument!.insertPageObject((oddDocument?.page(at: UInt(i)))!, at: pdfDocument!.pageCount)
            }
        } else if oddCount < evenCount {
            for i in count ... evenCount-1 {
                pdfDocument!.insertPageObject((evenDocument?.page(at: UInt(i)))!, at: pdfDocument!.pageCount)
            }
        }
        
        if mergeOutline {
            pdfDocument?.setOutlineRoot(CPDFOutline())
            var index = 0
            for outlineRoot in rootPDFOutlineArray {
                if outlineRoot != nil && outlineRoot.numberOfChildren > 0 {
                    for i in 0 ... outlineRoot.numberOfChildren-1 {
                        pdfDocument!.outlineRoot().insertChild(outlineRoot.child(at: UInt(i)), at: UInt(index))
                        index += 1
                    }
                }
            }
        }
        
        handerReDraw()
    }
    
    func mergeAction() {
        if (dataArray.count <= 1) {
//            return
        }
        
        var rootPDFOutlineArray: [CPDFOutline] = []
        var pdfDocument = outPDFDocument
        
        var mergeOutline: Bool = true
        for fileModel in dataArray {
            if fileModel.pageRange != .all {
                mergeOutline = false
            }
            
            var pdfOutlineArray: [CPDFOutline] = []
            if (fileModel.document.outlineRoot() != nil) {
                rootPDFOutlineArray.append(fileModel.document.outlineRoot())
                fetchAllChildren(outline: fileModel.document.outlineRoot(), containers: &pdfOutlineArray)
                pdfOutlineArray.removeObject(fileModel.document.outlineRoot())
            } else {
                var rootOutline = CPDFOutline()
                fileModel.document.setOutlineRoot(rootOutline)
                if fileModel.document.outlineRoot() != nil {
                    rootPDFOutlineArray.append(fileModel.document.outlineRoot())
                }
            }
            
            for outline in pdfOutlineArray {
                /// 这段代码主要是调用他的getter方法;outline显示正确
                outline.destination?.page().document.dataRepresentation()
            }
            
            if fileModel.pageRange == .all {
                for i in 0 ... fileModel.document.pageCount-1 {
                    pdfDocument!.insertPageObject(fileModel.document.page(at: UInt(i))!, at: pdfDocument!.pageCount)
                }
            } else if fileModel.pageRange == .oddPages {
                for i in 0 ... fileModel.document.pageCount-1 {
                    if i % 2 == 1 {
                        continue
                    }
                    
                    pdfDocument!.insertPageObject(fileModel.document.page(at: UInt(i))!, at: pdfDocument!.pageCount)
                }
            } else if fileModel.pageRange == .evenPages {
                for i in 0 ... fileModel.document.pageCount-1 {
                    if i % 2 == 0 {
                        continue
                    }
                    
                    pdfDocument!.insertPageObject(fileModel.document.page(at: UInt(i))!, at: pdfDocument!.pageCount)
                }
            } else if fileModel.pageRange == .custom {
                let pageNumbers = self.findSelectPage(fileModel: fileModel)
                for i in pageNumbers {
                    pdfDocument!.insertPageObject(fileModel.document.page(at: UInt(i-1))!, at: pdfDocument!.pageCount)
                }
            }
        }
        
        if mergeOutline {
            pdfDocument?.setOutlineRoot( CPDFOutline())
            var index = 0
            for outlineRoot in rootPDFOutlineArray {
                if outlineRoot != nil && outlineRoot.numberOfChildren > 0 {
                    for i in 0 ... outlineRoot.numberOfChildren-1 {
                        pdfDocument!.outlineRoot().insertChild(outlineRoot.child(at: UInt(i)), at: UInt(index))
                        index += 1
                    }
                }
            }
        }
        
        handerReDraw()
    }
    
    func handerReDraw() {
        if mergeSettingWindowController.selectedIndex == 0 { /// 原始尺寸
             
        } else {
            var pageSize = NSMakeSize(595, 841)
            if mergeSettingWindowController.selectedIndex == 1 { /// A4 595 x 841
                pageSize = NSMakeSize(595, 841)
            } else if mergeSettingWindowController.selectedIndex == 2 { /// A3 841 x 1190
                pageSize = NSMakeSize(841, 1190)
            } else if mergeSettingWindowController.selectedIndex == 3 { /// U.S.Letter 612 x 792
                pageSize = NSMakeSize(612, 792)
            } else if mergeSettingWindowController.selectedIndex == 4 { /// U.S.Legal 612 x 1108
                pageSize = NSMakeSize(612, 1108)
            } else if mergeSettingWindowController.selectedIndex == 5 { /// 自定义 595 x 841
//                pageSize = NSMakeSize(595, 841)
                pageSize.width = CGFloat(mergeSettingWindowController.customWidthTextField.floatValue)
                pageSize.height = CGFloat(mergeSettingWindowController.customHeightTextField.floatValue)
            }
            
            var pagesArray: [CPDFPage] = []
            let pageCount = outPDFDocument!.pageCount
            for _ in 0 ... pageCount-1 {
                pagesArray.append(outPDFDocument!.page(at: 0)!)
                outPDFDocument!.removePage(at: 0)
            }
            
            for i in 0 ... pageCount-1 {
                var page = KMMergePage()
                page.drawingPage = pagesArray[Int(i)]
                page.setBounds(NSMakeRect(0, 0, pageSize.width, pageSize.height), for: .cropBox)
                outPDFDocument!.insertPageObject(page, at: i)
            }
            
            /// 如果是自定义大小,删除所有的outline,因为合并出来的outline是无效的
            if mergeSettingWindowController.pageSizeComboBox.indexOfSelectedItem == 5 { /// 自定义 595 x 841
                let childCount: Int = Int(outPDFDocument!.outlineRoot().numberOfChildren)
                var array: [CPDFOutline] = []
                for i in 0 ... childCount-1 {
                    array.append((outPDFDocument!.outlineRoot().child(at: UInt(i)))!)
                }
                
                for outline in array {
                    outline.removeFromParent()
                }
            }
        }
    }
    
    func fetchAllChildren(outline: CPDFOutline, containers: inout [CPDFOutline]) {
        if !containers.contains(outline) {
            containers.append(outline)
        }
        
        if outline != nil && outline.numberOfChildren > 0 {
            for i in 0 ... (outline.numberOfChildren-1) {
                containers.append(outline.child(at: i)!)
                
                fetchAllChildren(outline: outline.child(at: i)!, containers: &containers)
            }
        }
    }
    
    func showAddMenu() {
        let menu: NSMenu = NSMenu()
        let addFileitem = menu.addItem(withTitle: NSLocalizedString("添加文件", comment: ""), action: #selector(itemAddFileAction), keyEquivalent: "")
        addFileitem.target = self
        let addFolderitem = menu.addItem(withTitle: NSLocalizedString("添加文件夹", comment: ""), action: #selector(itemAddFolderAction), keyEquivalent: "")
        addFolderitem.target = self
        let addOpenFileitem = menu.addItem(withTitle: NSLocalizedString("添加已打开文件", comment: ""), action: #selector(itemAddOpenFileAction), keyEquivalent: "")
        addOpenFileitem.target = self
        addOpenFileitem.action = nil
        
        let point: NSPoint = NSMakePoint(0, -10)
        menu.popUp(positioning: nil, at: point, in: titleBarView?.addItem)
    }
    
    @objc func itemAddFileAction() {
        let openPanel = NSOpenPanel()
        openPanel.title = NSLocalizedString("选择并合并文件。按下键盘上的命令按钮,逐次点击目标文件,即可选择多个文件", comment: "")
        openPanel.canChooseDirectories = false //是否允许选择目录
        openPanel.canChooseFiles = true //是否可以选择文件
        openPanel.allowsMultipleSelection = true //是否允许多选
        openPanel.allowedFileTypes = ["jpg","cur","bmp","jpeg","gif","png","tiff","tif",/*@"pic",*/"ico","icns","tga","psd","eps","hdr","jp2","jpc","pict","sgi","heic","pdf"]
        
        openPanel.beginSheetModal(for: view.window!, completionHandler: { result in
            if result != .OK {
                
            } else {
                for documentURL in openPanel.urls {
                    self.addModel(documentURL: documentURL)
                }
                
                self.contentionView?.reloadData()
                
                self.dealLockedFiles()
            }
        })
    }
    
    @objc func itemAddFolderAction() {
        let openPanel = NSOpenPanel()
        openPanel.title = NSLocalizedString("选择并合并文件。按下键盘上的命令按钮,逐次点击目标文件,即可选择多个文件", comment: "")
        openPanel.canChooseDirectories = true
        openPanel.canChooseFiles = false
        openPanel.allowsMultipleSelection = true
        
        openPanel.beginSheetModal(for: view.window!, completionHandler: { [self] result in
            if result != .OK {
                
            } else {
                var result: [URL] = []
                for folderURL in openPanel.urls {
                    findAllFiles(folder: folderURL, result: &result)
                }
                
                for documentURL in result {
                    addModel(documentURL: documentURL)
                }
                self.contentionView?.reloadData()
                
                self.dealLockedFiles()
            }
        })
    }
    
    func findAllFiles(folder: URL, result: inout [URL]) {
        let fileManager = FileManager.default
        var isDirectory: ObjCBool = ObjCBool(false)
        fileManager.fileExists(atPath: folder.path, isDirectory: &isDirectory)
        if (!isDirectory.boolValue) {
            return
        }
        
        let contents = try?fileManager.contentsOfDirectory(at: folder, includingPropertiesForKeys: nil)
        if contents?.count == 0 {
            return
        }
        
        let array = ["jpg","cur","bmp","jpeg","gif","png","tiff","tif",/*@"pic",*/"ico","icns","tga","psd","eps","hdr","jp2","jpc","pict","sgi","heic","pdf"]
        for documentURL in contents! {
            var isDirectory: ObjCBool = ObjCBool(false)
            fileManager.fileExists(atPath: documentURL.path, isDirectory: &isDirectory)
            if (isDirectory.boolValue) {
                findAllFiles(folder: documentURL, result: &result)
            } else {
                if !array.contains(documentURL.pathExtension.lowercased()) {
                    continue
                }
                
                result.append(documentURL)
            }
        }
    }
    
    @objc func itemAddOpenFileAction() {
        
    }
    
    func addModel(documentURL: URL) {
        let model: KMMergeFileModel = KMMergeFileModel();
        model.documentURL = documentURL
        if documentURL.pathExtension.lowercased() == "pdf" {
            model.document = CPDFDocument.init(url: documentURL)
            if model.document.isLocked {
                lockedFiles.append(documentURL)
                
                return
            }
            
            model.myDocument = CPDFDocument.init(url: documentURL)
            model.pageRange = .all
            model.page = model.document.page(at: 0)
            if model.document.pageCount > 1 {
                for i in 0 ... model.document.pageCount-1 {
                    let pageModel = KMMergePageModel()
                    pageModel.selected = true
                    pageModel.pageID = Int(i)
                    model.pages.append(pageModel)
                }
            } else {
                
            }
        } else {
            let doucument = CPDFDocument.init(url: documentURL)
            model.document = doucument
            model.page = doucument?.page(at: 0)
            model.document.insertPageObject(model.page, at: 0)
        }

        self.dataArray.append(model)
    }
    
    func replaceModel(documentURL: URL, index: Int) {
        if index >= 0 && index < dataArray.count {
            let model: KMMergeFileModel = KMMergeFileModel();
            model.documentURL = documentURL
            if documentURL.pathExtension.lowercased() == "pdf" {
                model.document = CPDFDocument.init(url: documentURL)
                model.myDocument = CPDFDocument.init(url: documentURL)
                model.pageRange = .all
                model.page = model.document.page(at: 0)
                if model.document.pageCount > 1 {
                    for i in 0 ... model.document.pageCount {
                        let pageModel = KMMergePageModel()
                        pageModel.selected = true
                        pageModel.pageID = Int(i)
                        model.pages.append(pageModel)
                    }
                } else {
                    
                }
            } else {
                let doucument = CPDFDocument.init(url: documentURL)
                model.document = doucument
                model.page = doucument?.page(at: 0)
                model.document.insertPageObject(model.page, at: 0)
            }

            self.dataArray[index] = model
        }
    }
    
    func isValidPagesString(pagesString: String)-> Bool {
        var valid = false
        for ch in pagesString {
            if ch != "0" && ch != "1" && ch != "2" && ch != "3" && ch != "4" && ch != "5" && ch != "6" && ch != "7" && ch != "8" && ch != "9" && ch != "," && ch != "-" {
                valid = false
                break
            } else {
                valid = true
            }
        }
        
        return valid
    }
    
    func findSelectPage(fileModel: KMMergeFileModel) -> ([Int]) {
        if !isValidPagesString(pagesString: fileModel.pageRangeString) {
            return []
        }
        
        var result: [Int] = []
        let array = fileModel.pageRangeString.components(separatedBy: ",")
        for string in array {
            if string.isEmpty {
                return []
            } else {
                let pages = string .components(separatedBy: "-")
                if pages.count > 2 {
                    return []
                } else if pages.count == 1 {
                    let page = pages[0]
                    if page.isEmpty || Int(page)! > fileModel.document.pageCount || Int(page)! == 0 {
                        return []
                    } else {
                        var hasSame: Bool = false
                        for i in result {
                            if i == Int(page)! {
                                hasSame = true
                                return []
                            }
                        }
                        if !hasSame {
                            result.append(Int(page)!)
                        }
                    }
                } else if pages.count == 2 {
                    let page1 = pages[0]
                    let page2 = pages[1]
                    if page1.isEmpty || page2.isEmpty || Int(page1)! >= Int(page2)! || Int(page2)! > fileModel.myDocument.pageCount || Int(page1)! == 0 {
                        return []
                    } else {
                        var hasSame: Bool = false
                        for i in Int(page1)! ... Int(page2)! {
                            for j in result {
                                if j == i {
                                    hasSame = true
                                    return []
                                }
                            }
                        }
                        if !hasSame {
                            for i in Int(page1)! ... Int(page2)! {
                                result.append(i)
                            }
                        }
                     }
                }
            }
        }
        
        return result
    }
    
    func findFileModel(indexPath: IndexPath) -> (fileModel: KMMergeFileModel, pageIndex: Int) {
        var count: Int = 0
        var flagModel : KMMergeFileModel!
        var index: Int = NSNotFound
        for model in dataArray {
            if (flagModel != nil) {
                break
            }
            
            if model.open {
                for i in 0...(model.document.pageCount-1) {
                    if count == indexPath.item {
                        index = Int(i)
                        flagModel = model
                        break
                    }
                    
                    count += 1
                }
            } else {
                if count == indexPath.item {
                    flagModel = model
                    break
                }
                
                count += 1
            }
        }
        
        return (flagModel, index)
    }
    
    func allItemIsExpanded() -> Bool {
        for fileModel in dataArray {
            if fileModel.canExpand() && !fileModel.open {
                return false
            }
        }
        return true
    }
    
    func allItemIsFolded() -> Bool {
        for fileModel in dataArray {
            if fileModel.open {
                return false
            }
        }
        return true
    }
    
    func dealLockedFiles() {
        if lockedFiles.count > 0 {
            let documentURL = lockedFiles.first
            let alert = NSAlert()
            alert.messageText = documentURL!.lastPathComponent.appending(", 已被保护")
            alert.addButton(withTitle: "输入密码")
            alert.addButton(withTitle: "关闭")
            let response = alert.runModal()
            if response == .alertFirstButtonReturn {
                let window = KMPasswordInputWindow().window()
                window?.documentURL = documentURL!
                window?.type = .open
                
                window?.itemClick = {
                    (index: Int, string: String) in
                    if index == 1 {
                        self.view.window?.endSheet(window!)
                        
                        self.lockedFiles.remove(at: 0)
                        self.dealLockedFiles()
                    } else {
                        self.view.window?.endSheet(window!)
                        
                        let model = KMMergeFileModel()
                        model.documentURL = documentURL
                        model.document = CPDFDocument(url: documentURL!)
                        model.document.unlock(withPassword: string)
                        model.myDocument = CPDFDocument.init(url: documentURL)
                        model.pageRange = .all
                        model.page = model.document.page(at: 0)
                        model.password = string
                        if model.document.pageCount > 1 {
                            for i in 0 ... model.document.pageCount-1 {
                                let pageModel = KMMergePageModel()
                                pageModel.selected = true
                                pageModel.pageID = Int(i)
                                model.pages.append(pageModel)
                            }
                        }
                        
                        self.dataArray.append(model)
                        
                        self.contentionView?.reloadData()
                        self.lockedFiles.remove(at: 0)
                        self.dealLockedFiles()
                    }
                }
                
                self.view.window?.beginSheet(window!)
            } else {
                self.lockedFiles.remove(at: 0)
                self.dealLockedFiles()
            }
        }
    }
    
    /**
     * MARK: Menu Actions
     */
    @objc func expandAllMenuAction() {
        for fileModel in dataArray {
            if fileModel.canExpand() {
                fileModel.open = true
            }
        }
        
        self.contentionView?.reloadData()
        
        deleteArray.removeAll()
        titleBarView?.setDeleteItemEnable(enable: false)
    }
    
    @objc func foldAllMenuAction() {
        for fileModel in dataArray {
            fileModel.open = false
        }
        
        self.contentionView?.reloadData()
    }
    
    @objc func expandMenuAction(sender: NSMenuItem) {
        let index = sender.tag
        if index >= 0 && index < dataArray.count {
            let fileModel: KMMergeFileModel = dataArray[index]
            if fileModel.canExpand() {
                fileModel.open = true
            }
            
            self.contentionView?.reloadData()
            
//            if index < deleteArray.count {
//                deleteArray.remove(at: index)
//            }
            deleteArray.removeAll()
            
            if deleteArray.count > 0 {
                titleBarView?.setDeleteItemEnable(enable: true)
            } else {
                titleBarView?.setDeleteItemEnable(enable: false)
            }
        }
    }
    
    @objc func addMenuAction() {
        itemAddFileAction()
    }
    
    @objc func removeMenuAction(sender: NSMenuItem) {
        let index = sender.tag
        if index >= 0 && index < dataArray.count {
            dataArray.remove(at: index)
            
            self.contentionView?.reloadData()
        }
    }
    
    @objc func replaceMenuAction(sender: NSMenuItem) {
        let index = sender.tag
        if index >= 0 && index < dataArray.count {
            let openPanel = NSOpenPanel()
            openPanel.title = NSLocalizedString("选择并合并文件。按下键盘上的命令按钮,逐次点击目标文件,即可选择多个文件", comment: "")
            openPanel.canChooseDirectories = false
            openPanel.canChooseFiles = true
            openPanel.allowsMultipleSelection = false
            openPanel.allowedFileTypes = ["jpg","cur","bmp","jpeg","gif","png","tiff","tif",/*@"pic",*/"ico","icns","tga","psd","eps","hdr","jp2","jpc","pict","sgi","heic","pdf"]
            
            openPanel.beginSheetModal(for: view.window!, completionHandler: { result in
                if result != .OK {
                    
                } else {
                    for documentURL in openPanel.urls {
                        self.replaceModel(documentURL: documentURL, index: index)
                    }
                    self.contentionView?.reloadData()
                }
            })
        }
    }
}

extension KMMergeViewController: KMMergeTitleBarDelegate {
    func titleBar(titleBar: KMMergeTitleBar, itemDidClick: KMMergeTitleBarButtonID) {
        KMPrint();
    }
}

extension KMMergeViewController: NSCollectionViewDataSource {
    func numberOfSections(in collectionView: NSCollectionView) -> Int {
        return 1
    }
    
    func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
        var count: Int = 0
        for model in dataArray {
            if model.open {
                count += Int(model.document.pageCount)
            } else {
                count += 1
            }
        }
        
        return count
    }
    
    func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
        var count: Int = 0
        var flagModel : KMMergeFileModel!
        var index: Int = NSNotFound
        for model in dataArray {
            if (flagModel != nil) {
                break
            }
            
            if model.open {
                for i in 0...(model.document.pageCount-1) {
                    if count == indexPath.item {
                        index = Int(i)
                        flagModel = model
                        break
                    }
                    
                    count += 1
                }
            } else {
                if count == indexPath.item {
                    flagModel = model
                    break
                }
                
                count += 1
            }
        }
        
        if index == NSNotFound {
            let cellView: KMMergeCollectionViewItem = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "CellID"), for: indexPath) as! KMMergeCollectionViewItem
            cellView.model = flagModel
            cellView.doubleClick = {
                [self] (viewItem: AnyObject) -> () in
                let cellItemView: KMMergeCollectionViewItem = viewItem as! KMMergeCollectionViewItem
                let model = cellItemView.model
                if model.canExpand() {
                    model.open = true
                   
                    self.titleBarView?.setPageRangeComboBoxHidden(isHidden: false)
                    self.titleBarView?.model = model
                   self.contentionView?.reloadData()
                    
//                    if deleteArray.contains(indexPath.item) {
//                        deleteArray.removeObject(indexPath.item)
//                    }
                    deleteArray.removeAll()
                    
                    if deleteArray.count > 0 {
                        titleBarView?.setDeleteItemEnable(enable: true)
                    } else {
                        titleBarView?.setDeleteItemEnable(enable: false)
                    }
                }
            }
            cellView.pageRangeClick = {
                [self] (viewItem: AnyObject) -> () in
                let cellItemView: KMMergeCollectionViewItem = viewItem as! KMMergeCollectionViewItem
                let model = cellItemView.model

                let window = KMPageRangePickerWindowController.init(windowNibName: "KMPageRangePickerWindowController")
                window.fileModel = model
                self.view.window?.beginSheet(window.window!)
                pageRangeWindowController = window
                
                window.cancelClick = {
                    [self] (window: NSWindow)->() in
                    self.view.window?.endSheet(window)
                }
                
                window.confirmClick = {
                    [self] (windowController: NSWindowController)->() in
                    if pageRangeWindowController.selectIndex == 0 {
                        model.pageRange = .all
                        model.updateChildPageRange(pageRange: .all)
                    } else if pageRangeWindowController.selectIndex == 1 {
                        model.pageRange = .oddPages
                        model.updateChildPageRange(pageRange: .oddPages)
                    } else if pageRangeWindowController.selectIndex == 2 {
                        model.pageRange = .evenPages
                        model.updateChildPageRange(pageRange: .evenPages)
                    } else if pageRangeWindowController.selectIndex == 3 {
                        model.pageRange = .custom
                        model.pageRangeString = pageRangeWindowController.customPagesTextField.stringValue
                        model.updateChildPageRange(pageRange: .custom)
                        
                        let pageNumbers = findSelectPage(fileModel: model)
                        for i in 0 ... (model.pages.count)-1 {
                            let pageModel = model.pages[i]
                            if pageNumbers .contains(Int(pageModel.pageID)+1) {
                                pageModel.selected = true
                            } else {
                                pageModel.selected = false
                            }
                        }
                    }
                    
                    self.contentionView?.reloadItems(at: [indexPath])
                    self.view.window?.endSheet(windowController.window!)
                }
            }
            
            return cellView
        } else {
            let cellView: KMMergeCollectionPageViewItem = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "PageCellID"), for: indexPath) as! KMMergeCollectionPageViewItem
            let model = flagModel.pages[index]
            model.page = flagModel.document.page(at: UInt(index))
            cellView.fileModel = flagModel
            cellView.model = model
            cellView.flodClick = {
                [self] (viewItem: AnyObject) -> () in
                let cellItemView: KMMergeCollectionPageViewItem = viewItem as! KMMergeCollectionPageViewItem
                let model = cellItemView.fileModel
                model.open = false

                self.titleBarView?.setPageRangeComboBoxHidden(isHidden: true)
                self.contentionView?.reloadData()
            }
            
            cellView.selectedClick = {
                [self] (viewItem: AnyObject) -> () in
                let cellItemView: KMMergeCollectionPageViewItem = viewItem as! KMMergeCollectionPageViewItem
                let model = cellItemView.model
                model.selected = !model.selected

                self.titleBarView?.setPageRangeComboBoxHidden(isHidden: false)
                cellView.fileModel.updatePagePange()
                self.titleBarView?.model = cellView.fileModel
                
                self.contentionView?.reloadItems(at: [indexPath])
            }
            
            cellView.view.wantsLayer = true
            cellView.view.layer?.backgroundColor = NSColor.lightGray.cgColor
            
            return cellView
        }

        return NSCollectionViewItem()   
    }
}

extension KMMergeViewController: NSCollectionViewDelegateFlowLayout {
    /**
     * MARK: item大小
     */
    func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize {
        return NSMakeSize(246 * (1 + zoomScale), 322 * (1 + zoomScale))
    }
    
    func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 0.01
    }
    
    func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return -5
    }
}

extension KMMergeViewController: NSCollectionViewDelegate {
    func collectionView(_ collectionView: NSCollectionView, shouldSelectItemsAt indexPaths: Set<IndexPath>) -> Set<IndexPath> {
        return indexPaths
    }
    
    func collectionView(_ collectionView: NSCollectionView, didSelectItemsAt indexPaths: Set<IndexPath>) {
        let index: IndexPath = indexPaths.first!
        var i = 0
        for model in dataArray {
            if i == index.item {
                model.selected = true
            } else {
                model.selected = false
            }
            i += 1
        }
        
        deleteArray.append(index.item)
        if collectionView.selectionIndexes.count > 0 {
            titleBarView?.setDeleteItemEnable(enable: true)
        } else {
            titleBarView?.setDeleteItemEnable(enable: false)
        }
    }
    
    func collectionView(_ collectionView: NSCollectionView, shouldDeselectItemsAt indexPaths: Set<IndexPath>) -> Set<IndexPath> {
        return indexPaths
    }
    
    func collectionView(_ collectionView: NSCollectionView, didDeselectItemsAt indexPaths: Set<IndexPath>) {
        let index: IndexPath = indexPaths.first!
        deleteArray.removeObject(index.item)
        
        if collectionView.selectionIndexes.count > 0 {
            titleBarView?.setDeleteItemEnable(enable: true)
        } else {
            titleBarView?.setDeleteItemEnable(enable: false)
            titleBarView?.setPageRangeComboBoxHidden(isHidden: true)
        }
    }
    
    func collectionView(_ collectionView: NSCollectionView, canDragItemsAt indexPaths: Set<IndexPath>, with event: NSEvent) -> Bool {
        for indexPath in indexPaths {
            let pageIndex = findFileModel(indexPath: indexPath).pageIndex
            if pageIndex != NSNotFound { /// 页面不用拖拽
                return false
            }
        }
        return true
    }
    
    func collectionView(_ collectionView: NSCollectionView, writeItemsAt indexPaths: Set<IndexPath>, to pasteboard: NSPasteboard) -> Bool {
        let data: Data = try! NSKeyedArchiver.archivedData(withRootObject: indexPaths, requiringSecureCoding: true)
        pasteboard.declareTypes([self.localForDraggedTypes], owner: self)
        pasteboard.setData(data, forType: self.localForDraggedTypes)
        
        dragedIndexPaths.removeAll()
        for indexPath in indexPaths {
            dragedIndexPaths.append(indexPath)
        }
        return true
    }
    
    func collectionView(_ collectionView: NSCollectionView, validateDrop draggingInfo: NSDraggingInfo, proposedIndexPath proposedDropIndexPath: AutoreleasingUnsafeMutablePointer<NSIndexPath>, dropOperation proposedDropOperation: UnsafeMutablePointer<NSCollectionView.DropOperation>) -> NSDragOperation {
        let pboard = draggingInfo.draggingPasteboard
        if (pboard.availableType(from: [localForDraggedTypes]) != nil) {
            return .move
        }
        
        return NSDragOperation.generic
    }
    
    func collectionView(_ collectionView: NSCollectionView, acceptDrop draggingInfo: NSDraggingInfo, indexPath: IndexPath, dropOperation: NSCollectionView.DropOperation) -> Bool {
        let pboard = draggingInfo.draggingPasteboard
        if (pboard.availableType(from: [localForDraggedTypes]) != nil) {
//            let indexPathsData: Data = pboard.data(forType: self.localForDraggedTypes)!
//            let set = try!NSKeyedUnarchiver.unarchivedObject(ofClasses: Set<IndexPath.self>, from: indexPathsData)!
            
            let dragIndex: Int = dragedIndexPaths.first!.item
            let toIndex = max(0, indexPath.item-1)
            if dragIndex < 0 || dragIndex > dataArray.count {
                return false
            }
            
            if dragIndex == toIndex {
                return false
            }
            
            /// 交互数据
            let dragFileModel = dataArray[dragIndex]
            dataArray.removeObject(dragFileModel)
            dataArray.insert(dragFileModel, at: toIndex)
            
            self.contentionView?.reloadData()
            
            return true
        }
        
        return false
    }
}

extension KMMergeViewController : KMMergeViewController_collectionView_delegate {
    func collection_menu(for event: NSEvent) -> NSMenu? {
        let point = event.locationInWindow
        let rigthIndex = self.contentionView!.indexPathForItem(at: self.contentionView!.convert(point, from: nil))
        
        if rigthIndex == nil { /// 空白处
            let menu = NSMenu(title: "")
            
            if dataArray.count == 0 {
            } else {
                if allItemIsExpanded() {
                    let foldAllItem = NSMenuItem(title: NSLocalizedString("折叠全部文件", comment: ""), action: #selector(foldAllMenuAction), keyEquivalent: "")
                    foldAllItem.target = self
                    menu.addItem(foldAllItem)
                } else if allItemIsFolded() {
                    let expandAllItem = NSMenuItem(title: NSLocalizedString("展开全部文件", comment: ""), action: #selector(expandAllMenuAction), keyEquivalent: "")
                    expandAllItem.target = self
                    menu.addItem(expandAllItem)
                } else {
                    let expandAllItem = NSMenuItem(title: NSLocalizedString("展开全部文件", comment: ""), action: #selector(expandAllMenuAction), keyEquivalent: "")
                    expandAllItem.target = self
                    menu.addItem(expandAllItem)
                    
                    let foldAllItem = NSMenuItem(title: NSLocalizedString("折叠全部文件", comment: ""), action: #selector(foldAllMenuAction), keyEquivalent: "")
                    foldAllItem.target = self
                    menu.addItem(foldAllItem)
                }
            }
            
            let addItem = NSMenuItem(title: NSLocalizedString("添加文件", comment: ""), action: #selector(addMenuAction), keyEquivalent: "")
            addItem.target = self
            menu.addItem(addItem)
            return menu
        }
        
        let cellView = self.contentionView!.item(at: rigthIndex!)
        if ((cellView?.isKind(of: KMMergeCollectionViewItem.self))! == true) {
            let fileCellView: KMMergeCollectionViewItem = cellView! as! KMMergeCollectionViewItem
            var index = 0
            var indexTag = NSNotFound
            for fileModel in dataArray {
                if fileModel.isEqual(to: fileCellView.model) {
                    indexTag = index
                    break
                }
                index += 1
            }
            
            let menu = NSMenu(title: "")
            let expandItem = NSMenuItem(title: NSLocalizedString("展开文件", comment: ""), action: #selector(expandMenuAction), keyEquivalent: "")
            expandItem.target = self
            expandItem.tag = indexTag
            if fileCellView.model.canExpand() {
                expandItem.action = #selector(expandMenuAction)
            } else {
                expandItem.action = nil
            }
            
            menu.addItem(expandItem)
            
            let expandAllItem = NSMenuItem(title: NSLocalizedString("展开全部文件", comment: ""), action: #selector(expandAllMenuAction), keyEquivalent: "")
            expandAllItem.target = self
            menu.addItem(expandAllItem)
            
            menu.addItem(NSMenuItem.separator())
            
            let removeItem = NSMenuItem(title: NSLocalizedString("移除文件", comment: ""), action: #selector(removeMenuAction), keyEquivalent: "")
            removeItem.target = self
            removeItem.tag = indexTag
            
            menu.addItem(removeItem)
            
            menu.addItem(NSMenuItem.separator())
            
            let replaceItem = NSMenuItem(title: NSLocalizedString("替换文件", comment: ""), action: #selector(replaceMenuAction), keyEquivalent: "")
            replaceItem.target = self
            replaceItem.tag = indexTag
            menu.addItem(replaceItem)
            
            let addItem = NSMenuItem(title: NSLocalizedString("添加文件", comment: ""), action: #selector(addMenuAction), keyEquivalent: "")
            addItem.target = self
            menu.addItem(addItem)
            return menu
        }
        return nil
    }
}