//
//  CharacterAutoTest.swift
//  KdanAuto
//
//  Created by 朱东勇 on 2022/11/22.
//

import Foundation
import Cocoa

class CharacterAutoTest : AutoTest {
    
//    override func type() -> String {
//        return "PDFConvert_China_Auto_Test"
//    }
    
    override func name() -> String {
        return "字符转换准确率测试"
    }
    
    override func keys() -> NSArray {
        return ["字符", "快照"]
    }
    
    static var cSharedInstance = CharacterAutoTest()
    override class func shared() -> AutoTest? {
        return cSharedInstance
    }
    
    
    // Auto Test refrence Check File
    override func autoTest() {
        clearCacheFiles()
        
        let checkString = self.selectedKeys().contains("字符")
        let needCompare = self.selectedKeys().contains("快照")
        
        if !needCompare && !checkString {
            _status = .Finished
            return
        }
        
        _status = .Process
        reportString = NSMutableAttributedString.init(string: "\n【\(String(self.fileType())) - \(self.name())】字符比对开始!\n",
                                                      attributes:[.foregroundColor : NSColor.blue])
        let files = DataModel.shared.originFilesFor(_fileType, type: _type)
        
        let checkDirectory = self.checkFileDirectory()
        let originDirectory = self.originFileDirectory()
        let resultDirectory = self.resultFileDirectory()
        
        var tDegree = Double(0);
        var tCount = Int(0)
        
        for fileName in files {
            let fName = NSString(string: fileName).deletingPathExtension
            let originPath = NSString(string: originDirectory).appendingPathComponent(fName+".pdf")
            let resultPath = NSString(string: resultDirectory).appendingPathComponent(fName+"."+_extention)
            let checkPath = NSString(string: checkDirectory).appendingPathComponent(fName+"."+_extention)
            
            
            reportString?.append(NSMutableAttributedString.init(string: "\n【\(String(self.fileType())) - \(self.name())】开始转换文件 \"\(fName)\"\n",
                                                               attributes:[.foregroundColor : NSColor.black]))
            // ...
            // 执行转换过程
            let convertSemaphore = DispatchSemaphore(value: 0)
            var success = false
            let convertQueue = DispatchQueue.global()
            convertQueue.async {
                success = FileConverter.shared().converter(originPath, inDesPath: resultPath)
                
                convertSemaphore.signal()
            }
            convertSemaphore.wait()
            
            if FileManager.default.fileExists(atPath: resultPath) && success {
                if checkString {
                    // Load check file
                    let checkData = NSData.init(contentsOfFile: checkPath) as! Data
                    var documentAttributes:NSDictionary!
                    let checkAttString = NSAttributedString.init(rtf: checkData, documentAttributes: &documentAttributes)
                    var checkString = NSString(string: checkAttString!.string) as NSString
                    
                    let resultString = try? NSString.init(contentsOfFile: resultPath, encoding: NSUTF8StringEncoding)
                    
                    
#if false
                    //识别字符串 \shptxt\shptxt ... }
                    let pageInfoStrings = resultString!.components(separatedBy: "\\shptxt\\shptxt") as NSArray
                    var finalString = ""
                    if pageInfoStrings.count > 0 {
                        let subStrings = pageInfoStrings.subarray(with: NSMakeRange(1, Int(pageInfoStrings.count - 1))) as! [String]
                        for pageInfoString in subStrings {
                            let endRange = NSString(string: pageInfoString).range(of: "}")
                            finalString = finalString.appending(NSString(string: pageInfoString).substring(to: endRange.location))
                        }
                    }
                    
                    
                    //识别所有 【空格 ~ \】 之间的值，并进行缝合
                    // Detect all strings between Spaces and \ and stitch
                    let strings = finalString.components(separatedBy: " ")
                    var resultStr = "" as NSString
                    for str in strings {
                        let markStr = str as NSString
                        
                        if (markStr.contains("\\f")) {
                            let fRange = markStr.range(of: "\\f")
                            let cRange = markStr.range(of: "\\c")
                            let bRange = markStr.range(of: "\\b")
                            let iRange = markStr.range(of: "\\i")
                            let eRange = markStr.range(of: "\\e")
                            let pRange = markStr.range(of: "\\p")
                            let minPos = min(Int(fRange.location),
                                             Int(cRange.location),
                                             Int(bRange.location),
                                             Int(iRange.location),
                                             Int(eRange.location),
                                             Int(pRange.location))
                            resultStr = resultStr.appending(markStr.substring(to: minPos)) as NSString
                        }else {
                            resultStr = resultStr.appending(markStr as String) as NSString
                        }
                    }
                    resultStr = self.replaceUnicodeString(resultStr)
#else
                    let resultData = NSData.init(contentsOfFile: resultPath) as! Data
                    var rDocumentAttributes:NSDictionary!
                    let resultAttString = NSAttributedString.init(rtf: resultData, documentAttributes: &rDocumentAttributes)
                    var resultStr = NSString(string: resultAttString!.string)
#endif
                    resultStr = resultStr.replacingOccurrences(of: "\n", with: "") as NSString
                    checkString = checkString.replacingOccurrences(of: "\n", with: "") as NSString
                    resultStr = resultStr.replacingOccurrences(of: " ", with: "") as NSString
                    checkString = checkString.replacingOccurrences(of: " ", with: "") as NSString
                    resultStr = resultStr.replacingOccurrences(of: "\\pard", with: "") as NSString
                    resultStr = resultStr.replacingOccurrences(of: "\\par", with: "") as NSString
                    
                    //                do { // save cache file for test
                    //                    try? NSString(string: resultStr).write(toFile: NSString(string: DataModel.shared.resultPath()).appending("/\(self.name())-result-cache.txt"),
                    //                                                      atomically: true, encoding: NSUTF8StringEncoding)
                    //
                    //                    try? NSString(string: checkString).write(toFile: NSString(string: DataModel.shared.resultPath()).appending("/\(self.name())-check-cache.txt"),
                    //                                                          atomically: true, encoding: NSUTF8StringEncoding)
                    //                }
                    
                    let maxSize = checkString.length
                    var successCount = 0;
                    /**
                     (A0 = B0)
                     - A-1 & B-1
                     (A0 != B0) & (A0 in B) & (B0 in A)
                     - 取 A0，B0最小 Range 值
                     - 字符串裁剪对齐
                     (A0 != B0) & (A0 in B)
                     - 存储B0到识别错误缓存
                     (A0 != B0) & (B0 in A)
                     - 存储 A0到识别遗漏字符串
                     (A0 != B0)
                     - 分别存储 A0、B0到遗漏及错误字串
                     */
                    var skipString = NSString()
                    var failString = NSString()
                    while (checkString.length > 0 && resultStr.length > 0) {
                        let subc = checkString.substring(to: 1) as NSString
                        let subr = resultStr.substring(to: 1) as NSString
                        
                        if subc.isEqual(to: subr) { // (A0 = B0)
                                                    // Check Success
                            appendErrorInfo(skipString, failString: failString)
                            skipString = NSString()
                            failString = NSString()
                            
                            
                            checkString = checkString.substring(from:1) as NSString
                            resultStr = resultStr.substring(from:1) as NSString
                            successCount = successCount + 1
                        }else if (checkString.contains(subr as String) && resultStr.contains(subc as String)) {
                            appendErrorInfo(skipString, failString: failString)
                            skipString = NSString()
                            failString = NSString()
                            
                            let cRange = checkString.range(of: subr as String)
                            let rRange = resultStr.range(of: subc as String)
                            
                            if (cRange.location < rRange.location) {
                                let cacheString = checkString.substring(to:cRange.location + cRange.length)
                                reportString?.append(NSMutableAttributedString.init(string: "对照字符串【\(cacheString)】未识别到\n",
                                                                                    attributes:[.foregroundColor : NSColor.red]))
                                checkString = checkString.substring(from:cRange.location) as NSString
                            }else {
                                let cacheString = resultStr.substring(to:rRange.location)
                                reportString?.append(NSMutableAttributedString.init(string: "字符串【\(cacheString)】识别出错\n",
                                                                                    attributes:[.foregroundColor : NSColor.red]))
                                resultStr = resultStr.substring(from:rRange.location + rRange.length) as NSString
                            }
                            
                        }else if (checkString.contains(subr as String)) {
                            skipString = skipString.appending(subc as String) as NSString
                            checkString = checkString.substring(from:1) as NSString
                        }else if (resultStr.contains(subc as String)) {
                            failString = failString.appending(subr as String) as NSString
                            resultStr = resultStr.substring(from:1) as NSString
                        }else {
                            skipString = skipString.appending(subc as String) as NSString
                            failString = failString.appending(subr as String) as NSString
                            
                            checkString = checkString.substring(from:1) as NSString
                            resultStr = resultStr.substring(from:1) as NSString
                        }
                    }
                    
                    skipString = skipString.appending(checkString as String) as NSString
                    failString = failString.appending(resultStr as String) as NSString
                    
                    
                    appendErrorInfo(skipString, failString: failString)
                    
                    let degree = Float(successCount)/Float(maxSize) * 100
                    var color = NSColor.black
                    if fabs(degree-100.0) >= 0.01 {
                        color = NSColor.red
                    }
                    reportString?.append(NSAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"比对完成，准确率\(degree)%(\(successCount)/\(maxSize))\n",
                                                                 attributes:[.foregroundColor : color]))
                    
                }
                // compare screenshoot between result file with check file
                if needCompare {
                    reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"快照生成中\n",
                                                                        attributes:[.foregroundColor : NSColor.black]))
                    let rComparePath = NSString(string: resultDirectory).appendingPathComponent(fName+".jpg")
                    let cComparePath = NSString(string: checkDirectory).appendingPathComponent(fName+".jpg")
                    
                    let processThumbSemaphore = DispatchSemaphore(value: 0)
                    var processSuccess = false
                    let thumbnailQueue = DispatchQueue.global()
                    thumbnailQueue.async {
                        processSuccess = ProcessThumbnal.process(resultPath, desPath: rComparePath, outputSize: CGSize.init(width: 2048, height: 2048))
                        
                        if (processSuccess &&
                            FileManager.default.fileExists(atPath: rComparePath)) {
                            
                            let degree = self.compareJPEG(rComparePath, checkPath: cComparePath)
                            
                            if degree == -1 {
                                self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"快照对比失败，生成快照失败或无比对文件\n",
                                                                                         attributes:[.foregroundColor : NSColor.red]))
                            }else {
                                var color = NSColor.black
                                if fabs(degree-100.0) >= 0.01 {
                                    color = NSColor.red
                                }
                                
                                self._fileDegreeInfo[fileName] = degree
                                tDegree += degree
                                tCount += 1
                                
                                self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"快照对比完成，图像相似度 \(degree)%\n",
                                                                                         attributes:[.foregroundColor : color]))
                            }
                        }else {
                            self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"快照生成失败\n",
                                                                                     attributes:[.foregroundColor : NSColor.red]))
                        }
                        processThumbSemaphore.signal()
                    }
                    processThumbSemaphore.wait()
                }
            }else {
                reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"转档失败！\n",
                                                              attributes:[.foregroundColor : NSColor.red]))
            }
            
        }
        
        if tCount != 0 {
            _degree = tDegree / Double(tCount)
        }else {
            _degree = 0
        }
        
        NSLog("\(reportString)")
        
        
        _status = .Finished
    }
    
    func appendErrorInfo(_ skipString:NSString, failString: NSString) {
        if skipString.length > 0  && failString.length > 0 {
            reportString?.append(NSMutableAttributedString.init(string: "对比字符串【\(skipString)】错识别为【\(failString)】\n",
                                                                attributes:[.foregroundColor : NSColor.red]))
        }else if (skipString.length > 0) {
            reportString?.append(NSMutableAttributedString.init(string: "对比字符串【\(skipString)】未识别到\n",
                                                                attributes:[.foregroundColor : NSColor.red]))
        }else if failString.length > 0 {
            reportString?.append(NSMutableAttributedString.init(string: "字符串【\(failString)】识别出错\n",
                                                                attributes:[.foregroundColor : NSColor.red]))
        }
    }
    
    func replaceUnicodeString(_ string:NSString) -> NSString {//中
        let items = string.components(separatedBy: "\\u") as [NSString]
        
        var resultString = NSString()
        for item in items {
            if (item.contains("?")) {
                let unicodeValue = item.intValue
                let skipRange = item.range(of: "?")
                let nextString = item.substring(from: Int(skipRange.location + skipRange.length)) as NSString
                let bytes : [UInt8] = [UInt8(unicodeValue/256),UInt8(unicodeValue%256)]
                let data = NSData.init(bytes: bytes, length: 2)
                
                let unicodeString = NSString.init(data: data as Data, encoding: NSUnicodeStringEncoding)! as NSString
                resultString = resultString.appending(String("\(unicodeString)\(nextString)")) as NSString
            }else {
                resultString = resultString.appending(String(item)) as NSString
            }
        }
        
        return resultString
    }
    
}
