//
//  lkf2020SP1Tests.swift
//  lkfcTests
//
//  Created by Alexander Holzer on 12.10.19.
//  Copyright © 2019 Alexander Holzer. All rights reserved.
//

import XCTest
@testable import lkfc

class lkf2020SP1Tests: XCTestCase {

    
    func createContextWith (model: UInt32, lines : [String]) throws -> LKFContext {
        return try lkfcTests.createContextWith(model:model, lines:lines)
    }
    
    func createContextWith (model: UInt32, year: Int32, lines : [String]) throws -> LKFContext {
        return try lkfcTests.createContextWith(model:model, year: year, lines:lines)
    }

    
    func resultForContext (context: LKFContext) -> String {
        return lkfcTests.resultForContext (context: context)
    }
    
    func combine (_ first:[String], _ second:[String]) -> [String] {
        return lkfcTests.combine(first, second)
    }

    override func setUp() {
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }

    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }

    static var fall_wx4n = [
        "X01|K714|1234||20190621|1200|S|19360601|80|W|AT|AT|1010|90101|A|P||||E|20190621|1200|11|J|0",
        "X02|K714|1234||20190621|01|11111100|20190621||J||||||N|80|",
                "X03|K714|1234||20190621|I51.9|H|D||",
        "X03|K714|1234||20190621|901.9|Z|D||11111100||Z1",
        "X03|K714|1234||20190621|929.9|Z|D||11211100||Z2"]

    static let warningFields : [LKFErrorField] = [.aufnr, .ident, .code, .fucoaufnr, .childIdent, .feld_lang]

    func testWX4N () throws {
        var context = try createContextWith(model:2019, lines: lkf2020SP1Tests.fall_wx4n)
        XCTAssert (context.lastError == nil, "couldn't not execute case" + context.lastError!.message)
        var res = resultForContext(context: context)
        var errors = context.errorsWith (code:"WX4N") // Diagnosen-Kombination
        XCTAssert (errors != nil, "missing error WX4N")

        if let warningOutput = context.warningOutput(fields:lkf2020SP1Tests.warningFields), warningOutput.count == 2 {
            XCTAssert(warningOutput[1].compare ("1234         ; X01 MBDS                       ; WX4N      ;              ;                 ; 901.9 929.9 ") == .orderedSame, "different warning line 2019/WX4N")
        }
        else {
            XCTAssert(false, "no warning output: 2019/WX4N")
        }
        
        XCTAssert(res.compare ("X05|K714|1234||20190621|HDG06.04|A||||30|||||30") == .orderedSame, "result different")
        
        context = try createContextWith(model:2020, lines: lkf2020SP1Tests.fall_wx4n)
        XCTAssert (context.lastError == nil, "couldn't not execute case" + context.lastError!.message)
        context.flags = 1<<17
        res = resultForContext(context: context)
        errors = context.errorsWith (code:"WX4N") // Diagnosen-Kombination
        XCTAssert (errors != nil, "invalid error WX4N")
        
        if let warningOutput = context.warningOutput(fields:lkf2020SP1Tests.warningFields), warningOutput.count == 3  {
            XCTAssert(warningOutput[1].compare ("1234         ; X03 Z929.9                     ; WX4N      ; 11211100     ; Z2              ; 901.9 929.9 ") == .orderedSame, "different warning line 2020/WX4N")
            XCTAssert(warningOutput[2].compare ("1234         ; X03 Z901.9                     ; * WX4N    ; 11111100     ; Z1              ; 901.9 929.9 ") == .orderedSame, "different warning line 2020/WX4N")

        }
        else {
            XCTAssert(false, "missing/incorrect warning output: 2020/WX4N")
        }
        XCTAssert(res.compare ("X05|K714|1234||20190621|HDG06.04|A||||30|||||30") == .orderedSame, "result different")

 //       XCTAssert (res.compare("X05|K714|1234||20190621|HDG06.04|A|||36|30|||||66") == ComparisonResult.orderedSame, "result different")
    }
    
    static var fall_wx4z = [
    "X01|K418|234||20190303|0802|I|19850101|30|M|AT|AT|1020|90201|2||||||||14|J|||",
    "X02|K418|234||20190303|001|16731100|20190303|0802|J|||||||30|0219000009|00001",
    "X02|K418|234||20190303|002|16731100|20190303|0852|J|||||||30|0219000003|00002",
    "X04|K418|234||20190303|ZZ531||J|1|20190303|0852|16731100||0219000003||00002",
    "X04|K418|234||20190303|ZZ531||J|1|20190303|0802|16731100||0219000009||00003",
    "X04|K418|234||20190303|ZZ531||J|1|20190303|0802|16731100||0219000009||00001"
    ]

    func testWX4Z () throws {
        let context = try createContextWith(model:2019, lines: lkf2020SP1Tests.fall_wx4z)
        XCTAssert (context.lastError == nil, "couldn't not execute case" + context.lastError!.message)
        context.flags = 1<<17
        let res = resultForContext(context: context)
        let errors = context.errorsWith (code:"WX4Z") // Diagnosen-Kombination
        XCTAssert (errors != nil, "missing error WX4Z")

        if let warningOutput = context.warningOutput(fields:lkf2020SP1Tests.warningFields), warningOutput.count >= 2  {
            XCTAssert(warningOutput[1].compare ("234          ; X04 ZZ531                      ; WX4Z      ; 0219000009   ; 00003           ; 001:ZZ531       ") == .orderedSame)
            XCTAssert(warningOutput[2].compare ("234          ; X04 ZZ531                      ; * WX4Z    ; 0219000009   ; 00001           ; 001:ZZ531       ") == .orderedSame)
            XCTAssert(warningOutput[3].compare ("234          ; X04 ZZ531                      ; * WX4Z    ; 0219000003   ; 00002           ; 001:ZZ531       ") == .orderedSame)

        }
        else {
            XCTAssert(false, "missing/incorrect warning output: 2020/WX4N")
        }
        XCTAssert(res.compare ("X05|K418|234||20190303|APG18.50|A||41|||||||41") == .orderedSame, "result different")
    }
    
    static var fall_oemelka1 = [
        "K01|2019|K917.1|12718100|100|Test|A",
        "K01|2019|K917.2|11111100|100|Test|A",
        "X01|K917|234||20200303|1443|S|19310501|85|M|AT|AT|4941|41214|A|A||||E|20200312|1612|UB|N|||",
        "X02|K917|234||20200303|001|12718100|20200303|0802|J|||||||30|0219000009|00001",
        "X02|K917|234||20200303|002|12718100|20200303|0852|J|||||||30|0219000003|00002",
        "X03|K917|234||202ß0303|F10.0|H|||||00001"
    ]
    
    static var fall_gleicheKA = [
    "X04|K917|234||20200303|XC380||J|1|20200303|0802|12718100||0219000009||00001"
    ]

    static var fall_andererStandort = [
    "X04|K917|234||20200303|XC380||J|1|20200303|0802|11111100|K917.2|0219000009||00001"
    ]

    static var fall_K915 = [
    "X04|K917|234||20200303|XC380||J|1|20200303|0802||K915|||00001"
    ]

    static var fall_K915_1 = [
    "X04|K917|234||20200303|XC380||J|1|20200303|0802||K915.1|||00001"
    ]

    static var fall_K915_2 = [
    "X04|K917|234||20200303|XC380||J|1|20200303|0802||K915.2|||00001"
    ]

    static var fall_K000 = [
    "X04|K917|234||20200303|XC380||J|1|20200303|0802||K000|||00001"
    ]

    static var fall_E000 = [
    "X04|K917|234||20200303|XC380||J|1|20200303|0802||E000|||00001"
    ]
    
    // Test erfordert 2020-OEMELKA = K917.1XC380N X         X
    // Test erfordert 2020-OEMELKA = K915.2XC380N X         X
    
    func testOEMELKA() throws {
        var context = try createContextWith(model:2020, lines: lkfcTests.combine (lkf2020SP1Tests.fall_oemelka1, lkf2020SP1Tests.fall_gleicheKA))
        XCTAssert (context.lastError == nil, "couldn't not execute case" + context.lastError!.message)
        context.flags = 1<<23
        _ = resultForContext(context: context)
        var errors = context.errorsWith (code:"WX2Q")
        XCTAssert (errors != nil, "missing error WX2Q")
        
        context = try createContextWith(model:2020, lines: lkfcTests.combine (lkf2020SP1Tests.fall_oemelka1, lkf2020SP1Tests.fall_andererStandort))
        XCTAssert (context.lastError == nil, "couldn't not execute case" + context.lastError!.message)
        context.flags = 1<<23
        _ = resultForContext(context: context)
        errors = context.errorsWith (code:"WX2Q")
        XCTAssert (errors == nil, "WX2Q not expected")

        context = try createContextWith(model:2020, lines: lkfcTests.combine (lkf2020SP1Tests.fall_oemelka1, lkf2020SP1Tests.fall_K915))
        XCTAssert (context.lastError == nil, "couldn't not execute case" + context.lastError!.message)
        context.flags = 1<<23
        _ = resultForContext(context: context)
        errors = context.errorsWith (code:"WX2Q")
        //XCTAssert (errors != nil, "missing error WX2Q")
        XCTAssert (errors == nil, "WX2Q not expected")
        context = try createContextWith(model:2020, lines: lkfcTests.combine (lkf2020SP1Tests.fall_oemelka1, lkf2020SP1Tests.fall_K915_1))
        XCTAssert (context.lastError == nil, "couldn't not execute case" + context.lastError!.message)
        context.flags = 1<<23
        _ = resultForContext(context: context)
        errors = context.errorsWith (code:"WX2Q")
        XCTAssert (errors == nil, "WX2Q not expected")

        context = try createContextWith(model:2020, lines: lkfcTests.combine (lkf2020SP1Tests.fall_oemelka1, lkf2020SP1Tests.fall_K915_2))
        XCTAssert (context.lastError == nil, "couldn't not execute case" + context.lastError!.message)
        context.flags = 1<<23
        _ = resultForContext(context: context)
        errors = context.errorsWith (code:"WX2Q")
        XCTAssert (errors != nil, "missing error WX2Q")

        context = try createContextWith(model:2020, lines: lkfcTests.combine (lkf2020SP1Tests.fall_oemelka1, lkf2020SP1Tests.fall_K000))
        XCTAssert (context.lastError == nil, "couldn't not execute case" + context.lastError!.message)
        context.flags = 1<<23
        _ = resultForContext(context: context)
        errors = context.errorsWith (code:"WX2Q")
        XCTAssert (errors == nil, "WX2Q not expected for K000")

        context = try createContextWith(model:2020, lines: lkfcTests.combine (lkf2020SP1Tests.fall_oemelka1, lkf2020SP1Tests.fall_E000))
        XCTAssert (context.lastError == nil, "couldn't not execute case" + context.lastError!.message)
        context.flags = 1<<23
        _ = resultForContext(context: context)
        errors = context.errorsWith (code:"WX2Q")
        XCTAssert (errors == nil, "missing error WX2Q for E000")
    }
    
    static var fall_oemelka2 = [
            "K01|2019|K917.1|12718100|100|Test|A",
            "K01|2019|K917.2|11111100|100|Test|A",
    "X01|K917|234||20200303|1443|S|19310501|85|M|AT|AT|4941|41214|A|A||||E|20200312|1612|UB|N|||",
            "X02|K917|234||20200303|001|11111101|20200303|0802|J|||||||30|0219000009|00001",
            "X02|K917|234||20200303|002|12718100|20200305|0852|J|||||||30|0219000003|00002",
            "X03|K917|234||202ß0303|F10.0|H|||||00001",
            "X04|K917|234||20200303|XC380||J|1|20200305|0802|12718100||0219000009||00001"
        ]

    func testOEMELKA2() throws {
        let context = try createContextWith(model:2020, lines: lkf2020SP1Tests.fall_oemelka2)
        XCTAssert (context.lastError == nil, "couldn't not execute case" + context.lastError!.message)
        context.flags = 1<<23
        _ = resultForContext(context: context)
        
        var foundWX2Q = false
        var foundWX3L = false

        if let warnings = context.warningOutput(fields: [.kanr, .abtfc, .code, .feld, .text]) {
            
            for w in warnings {
                if w.range(of: "WX2Q") != nil {
                    foundWX2Q = true
                    if !w.hasPrefix("K917.1     ; 12718100 ; WX2Q      ; 002:XC380   ;") {
                        XCTAssert (false, "WX2Q different")
                    }
                }
                else if w.range(of: "WX3L") != nil {
                    foundWX3L = true
                    if !w.hasPrefix("K917.1     ; 12718100 ; WX3L      ; 002:XC380   ;") {
                        XCTAssert (false, "WX3L different")
                    }
                }
            }
        }
            
        if !foundWX2Q {
            XCTAssert (false, "WX2Q not found")
        }
        if !foundWX3L {
            XCTAssert (false, "WX3L not found")
        }
    }

    static var ambABTVD = [
        "X01|K102|1||20200101|1000|I|19340101|85|M|AT|AT|8010|60101|||||||||15|J|0||",
        "X02|K102|1||20200101|001|16914600|20200101|2136|J||||||N|85|",
        "X02|K102|1||20200101|002|17725100|20200101|2326|J||||||N|85|",
        "X02|K102|1||20200101|003|16914600|20200102|0021|J||||||N|85|"
    ]
    
    
    func testAmbABTVD() throws {
        var context = try createContextWith(model:2017, lines: lkf2020SP1Tests.ambABTVD)
        XCTAssert (context.lastError == nil, "couldn't not execute case" + context.lastError!.message)
        _ = resultForContext(context: context)
        var aufenthalt = context[0]
        XCTAssert(aufenthalt.getField(fieldNum: 14) == "1", "Amb-GESVD 2017 is expected to be 1 (overnight)")
        var result = aufenthalt.getResult()
        XCTAssert(result.abtbd[1] == 1, "Amb-ABTBD 2017 is expected to be 1 (overnight)")
        
        context = try createContextWith(model:2019, lines: lkf2020SP1Tests.ambABTVD)
        XCTAssert (context.lastError == nil, "couldn't not execute case" + context.lastError!.message)
        _ = resultForContext(context: context)
        aufenthalt = context[0]
        XCTAssert(aufenthalt.getField(fieldNum: 14) == "0", "Amb-GESVD 2019 is expected to be 0")
        result = aufenthalt.getResult()
        XCTAssert(result.abtbd[1] == 1, "Amb-ABTBD 2019 is expected to be 1 (overnight)")

        context = try createContextWith(model:2020, lines: lkf2020SP1Tests.ambABTVD)
        XCTAssert (context.lastError == nil, "couldn't not execute case" + context.lastError!.message)
        _ = resultForContext(context: context)
        aufenthalt = context[0]
        XCTAssert(aufenthalt.getField(fieldNum: 14) == "0", "Amb-GESVD 2020 is expected to be 0")
        result = aufenthalt.getResult()
        XCTAssert(result.abtbd[1] == 0, "Amb-ABTBD 2020 is expected to be 0")

    }
}
