//
//  lkfcFeatureTests.swift
//  lkfcTests
//
//  Created by Alexander Holzer on 18.08.18.
//  Copyright © 2018 Alexander Holzer. All rights reserved.
//

import XCTest
@testable import lkfc

class lkfcFeatureTests: XCTestCase {
    
    override func setUp() {
        super.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.
        super.tearDown()
    }
    
    
    static var fall1 = [
        "X01|K714|1234||20190621|1200|S|19360501|80|M|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|R53|Z|D||",
        "X04|K714|1234||20190621|BG020||J|0001|20190621|2024|18111600|"]
    
    func createContextWith (model: UInt32, lines : [String]) throws -> LKFContext {
        return try lkfcTests.createContextWith(model:model, lines:lines)
    }
    
    func createContextWith (model: UInt32, year: Int32, flags : Int32 = 0, lines : [String]) throws -> LKFContext {
        return try lkfcTests.createContextWith(model: model, year: year, flags: flags, lines: lines)
    }
    func resultForContext (context: LKFContext) -> String {
        return lkfcTests.resultForContext (context: context)
    }
    
    func testErrorFormat() throws {
 
        let context = try createContextWith(model: 2019, lines: lkfcFeatureTests.fall1)
        _ = resultForContext(context: context)
        var errorFile = LKFOutputErrorFile(context: context)
        errorFile.setErrorFormat(facility:1, fields:[.code,.aufnr])
        var errors = errorFile.getOutput()
        XCTAssert(errors.contains("EX1K      ; 1234        "), "missing line or wrong format")
        
        errorFile = LKFOutputErrorFile(context: context)
        errors = errorFile.getOutput()
        XCTAssert(errors.contains("X03     ; 1234         ; X03 MBDS                       ; EX1K      ;                        ;            ;                      ; Hauptdiagnose fehlt"), "missing line or wrong format")

    }
    
    static var fallapg = [
    "X01|K201|APG01||20190103|1535|I|19580701|60|M|AT|AT|9360|20505|||||||||16|J|2||",
    "X02|K201|APG01||20190103|001|16111100|20190103|1535|J||||||N|60|",
    "X02|K201|APG01||20190103|002|17821100|20190103|1538|J||||||N|60|",
    "X02|K201|APG01||20190103|003|16725100|20190103|1614|J||||||N|60|",
    "X03|K201|APG01||20190103|I80.9|H|D||",
    "X03|K201|APG01||20190103|I10|Z|D||",
    "X04|K201|APG01||20190103|ZC510||J|1|20190103|1535|16111100||",
    "X04|K201|APG01||20190103|KC510||J|1|20190103|1540|16111100||",
    "X04|K201|APG01||20190103|EB510||J|1|20190103|1545|16111100||",
    "X04|K201|APG01||20190103|EZ510||J|1|20190103|1545|16111100||",
    "X04|K201|APG01||20190103|ZZ670||J|1|20190103|1552|17821100||",
    "X04|K201|APG01||20190103|ZB520||J|1|20190103|1614|16725100||",
    "X04|K201|APG01||20190103|ZZ531||J|1|20190103|1535|16111100||",
    "X04|K201|APG01||20190103|ZX540||J|19|20190103|1538|17821100||",
    "X04|K201|APG01||20190103|ZX560||J|3|20190103|1538|17821100||",
    "X04|K201|APG01||20190103|ZX580||J|32|20190103|1538|17821100||",
    "X04|K201|APG01||20190103|ZX620||J|2|20190103|1538|17821100||",
    "X04|K201|APG01||20190103|ZX740||J|1|20190103|1538|17821100||",
    "X04|K201|APG01||20190103|DE510||J|1|20190103|1540|16111100||",
    "X04|K201|APG01||20190103|DZ510||J|1|20190103|1540|16111100||"
    ]
    
    static var fallamg = [
    "X01|K214|AMG01||20190102|1023|I|19480713|70|M|AT|AT|9500|20201|||||||||05|J|0",
    "X02|K214|AMG01||20190102|001|16115800|20190102|1023|J||||||N|70|",
    "X02|K214|AMG01||20190102|002|17821100|20190102|1041|J||||||N|70|2019000091",
    "X02|K214|AMG01||20190102|003|16111100|20190102|1109|J||||||N|70|2019000091",
    "X02|K214|AMG01||20190102|004|16115800|20190102|1501|J||||||N|70|2019000091",
    "X03|K214|AMG01||20190102|R69|H|D||",
    "X03|K214|AMG01||20190102|C25.9|Z|D||2019000091",
    "X03|K214|AMG01||20190102|C78.7|Z|D||2019000091",
    "X03|K214|AMG01||20190102|I10|Z|D||2019000091",
    "X04|K214|AMG01||20190102|XC595||J|1|20190102|1501|16115800||2019000091",
    "X04|K214|AMG01||20190102|ZX540||J|16|20190102|1041|17821100||2019000091",
    "X04|K214|AMG01||20190102|ZX580||J|19|20190102|1041|17821100||2019000091",
    "X04|K214|AMG01||20190102|ZZ580||J|1|20190102|1111|16111100||2019000091"
    ]
    
    static var abtCountCase1 = [
        "X01|K427|123||20200201|0711|I|19570101|65|M|AT|AT|4971|41203|||||||||07|J|0||",
        "X02|K427|123||20200201|001|17115800|20200201|0711|J||||||N|65|11",
        "X02|K427|123||20200201|002|17725100|20200201|1127|J||||||N|65|11",
        "X03|K427|123||20200201|C90.0|H|||11",
        "X03|K427|123||20200201|H40.9|Z|||11",
        "X04|K427|123||20200201|DH040||J|1|20200201|1127|17725100||11",
        "X04|K427|123||20200201|ZB520||J|1|20200201|1341|17725100||11",
        "X04|K427|123||20200201|ZX540||J|1|20200201|0711|17821100||11",
        "X04|K427|123||20200201|ZX560||J|1|20200201|0711|17821100||11",
        "X04|K427|123||20200201|ZX580||J|1|20200201|0711|17821100||11",
        "X04|K427|123||20200201|ZX750||J|1|20200201|0711|17821100||11",
        "X04|K427|123||20200201|ZX899||J|1|20200201|0711|17115800||11",
        "X04|K427|123||20200201|ED515||J|1|20200201|1127|17725100||11",
        "X04|K427|123||20200201|EF510||J|1|20200201|1127|17725100||11",
        "X04|K427|123||20200201|XA022||J|1|20200201|0711|17115800||11",
        "X04|K427|123||20200201|XA022||J|1|20200201|0711|17115800||11",
        "X04|K427|123||20200201|ZA510||J|1|20200201|1127|17725100||11"
    ]
    
    static var abtCountCase2 = [
        ""
    ]

    
    func equalDouble (_ d1: Double, _ d2: Double) -> Bool {
        let diff = d1 - d2
        if diff < 0.0001 && diff > -0.0001 {
            return true
        }
        return false
    }
    
    func analyseResult (aufenthalt: LKFAufenthalt, expectedPoints: Int, output: Bool) -> Bool {
        let abtCount = aufenthalt.abtCount
        
        var tp = 0.0
        var lp = 0.0
        var sum = 0.0
        
        var res = true
                
        for i in 0..<abtCount {
            let abt = aufenthalt.abtAt(index: i)
            let res = abt.scoringData()
            if output {
                let s = String(format: "%@: %@ %8.2f %8.2f %8.2f", abt.ABTFC, res.pos, res.tp, res.lp, res.sum)
                print(s)
            }
            tp += res.tp
            lp += res.lp
            sum += res.sum
        }
        if output {
            print(String(format: "        :     %8.2f %8.2f %8.2f", tp, lp, sum))
        }

        let melCount = aufenthalt.melCount
        
        for i in 0..<melCount {
            let mel = aufenthalt.melAt(index: i)
            let res = mel.scoringData()
            if output {
                let s = String(format: "%@: %5d %5d %5d", res.mel, res.melzu, res.leist, res.plk)
                print(s)
            }
        }
        
        let result = aufenthalt.getResult()
        if output {
            print(String(format: "        :     %5d    %5d    %5d", result.tp + result.scutk, result.lp + result.melzu + result.sculk, result.sum))
        }

        if expectedPoints > 0 {
            res = expectedPoints == result.sum
            XCTAssert(res, "point difference actual=\(result.sum), expected:\(expectedPoints)")
        }
        
        if !equalDouble (Double(result.sum), sum) {
            XCTAssert(false, "different points")
            res = false
        }
        else {
            if !equalDouble (Double(result.tp + result.scutk), tp) {
                XCTAssert(false, "different contact points between case and X02")
                res = false
            }
            if !equalDouble (Double(result.lp + result.sculk + result.melzu), lp) {
                XCTAssert(false, "different mel points between case and X02")
                res = false
            }
        }
        
        return res
    }
    
    func analyseResult (context: LKFContext) -> (Int,Int) {
        let aufenthaltCount = context.getAufenthaltCount()
        var checkedCount : Int = 0
        var issueCount : Int = 0
        for i in 0..<aufenthaltCount {
            
            let aufenthalt = context[i]
            if !aufenthalt.isAmbulant || aufenthalt.getField(fieldNum: 1) >= "4" {
                continue
            }
            
            checkedCount += 1
            
            if !analyseResult(aufenthalt: context[i], expectedPoints: 0, output: false) {
                issueCount += 1
            }
        }
        return (checkedCount, issueCount)
    }

    func analyseFirstResult (context: LKFContext, expectedPoints: Int) -> Bool {
        let aufenthalt = context.first
        return analyseResult(aufenthalt: aufenthalt, expectedPoints: expectedPoints, output: false)
    }
    
    func testAmbAbtPoints() throws {
        
       var context = try createContextWith(model: 2019, year: 2019, lines: lkfcFeatureTests.fallapg)
        _ = resultForContext(context: context)
        _ = analyseFirstResult(context: context, expectedPoints: 79)
        
        context = try createContextWith(model: 2019, year: 2019, lines: lkfcFeatureTests.fallamg)
        _ = resultForContext(context: context)
        _ = analyseFirstResult(context: context, expectedPoints: 1508)
  
        context = try createContextWith(model: 2020, year: 2020, lines: lkfcFeatureTests.abtCountCase1)
        _ = resultForContext(context: context)
        _ = analyseFirstResult(context: context, expectedPoints: 0)
/*
       var context = try createContextWith(model: 2020, year: 2020, lines: lkfcFeatureTests.abtCountCase2)
        context.flags = 1
        _ = resultForContext(context: context)
        _ = analyseFirstResult(context: context, expectedPoints: 0)
*/
    }
    
    
    static let ambPath = URL(fileURLWithPath: "\(LKFTest.rootPath)amb2020", isDirectory: true)

    func testAmbAbtPath() throws {
        let files : [URL]
        do {
            files = try FileManager.default.contentsOfDirectory(at: lkfcFeatureTests.ambPath, includingPropertiesForKeys: nil, options: [])
        }
        catch {
            assert(false, "cannot read input files")
            return
        }
        
        var context : LKFContext

        for f in files {
            context = try LKFContext(model: 2020, path: LKFTest.rootPath)
            context.flags = 1
            do {
                try context.load(file: f, encoding: .windowsCP1252)
                try context.execute()
                let counter = analyseResult(context: context)
                if (counter.1 == 0){
                    print ("analysing \(f.absoluteString) : \(counter.0) ok")
                }
                else {
                    print ("analysing \(f.absoluteString) : \(counter.1) issues, \(counter.0) checked")
                }

            }
            catch {
                XCTAssert(false, "error reading file \(f.absoluteString)")
            }
        }
    }

    func expectErrorCount (context: LKFContext, code:String) -> Int {
        let err = context.errorsWith(code: code)
        return err?.count ?? 0
    }
    
    func expectError (context: LKFContext, code:String) -> Bool {
        return expectErrorCount(context: context, code: code) == 1
    }
    
    static var fall_melleist_stat = [
        "K01|2019|K427.1|17821100|100|Test|A",
        "K01|2019|K427.2|11111100|100|Test|A",
        "X01|K427|1234||20180102|1443|S|19310501|85|M|AT|AT|4941|41214|A|A||||E|20180112|1612|UB|N|||",
        "X02|K427|1234||20180102|001|11111100|20180102|1443|||||||N|85||00001",
        "X03|K427|1234||20180102|F10.0|H|||||00001",
        "X04|K427|1234||20180102|BD039|L|J|1|20180105|0120|11211100||"
    ]
    
    func testStandortInError() throws {
        let context = try createContextWith(model: 2019, year: 2018, lines: lkfcFeatureTests.fall_melleist_stat)
        _ = resultForContext(context: context)
        
        let errorFile = LKFOutputErrorFile(context: context)
        errorFile.errorTypes = 65535 - 255
        errorFile.setErrorFormat(fields: [.kanr, .code])
        let output = errorFile.getOutput()
        
        XCTAssert (output.contains("K427.2     ; WX51     "), "Standort-Info?")
    }
    
    static var fall_zn810 = [
        "X01|K427|1234||20180102|1443|S|19310501|85|M|AT|AT|4941|41214|A|A||||S|20180112|1612|UB|N|||",
        "X02|K427|1234||20180102|001|11111100|20180102|1443|||||||N|85||00001",
        "X03|K427|1234||20180102|F10.0|H|||||00001"
    ]
    
    static var zn810A = ["X04|K427|1234||20180102|ZN810||J|1|20180105|0120|11211100||"]
    static var zn810B = ["X04|K427|1234||20180102|ZN810||J|1|20180203|0120|11211100||"]
    static var zn810C = ["X04|K427|1234||20180102|ZN810||J|1|20180303|0120|11211100||"]

    static var fall_zn810y = [
        "X01|K427|1234||20181205|1443|S|19320401|85|M|AT|AT|4941|41214|A|A||||S|20181215|1612|UB|N|||",
        "X02|K427|1234||20181205|001|11111100|20181205|1443|||||||N|85||00001",
        "X03|K427|1234||20181205|F10.0|H|||||00001",
        "X04|K427|1234||20181205|ZN810||J|1|20190107|0120|11211100||"
    ]
    
    func testZN810() throws {
        var context = try createContextWith(model: 2018, year: 2018, lines: lkfcTests.combine (lkfcFeatureTests.fall_zn810, lkfcFeatureTests.zn810A))
        _ = resultForContext(context: context)
        XCTAssert(!expectError(context: context, code: "EX29"), "EX29 wrong")
        
        context = try createContextWith(model: 2019, year: 2018, lines: lkfcTests.combine (lkfcFeatureTests.fall_zn810, lkfcFeatureTests.zn810B))
        _ = resultForContext(context: context)
        XCTAssert(!expectError(context: context, code: "EX29"), "EX29 wrong")

        context = try createContextWith(model: 2019, year: 2018, lines: lkfcFeatureTests.fall_zn810)
        _ = resultForContext(context: context)
        XCTAssert(!expectError(context: context, code: "EX29"), "EX29 wrong")

        context = try createContextWith(model: 2019, year: 2018, lines: lkfcFeatureTests.fall_zn810y)
        _ = resultForContext(context: context)
        XCTAssert(!expectError(context: context, code: "EX29"), "EX29 wrong")

        
        context = try createContextWith(model: 2018, year: 2018, lines: lkfcTests.combine (lkfcFeatureTests.fall_zn810, lkfcFeatureTests.zn810C))
        _ = resultForContext(context: context)
        XCTAssert(expectError(context: context, code: "EX29"), "EX29 missing")
    }
    
    static var statData = [        "X01|K427|1234||20180102|1443|S|19310501|85|M|AT|AT|1020|41214|A|A||||E|20180112|1612|UB|N|||",
        "X02|K427|1234||20180102|001|11111100|20180102|1443|||||||N|85||00001",
        "X03|K427|1234||20180102|F10.0|H|||||00001",
        "X04|K427|1234||20180102|BD039|L|J|1|20180105|0120|11211100||",
        "X01|K427|1235||20180102|1443|S|19310501|85|M|DE|DE||41214|A|A||||E|20180112|1612|UB|N|||",
        "X02|K427|1235||20180102|001|11111100|20180102|1443|||||||N|85||00001",
        "X03|K427|1235||20180102|F10.0|H|||||00001",
        "X04|K427|1235||20180102|BD039|L|J|1|20180105|0120|11211100||"
    ]
    
    static func replace(source:[String], from: String, to: String) -> [String] {
        var result = [String]()
        for s in source {
            result.append(s.replacingOccurrences(of: from, with: to))
        }
        return result
    }
    
    func replace(source:[String], from: String, to: String) -> [String] {
        return lkfcFeatureTests.replace(source:source, from: from, to:to)
    }
    
    func testStatOnly () throws  {
        var context = try LKFNoMetaDataContext (year:2020, path: LKFTest.rootPath)
        if let lastError = context.lastError {
            XCTAssert(false, lastError.message)
        }
        else {

            for s in lkfcFeatureTests.statData {
                try? context.addLine(line: s)
            }
        
            _ = resultForContext(context: context)

            try context.executeStat()
       
            let statFile = LKFOutputStatFile(context: context)
            let res = statFile.createOutput()
        
            /*
            for s in res {
                print("\(s)\n")
            }
            */
        }
        
        context = try LKFNoMetaDataContext (year:2026, path: LKFTest.rootPath)
        if let lastError = context.lastError {
            XCTAssert(false, lastError.message)
        }
        else {
            let future = replace(source: lkfcFeatureTests.statData, from: "2018", to: "2026")

            for s in future {
                try? context.addLine(line: s)
            }
        
            _ = resultForContext(context: context)
        
            try context.executeStat()
        
            let statFile = LKFOutputStatFile(context: context)
            let res = statFile.createOutput()
            /*
            for s in res {
                print("\(s)\n")
            }
             */
        }
        
        context = try LKFNoMetaDataContext (year:1996, path: LKFTest.rootPath)
        
        if let lastError = context.lastError {
            XCTAssert(false, lastError.message)
        }
        else {
            let old = replace(source: lkfcFeatureTests.statData, from: "2018", to: "1996")
            for s in old {
                try? context.addLine(line: s)
            }
            
            _ = resultForContext(context: context)
            
            try context.executeStat()
            
            let statFile = LKFOutputStatFile(context: context)
            let res = statFile.createOutput()
            /*
            for s in res {
                print("\(s)\n")
            }
             */
        }
    }
    
    static var fall_am110 = [
        "X01|K427|1234||20180102|1443|S|19310501|85|M|AT|AT|1020|41214|H|||||H|20180112|1612|UB|N|||",
        "X02|K427|1234||20180102|001|14516802|20180102|1443|||||||N|85||00001",
        "X03|K427|1234||20180102|F10.0|H|||||00001",
        "X04|K427|1234||20180102|AM110||J|1|20180105|0120|14516802||",
        "L01|2019|K427|14516802|O|TK|",
    ]

    static var fall_am120 = [
        "X01|K427|1234||20180102|1443|S|19310501|85|M|AT|AT|1020|41214|H|||||H|20180112|1612|UB|N|||",
        "X02|K427|1234||20180102|001|14648501|20180102|1443|||||||N|85||00001",
        "X03|K427|1234||20180102|F10.0|H|||||00001",
        "X04|K427|1234||20180102|AM120||J|1|20180105|0120|14516802||",
        "L01|2019|K427|14648501|J|TK|",
    ]
    
    func testAM110 () throws {
        let context = try createContextWith(model: 2020, year: 2018, lines: lkfcFeatureTests.fall_am120)
         _ = resultForContext(context: context)
         XCTAssert(!expectError(context: context, code: "WX3Q"), "WX3Q wrong")
/*
        context = try createContextWith(model: 2020, year: 2018, lines: lkfcFeatureTests.fall_am110)
        _ = resultForContext(context: context)
        XCTAssert(!expectError(context: context, code: "WX3Q"), "WX3Q wrong")
 */
    }
    
    static var fallTransMEL = [
    "X01|K214|TRANS||20190102|1023|I|19480713|70|M|AT|AT|9500|20201|||||||||05|J|0",
    "X02|K214|TRANS||20190102|001|16115800|20190102|1023|J||||||N|70|",
    "X02|K214|TRANS||20190102|002|17821100|20190102|1041|J||||||N|70|2019000091",
    "X02|K214|TRANS||20190102|003|16111100|20190102|1109|J||||||N|70|2019000091",
    "X02|K214|TRANS||20190102|004|16115800|20190102|1501|J||||||N|70|2019000091",
    "X03|K214|TRANS||20190102|R69|H|D||",
    "X03|K214|TRANS||20190102|F64.0|H|D||",
    "X04|K214|TRANS||20190102|QE180|L|J|1|20190102|1501|16115800||2019000091"
    ]

    static var fallTransMEL2 = [
    "X01|K214|TRANS||20190102|1023|I|19480713|70|M|AT|AT|9500|20201|||||||||05|J|0",
    "X02|K214|TRANS||20190102|001|16115800|20190102|1023|J||||||N|70|",
    "X02|K214|TRANS||20190102|002|17821100|20190102|1041|J||||||N|70|2019000091",
    "X02|K214|TRANS||20190102|003|16111100|20190102|1109|J||||||N|70|2019000091",
    "X02|K214|TRANS||20190102|004|16115800|20190102|1501|J||||||N|70|2019000091",
    "X03|K214|TRANS||20190102|F64.0|H|D||",
    "X04|K214|TRANS||20190102|QE180|L|J|1|20190102|1501|16115800||2019000091"
    ]

    static var fallTransMEL3 = [
     "X01|K214|TRANS||20190102|1023|I|19480713|70|X|AT|AT|9500|20201|||||||||05|J|0",
     "X02|K214|TRANS||20190102|001|16115800|20190102|1023|J||||||N|70|",
     "X02|K214|TRANS||20190102|002|17821100|20190102|1041|J||||||N|70|2019000091",
     "X02|K214|TRANS||20190102|003|16111100|20190102|1109|J||||||N|70|2019000091",
     "X02|K214|TRANS||20190102|004|16115800|20190102|1501|J||||||N|70|2019000091",
     "X03|K214|TRANS||20190102|R69|H|D||",
     "X04|K214|TRANS||20190102|QE180|L|J|1|20190102|1501|16115800||2019000091"
     ]
    
    static var fallTransHD = [
    "X01|K214|TRANS||20190102|1023|I|19480713|70|M|AT|AT|9500|20201|||||||||05|J|0",
    "X02|K214|TRANS||20190102|001|16115800|20190102|1023|J||||||N|70|",
    "X02|K214|TRANS||20190102|002|17821100|20190102|1041|J||||||N|70|2019000091",
    "X02|K214|TRANS||20190102|003|16111100|20190102|1109|J||||||N|70|2019000091",
    "X02|K214|TRANS||20190102|004|16115800|20190102|1501|J||||||N|70|2019000091",
    "X03|K214|TRANS||20190102|C79.6|H|D||",
    "X03|K214|TRANS||20190102|R69|H|D||",
    "X03|K214|TRANS||20190102|F64.0|H|D||",
    ]
    
    static var fallTransZD = [
    "X01|K214|TRANS||20190102|1023|I|19480713|70|M|AT|AT|9500|20201|||||||||05|J|0",
    "X02|K214|TRANS||20190102|001|16115800|20190102|1023|J||||||N|70|",
    "X02|K214|TRANS||20190102|002|17821100|20190102|1041|J||||||N|70|2019000091",
    "X02|K214|TRANS||20190102|003|16111100|20190102|1109|J||||||N|70|2019000091",
    "X02|K214|TRANS||20190102|004|16115800|20190102|1501|J||||||N|70|2019000091",
    "X03|K214|TRANS||20190102|C79.6|Z|D||",
    "X03|K214|TRANS||20190102|F64.0|H|D||",
    ]

    static var fallTransZD2 = [
    "X01|K214|TRANS||20190102|1023|I|19480713|70|M|AT|AT|9500|20201|||||||||05|J|0",
    "X02|K214|TRANS||20190102|001|16115800|20190102|1023|J||||||N|70|",
    "X02|K214|TRANS||20190102|002|17821100|20190102|1041|J||||||N|70|2019000091",
    "X02|K214|TRANS||20190102|003|16111100|20190102|1109|J||||||N|70|2019000091",
    "X02|K214|TRANS||20190102|004|16115800|20190102|1501|J||||||N|70|2019000091",
    "X03|K214|TRANS||20190102|R69|H|D||",
    "X03|K214|TRANS||20190102|C79.6|Z|D||",
    "X03|K214|TRANS||20190102|F64.0|Z|D||",
    ]

    
    func testEX1Y () throws {
        var context = try createContextWith(model: 2020, year: 2019, lines: lkfcFeatureTests.fallTransMEL)
         _ = resultForContext(context: context)
         XCTAssert(!expectError(context: context, code: "EX1Y"), "EX1Y wrong")
        
        context = try createContextWith(model: 2019, year: 2019, lines: lkfcFeatureTests.fallTransMEL)
        _ = resultForContext(context: context)
        XCTAssert(expectError(context: context, code: "EX1Y"), "EX1Y expected") // BUG - compatibility 2019

        context = try createContextWith(model: 2019, year: 2019, lines: lkfcFeatureTests.fallTransMEL2)
        _ = resultForContext(context: context)
        XCTAssert(!expectError(context: context, code: "EX1Y"), "EX1Y wrong")

        context = try createContextWith(model: 2020, year: 2019, lines: lkfcFeatureTests.fallTransMEL3)
        _ = resultForContext(context: context)
        XCTAssert(!expectError(context: context, code: "EX1Y"), "EX1Y wrong")

        context = try createContextWith(model: 2019, year: 2019, lines: lkfcFeatureTests.fallTransHD)
        _ = resultForContext(context: context)
        XCTAssert(expectError(context: context, code: "EX1U"), "EX1U expected")

        context = try createContextWith(model: 2020, year: 2019, lines: lkfcFeatureTests.fallTransHD)
        _ = resultForContext(context: context)
        XCTAssert(!expectError(context: context, code: "EX1U"), "EX1U wrong")

        context = try createContextWith(model: 2019, year: 2019, lines: lkfcFeatureTests.fallTransZD)
        _ = resultForContext(context: context)
        XCTAssert(expectError(context: context, code: "EX1U"), "EX1U expected")

        context = try createContextWith(model: 2020, year: 2019, lines: lkfcFeatureTests.fallTransZD)
        _ = resultForContext(context: context)
        XCTAssert(!expectError(context: context, code: "EX1U"), "EX1U wrong")

        context = try createContextWith(model: 2019, year: 2019, lines: lkfcFeatureTests.fallTransZD2)
        _ = resultForContext(context: context)
        XCTAssert(expectError(context: context, code: "EX1U"), "EX1U expected")

        context = try createContextWith(model: 2020, year: 2019, lines: lkfcFeatureTests.fallTransZD2)
        _ = resultForContext(context: context)
        XCTAssert(!expectError(context: context, code: "EX1U"), "EX1U wrong")

    }

    
    static func createStatContextWith (year: UInt32, lines : [String]) throws -> LKFContext {
        let context = try LKFNoMetaDataContext (year: year, path: LKFTest.rootPath)
        //context.setContextParameters(year: year)
        for s in lines {
            try? context.addLine(line: s)
        }
        return context
    }

    static var fallGesBd = [
        "X01|K214|GES1||20190102|1023|S|19480713|70|M|AT|AT|9500|20201|A|||||E|20190103|1214|05|J|0",
        "X02|K214|GES1||20190102|001|16115800|20190102|1023|J||||||N|70|",
        "X02|K214|GES1||20190102|002|10000000|20190102|1641|J||||||N|70|2019000091",
        "X02|K214|GES1||20190102|003|16111100|20190103|1109|J||||||N|70|2019000091",
        "X03|K214|GES1||20190102|R69|H|D||"
    ]

    func testGesBD () throws {
        let statcontext = try lkfcFeatureTests.createStatContextWith(year: 2019, lines: lkfcFeatureTests.fallGesBd)
        _ = resultForContext(context: statcontext)
        var res = statcontext[0].getResult()
        if let gesbd = res.getFieldValue(fieldIndex: 14) {
            XCTAssert(gesbd == "0", "gesbd 0 expected (value = \(gesbd)")
        }
        let standardContext = try createContextWith(model: 2019, year: 2019, lines: lkfcFeatureTests.fallGesBd)
        _ = resultForContext(context: standardContext)
        res = standardContext[0].getResult()
        if let gesbd = res.getFieldValue(fieldIndex: 14) {
            XCTAssert(gesbd == "0", "gesbd 0 expected (value = \(gesbd))")
        }
    }
    
    static var fall_oemelka = [
        "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||20200303|F10.0|H|||||00001",
        "X04|K917|234||20200303|XC380||J|1|20200303|0802|12718100||0219000009|2345|00001"
    ]

    func testFlagMELPOS () throws {
        var context = try createContextWith(model: 2020, year: 2020, flags: (1<<23), lines: lkfcFeatureTests.fall_oemelka)
        _ = resultForContext(context: context)
        var errors = context.errorsWith (code:"WX2Q", fields:[.code,.aufnr,.feld_lang, .mbds_mel])
        if let errors {
            XCTAssert (errors[0] == "WX2Q      ; 234          ; 001:XC380              ; XC380       ", "incorrect output for WX2Q")
        }
        else {
            XCTAssert (errors != nil, "missing error WX2Q")
        }
        context = try createContextWith(model: 2020, year: 2020, flags: (1<<23) + (1<<29), lines: lkfcFeatureTests.fall_oemelka)
        _ = resultForContext(context: context)
        errors = context.errorsWith (code:"WX2Q", fields:[.code,.aufnr,.feld_lang, .mbds_mel])
        XCTAssert (errors != nil, "missing error WX2Q")
        if let errors {
            XCTAssert (errors[0] == "WX2Q      ; 234          ; XC380:2345             ; XC380:2345  ", "incorrect output for WX2Q")
        }
        else {
            XCTAssert (errors != nil, "missing error WX2Q")
        }
    }

    func testChangeModel () throws {

        guard let url2024 = URL(string: "file:///Users/alexanderholzer/lkf/test/2024/") else {
            XCTAssert (false, "could not create 2024 model url")
            return
        }
        
        guard let url2025 = URL(string:"file:///Users/alexanderholzer/lkf/test/2025/") else {
            XCTAssert (false, "could not create 2025 model url")
            return
        }
        
        let metaDataContext2024 = LKFMetaDataFilesContext(model: 2024, baseUrl: url2024)
        let metaDataContext2025 = LKFMetaDataFilesContext(model: 2025, baseUrl: url2025)
        
        
        _ = try metaDataContext2024.load()
        _ = try metaDataContext2025.load()
        
        let context = try LKFContext(metaDataContext: metaDataContext2024)
        context.setContextParameters(year: 2024)
        context.flags = 1
        guard let fileUrl = URL(string:"file:///Users/alexanderholzer/lkf/test/in2025/d/k952j001.s25") else {
            XCTAssert (false, "could not create 2025 datafile url")
            return
        }

        try context.load(file: fileUrl, encoding: .isoLatin1)
        
        for it in 1..<3 {
            try context.execute()
            let scges = context.getScorField(field: 34)
            XCTAssert (scges == 15197707, "scoring sum is not correct (2024/{\(it)}): \(scges)")
        }
        

        try context.changeModel(metaDataContext: metaDataContext2025)

        for it in 1..<5 {
            try context.execute()
            let scges = context.getScorField(field: 34)
            XCTAssert (scges == 7751525, "scoring sum is not correct (2025/{\(it)}): \(scges)")
        }

        try context.changeModel(metaDataContext: metaDataContext2024)
        
        for it in 1..<5 {
            try context.execute()
            let scges = context.getScorField(field: 34)

            XCTAssert (scges == 15197707, "scoring sum is not correct (2024/{\(it)}): \(scges)")
        }
    }
}
