//
//  LKFIssueList.swift
//  lkfc
//
//  Created by Alexander Holzer on 06.06.22.
//  Copyright © 2022 Alexander Holzer. All rights reserved.
//

import Foundation
@_implementationOnly import LibLKF

public class LKFIssueList {
    
    public let context : LKFContext
    public let errorFlags : UInt32
    public var issues = [LKFIssue]()
    public let errorFields : [LKFErrorField]
    public var errorFieldColumnNames : [String]?
    
    public init (context: LKFContext, errorFields: [LKFErrorField]? = nil, errorFlags: UInt32 = 255) {
        self.context = context
        self.errorFlags = errorFlags
        self.errorFields = errorFields ?? LKFIssueList.defaultErrorFields
        load()
    }
    
    static let defaultErrorFields : [LKFErrorField] = [.code, .text, .feld_lang, .feldname, .aufid64, .abtfcent, .aufdat]
    static let systemFields : [LKFErrorField] = [.code, .caseindex]
    
    class func valuesFromLine (line: String) -> [String] {
        return line.components(separatedBy: ";").map { $0.trimmingCharacters(in: .whitespaces)}
    }
    
    func load () {
        var errorFieldIndexes = errorFields.map { $0.rawValue }
        
        errorFieldIndexes.append(contentsOf: LKFIssueList.systemFields.map { $0.rawValue })
        
        _ = errorFieldIndexes.withUnsafeBufferPointer { unsafe in
            LibLKF.lkf_setErrorFormat(context.ptr, 0, UInt32(errorFieldIndexes.count), unsafe.baseAddress)
        }
        let count = LibLKF.lkf_setErrorFilter(context.ptr!, errorFlags)
        let lineBuffer = UnsafeMutablePointer<CChar>.allocate(capacity:1024)
        
        LibLKF.lkf_getSatzartErrorHeadline(context.ptr!, 0, 1024, lineBuffer)
        let headline = String(cString:lineBuffer)
        errorFieldColumnNames = LKFIssueList.valuesFromLine(line: headline)
        
        let codeColumnIndex = errorFields.count
        let aufenthaltIndexColumnIndex = codeColumnIndex + 1
        
        for i in 0..<count {
            LibLKF.lkf_getSatzartError(context.ptr!, i, 1024, lineBuffer)
            let line = String(cString:lineBuffer)
            let parts = LKFIssueList.valuesFromLine(line: line)
            let code = (parts.count > codeColumnIndex) ? parts[codeColumnIndex] : ""
            let aufenthaltIndex = parts.count > aufenthaltIndexColumnIndex ? (Int(parts[aufenthaltIndexColumnIndex]) ?? nil) : nil
            issues.append(LKFIssue(index: i, code: code, aufenthaltIndex: aufenthaltIndex, values: parts))
        }
        lineBuffer.deallocate()
    }
    
    public convenience init (context:LKFContext, errorFields: [LKFErrorField]? = nil, error: Bool, warning: Bool, info: Bool, global: Bool, aufenthalt: Bool) {
        
        var errorFlags : UInt32 = 0
        var facility : UInt32 = 0
        
        if global {
            facility = 8 + 16 + 32 + 64
        }
        if aufenthalt {
            facility += 2 + 4
        }
        
        if error {
            if global {
                errorFlags += 1
            }
            errorFlags += facility
        }
        if warning {
            errorFlags += (1<<8) * facility
        }
        if info {
            errorFlags += (1<<20) * facility
        }
        
        self.init(context: context, errorFields: errorFields, errorFlags: errorFlags)
    }
}
