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

import Foundation
@_implementationOnly import LibLKF

public class LKFRecordType {
    
    public let recordTypes: LKFRecordTypes
    public let type: String
    public let title: String
    public let keyfieldIndices : [Int]?
    public private(set) var fields : [LKFRecordTypeField]
    
    public private(set) var allField : LKFRecordTypeField?
    public private(set) var recordTypeCheck : LKFRecordTypeCheck?
    
    public var typeOrder : String {
        if type.hasPrefix("I") {
            return "Z" + type
        }
        return type
    }
    
    init (recordTypes: LKFRecordTypes, type: String, title: String, keyFieldIndices: [Int]?) {
        self.recordTypes = recordTypes
        self.type = type
        self.title = title
        self.keyfieldIndices = keyFieldIndices
        self.fields = []
    }
    
    var lkfContext : LKFContext? {
        return recordTypes.lkfContext
    }
    
    static func partsFrom (cString:UnsafePointer<CChar>, separator: CharacterSet = [";"], minimumParts: Int? = nil) -> [String]? {
        let parts = String(cString:cString).components(separatedBy: separator)
        if let minimumParts {
            return parts.count >= minimumParts ? parts : nil
        }
        return parts.count >= 0 ? parts : nil
    }
    
    public var keyFields : [LKFRecordTypeField]? {
        
        guard let keyfieldIndices else {
            return nil
        }
        var arr = [LKFRecordTypeField]()
        for k in keyfieldIndices {
            if k >= 0 && k < fields.count {
                arr.append(fields[k])
            }
        }
        return arr
    }
    
    public var otherFields : [LKFRecordTypeField]? {
        guard let keyfieldIndices else {
             return fields
        }

        var arr = [LKFRecordTypeField]()

        for i in 0..<fields.count {
            if keyfieldIndices.contains(i) {
                continue
            }
            arr.append(fields[i])
        }
        return arr
            
    }
    
    public func isKeyField (index: Int) -> Bool {
        if let keyfieldIndices {
            return keyfieldIndices.contains(where: { $0 == index})
        }
        return false
    }
    
    convenience init? (recordTypes: LKFRecordTypes, satzarten: OpaquePointer, index: UInt32, lineBuffer: UnsafeMutablePointer<CChar>) {
        
        guard LibLKF.lkf_Satzart_getSatzartDef(satzarten, index, lineBuffer, 1024) != 0, let parts = LKFRecordType.partsFrom(cString: lineBuffer, minimumParts: 4) else {
            return nil
        }
        let type = parts[1]
        let title = parts[3]
        let recordTypes = recordTypes
        let keyFieldIndices : [Int]?
        
        if LibLKF.lkf_Satzart_getSatzartKeyInfo(satzarten, index, lineBuffer, 1024) != 0, let parts = LKFRecordType.partsFrom(cString: lineBuffer) {
            keyFieldIndices = parts.map { Int($0.trimmingCharacters(in: .whitespaces)) ?? -1 }
        }
        else {
            keyFieldIndices = nil
        }
        
        self.init(recordTypes: recordTypes, type: type, title: title, keyFieldIndices: keyFieldIndices)
        
        let fieldCount = LibLKF.lkf_Satzart_getSatzartFieldCount(satzarten, index)
        
        self.fields = [LKFRecordTypeField]()
        
        for f in 0..<fieldCount {
            if let field = LKFRecordTypeField(recordType: self, satzarten: satzarten, satzartIndex: index, fieldIndex: f, lineBuffer: lineBuffer) {
                self.fields.append(field)
            }
        }
        
        if let lkfContext {
            
            if let checkInfo = LibLKF.lkf_Satzart_getSatzartFieldCheck(lkfContext.ptr!, satzarten, index, 65536) {
                self.allField = LKFRecordTypeField (recordType: self, name: "Satzart-Check", type: "-", pos: nil, len: nil)
                recordTypeCheck = LKFRecordTypeCheck(field: allField!, checkInfo: checkInfo, lineBuffer: lineBuffer)
                self.allField!.change(check: recordTypeCheck)
            }
        }
    }
    
    func change(allField: LKFRecordTypeField?) {
        self.allField = allField
    }
    
    public func checksFor (errorCode: String) -> [LKFRecordTypeCheck]? {
        var checks : [LKFRecordTypeCheck]?
        
        if let allField, let c = allField.checksFor(errorCode: errorCode) {
            checks = c
        }
        
        for f in fields {
            if let c = f.checksFor(errorCode: errorCode) {
                if checks == nil {
                    checks = c
                }
                else {
                    checks!.append(contentsOf: c)
                }
            }
        }
        return checks
    }

}
