//
//  LKFDataStructures.swift
//  LKF
//
//  Created by Alexander Holzer on 28.03.23.
//  Copyright © 2023 Alexander Holzer. All rights reserved.
//

import Foundation
@_implementationOnly import LibLKF

public class LKFRecordTypes {
    public let model: UInt32
    public private(set) var recordTypes : [String:LKFRecordType]
    public private(set) var globalKASKOREChecks : [LKFRecordTypeCheck]
    public private(set) var globalBerichtChecks : [LKFRecordTypeCheck]
    public let errorDefList: LKFErrorDefList?
    public weak var lkfContext: LKFContext?
    
    public init (lkfContext: LKFContext) {
        self.model = lkfContext.model
        self.lkfContext = lkfContext
        self.recordTypes = [:]
        self.globalKASKOREChecks = []
        self.globalBerichtChecks = []
        guard let pSatzarten = LibLKF.lkf_Satzart_getDefinition(lkfContext.model) else {
            errorDefList = nil
            return
        }

        let count = LibLKF.lkf_Satzart_getCount(pSatzarten)
        self.recordTypes = [:]
        self.errorDefList = lkfContext.errorDefList
        
        var dict = [String:LKFRecordType]()
        
        let lineBuffer = UnsafeMutablePointer<CChar>.allocate(capacity:2048)
        defer {
            lineBuffer.deallocate()
        }
        
        for i in 0..<count {
            
            guard let recordType = LKFRecordType(recordTypes: self, satzarten: pSatzarten, index: i, lineBuffer: lineBuffer) else {
                continue
            }
            dict[recordType.type] = recordType
        }
        
        var gei : UInt32 = 0
        let kasKoreRecordType = LKFRecordType(recordTypes: self, type: "KASKORE", title: "KASKORE Global Checks", keyFieldIndices: nil)
        let allKasKoreField = LKFRecordTypeField(recordType: kasKoreRecordType, name: "Global", type: "", pos: nil, len: nil)
        kasKoreRecordType.change(allField: allKasKoreField)
        while let checkInfo = LibLKF.lkf_Satzart_getSatzartFieldCheck(lkfContext.ptr!, pSatzarten, 65536, gei) {
            if let recordTypeCheck = LKFRecordTypeCheck(field: allKasKoreField, checkInfo: checkInfo, lineBuffer: lineBuffer) {
                self.globalKASKOREChecks.append(recordTypeCheck)
            }
            gei += 1
        }
    
        let berichtRecordType = LKFRecordType(recordTypes: self, type: "BERICHT", title: "BERICHT Global Checks", keyFieldIndices: nil)
        let allBerichtField = LKFRecordTypeField(recordType: kasKoreRecordType, name: "Global", type: "", pos: nil, len: nil)
        berichtRecordType.change(allField: allBerichtField)
        gei = 0
        while let checkInfo = LibLKF.lkf_Satzart_getSatzartFieldCheck(lkfContext.ptr!, pSatzarten, 131072, gei) {
            if let recordTypeCheck = LKFRecordTypeCheck(field: allKasKoreField, checkInfo: checkInfo, lineBuffer: lineBuffer) {
                self.globalBerichtChecks.append(recordTypeCheck)
            }
            gei += 1
        }

        recordTypes = dict
    }
    
    public func getRecordTypes(global: Bool) -> [LKFRecordType] {
        if global {
            return recordTypes.values.filter { !$0.type.hasPrefix("X") && !$0.type.hasPrefix("I") }
        }
        return recordTypes.values.filter { $0.type.hasPrefix("X") || $0.type.hasPrefix("I") }
        
    }
    
    public func checksFor (errorCode: String) -> [LKFRecordTypeCheck]? {
        
        var checks : [LKFRecordTypeCheck]?

        for e in globalKASKOREChecks {
            if let c = e.checksFor(errorCode: errorCode) {
                if checks == nil {
                    checks = c
                }
                else {
                    checks!.append(contentsOf: c)
                }
            }
        }

        for e in globalBerichtChecks {
            if let c = e.checksFor(errorCode: errorCode) {
                if checks == nil {
                    checks = c
                }
                else {
                    checks!.append(contentsOf: c)

                }
            }
        }

        for e in recordTypes.values {
            if let c = e.checksFor(errorCode: errorCode) {
                if checks == nil {
                    checks = c
                }
                else {
                    checks!.append(contentsOf: c)

                }
            }
        }

        return checks
        
        
    }
}
