package dds.tools.scripts

import javax.swing.JOptionPane

import com.dvelop.d3.server.core.D3Interface

import groovy.sql.GroovyRowResult

def adminUser = "d3_service"
boolean noHooks = true

class Config{
    static def MODE = 2 // 0: Es werden nur die SQL-Statements in die Info-Log-Dateien ausgegeben
    // 1: Es werden alle Dokumente durchlaufen, es werden jedoch keine Updates ausgeführt
    // 2: Das Script aktualisiert die konfigurierten Dokumente
    static TOP_CLAUSE = "TOP 100"
    static def LOG_PATH = "C:\\TEMP"
    static List<Rule> rules = []
    static ok = 0
    static errors = 0


    static def init(D3Interface d3) {
        d3.log.info("Regelwerk wird erstellt")
        //rules.add(new Rule(d3, "DOKUMENTARKUERZEL", [new FieldTupel("Integer FELD_NR_QUELLE", "Integer FELD_NR_ZIEL", "Boolean TRUE: Es wird nur der Ganzzahl-Anteil übernommen. Schlägt die Konvertierung fehlt wird null übernommen. - DEFAULT = FALSE")]))
        rules.add(new Rule(d3, "DEINV", [new FieldTupel(83, 1), new FieldTupel(17, 62)]))
        rules.add(new Rule(d3, "DIERE", [new FieldTupel(55, 1), new FieldTupel(70, 2)]))
        rules.add(new Rule(d3, "AA002", [new FieldTupel(6, 60), new FieldTupel(1, 61)]))

        d3.log.info("Es wurden ${rules.size()} Regeln angelegt.")
        def ld = new File(LOG_PATH)
        if ( ! ld.exists()) {
            if (!ld.mkdirs()) {
                throw new Exception("Das Logverzeichnis '$LOG_PATH' konnte nicht angelegt werden")
            }
        }
    }
}

class Rule{
    def docType, ok, errors
    List<FieldTupel> mapping
    private String selectQuery
    private File logFileInfo
    private File logFileError
    private D3Interface d3

    Rule(D3Interface d3, String docType, FieldTupel fieldTupel) {
        this.d3 = d3
        this.docType = docType
        this.mapping = [fieldTupel]
        init()
    }

    Rule(D3Interface d3, String docType, List<FieldTupel> fieldTupelArray){
        this.d3 = d3
        this.docType = docType
        this.mapping = fieldTupelArray
        init()
    }

    def init() {
        ok = 0
        errors = 0
        logFileInfo = new File("${Config.LOG_PATH}\\${docType}_info.txt")
        logFileError = new File("${Config.LOG_PATH}\\${docType}_error.txt")
        selectQuery = """SELECT ${Config.TOP_CLAUSE} f.doku_id\r\n, ${mapping.collect{ FieldTupel ft -> ft.getSelectClause() }.join('\r\n, ') }
FROM firmen_spezifisch f
WHERE f.kue_dokuart = '${docType}' 
AND f.doku_id > ? 
AND (${mapping.collect{ FieldTupel ft -> ft.getWhereClause() }.join('\r\nOR ') }) 
ORDER BY f.doku_id"""
        logFileInfo << "${selectQuery}\r\n"
    }

    List<GroovyRowResult> selectDocuments(D3Interface d3, def lastId) {
        def params = [lastId]
        logInfo("Selektiere weitere Dokumente mit params=$params")
        d3.sql.executeAndGet(selectQuery, params)
    }

    void logInfo(msg) {
        d3.log.info(msg)
        logFileInfo << """${new Date().format("yyyy-dd-MM hh:mm:ss")};${(Config.MODE != 2) ? 'SIMULATION!;' : ''}$msg\r\n"""
    }

    void logError(def msg) {
        d3.log.error(msg)
        logFileError << """${new Date().format("yyyy-dd-MM hh:mm:ss")};$msg\r\n"""
    }

    String toString() {
        def mappingString = mapping.collect {
            it.toString()
        }.join(", ")
        "dokumentart: $docType, Mapping: $mappingString"
    }
}

class FieldTupel{
    def oldDbField, newDbField, toInteger

    FieldTupel(def oldDbField, def newDbField, def toInteger = false) {
        this.oldDbField = oldDbField
        this.newDbField = newDbField
        this.toInteger = toInteger

        if ( (newDbField >= 1 && newDbField <= 49) ) {
            println("Zielfeld $newDbField ist STRING")
        } else if ( newDbField >= 60  && newDbField <= 69 )  {
            println("Zielfeld $newDbField ist MULTI")
        } else {
            throw new Exception("DB Position $newDbField ist nicht erlaubt als Ziel!")
        }
        if ( oldDbField >= 60 && oldDbField <= 69 ) {
            throw new Exception("DB Position $oldDbField ist nicht erlaubt als Quelle!")
        }
    }

    private getConvertStr( def dbPos ) {
        if (dbPos >= 50 && dbPos <= 59) {
            "TRY_CONVERT(nvarchar, f.dok_dat_feld_${dbPos}, 104)"
        } else if (dbPos >= 70 && dbPos <= 79) {
            "TRY_CONVERT(nvarchar, f.dok_dat_feld_${dbPos})"
        } else {
            if (toInteger) {
                "CONVERT(nvarchar, TRY_CONVERT(int, f.dok_dat_feld_${dbPos}))"
            } else {
                "CONVERT(nvarchar, f.dok_dat_feld_${dbPos})"
            }
        }
    }

    def getWhereClause() {
        if ( newDbField < 60 || newDbField > 69 ) {
            "(f.dok_dat_feld_${oldDbField} IS NOT NULL AND (f.dok_dat_feld_${newDbField} IS NULL OR ${getConvertStr(oldDbField)} <> f.dok_dat_feld_${newDbField} ))".toString()
        } else {
            "(f.dok_dat_feld_${oldDbField} IS NOT NULL AND NOT EXISTS(SELECT top 1 * FROM firm_spez_mult_val m WHERE f.doku_id = m.doku_id and m.field_no = ${newDbField} AND value_char = ${getConvertStr(oldDbField)} ))".toString()
        }
    }

    def getSelectClause() {
        """${ (newDbField < 60 || newDbField > 69) ? getConvertStr(newDbField) : "'Werte von 60ger Feldern koennen nicht gelogt werden!'" } as dok_dat_feld_${newDbField}, ${getConvertStr(oldDbField)} as dok_dat_feld_${oldDbField}"""
    }

    String toString(){
        "[oldDbPos=$oldDbField, newDbPos=$newDbField, toInteger=$toInteger]"
    }
}

def printStatus(D3Interface d3, Integer c, Boolean running = true){
    d3.log.statusBar("${ (Config.MODE != 2) ? '(SIMULATON)' : '' }Verarbeite Regel ${c + 1}/${Config.rules.size()}: Ok: ${Config.rules[c].ok}, Fehler: Ok: ${Config.rules[c].errors} | Gesamkt Ok: ${Config.ok}, Fehler: ${Config.errors} ${running ? '...' : '-Script beendet'}")
}

def errors = 0
def updated = 0
D3Interface d3 = getProperty("d3")

try {
    d3.log.info("Script ${this.getClass().toString()} gestartet")
    d3.log.statusBar("Script ${this.getClass().toString()} gestartet")

    Config.init( d3 )

    d3.log.info("Es wurden ${Config.rules.size()} Regeln hinterlegt.")

    if (Config.MODE == 0) {
        d3.log.statusBar("Dialog ist geoeffnet!")
        JOptionPane.showMessageDialog(null, "Es wurden die SQL-Statements generiert und in die Info-Log Dateien geschrieben.\nMode=0")
        d3.log.statusBar("Script beendet.")
        return null
    }

    if (JOptionPane.OK_OPTION != JOptionPane.showConfirmDialog(null, "Es wurden ${Config.rules.size()} Regeln hinterlegt. Soll das Script ausgefuehrt werden?")) {
        d3.log.error("Script durch Benutzer abgebrochen!")
        d3.log.statusBar("Script durch Benutzer abgebrochen!")
        return 0
    }

    if (Config.rules.size() > 0) {
        Config.rules.eachWithIndex { Rule rule, def index ->
            rule.logInfo("START *****************************************************")
            rule.logInfo(rule.toString())
            def rows = rule.selectDocuments(d3, "0")
            while (rows != null && rows.size() > 0) {
                rule.logInfo("Anzahl ermittelter Dokumente: ${rows.size()}")
                rows.each{ r ->
                    try {
                        def doc = d3.archive.getDocument(r.doku_id)

                        rule.mapping.each { m ->
                            def newValue = r["dok_dat_feld_${m.oldDbField}"]
                            d3.log.info("""setField ${m.newDbField} to ${newValue}""")
                            if ( m.newDbField < 60 || m.newDbField > 69 ) {
                                doc.field[ m.newDbField ] = r["dok_dat_feld_${m.oldDbField}"]
                            } else {
                                doc.field[ m.newDbField ][1] = r["dok_dat_feld_${m.oldDbField}"]
                                for ( def j = 2; j <= d3.config.value("CUR_60ER_FIELD_NR").toInteger(); j++ ) {
                                    doc.field[ m.newDbField ][j] = null
                                }
                            }
                        }
                        if (Config.MODE == 2) {
                            doc.updateAttributes(adminUser, true)
                        }
                        Config.ok++
                        rule.ok++
                        rule.logInfo("Dokument aktualisiert $r")
                    } catch (Exception e) {
                        d3.log.error("$r -> ${e.message}")
                        rule.logError("${r.doku_id};${e.message}")
                        rule.errors++
                        Config.errors++
                    }
                    printStatus(d3, index)
                }

                rows = rule.selectDocuments(d3, rows.doku_id.last())
            }
            rule.logInfo("Keine (weiteren) Dokumente ermittelt")
            rule.logInfo("Zusammenfassung: Ok: ${rule.ok}, Fehler: ${rule.errors}")
            rule.logInfo("ENDE *****************************************************")
        }
    }
    printStatus(d3, Config.rules.size() - 1, false)
} catch (Exception e) {
    e.printStackTrace()
    d3.log.statusBar("Bei der Verarbeitung ist ein Fehler aufgetreten. Bitte kontrollieren Sie das d3 log. - Dialog geöffnet")
    JOptionPane.showMessageDialog(null, "Bei der Verarbeitung ist ein Fehler aufgetreten.\r\nBitte kontrollieren Sie das d3 log.")
    d3.log.statusBar("Bei der Verarbeitung ist ein Fehler aufgetreten. Bitte kontrollieren Sie das d3 log.")
}
d3.log.info("Script ${this.getClass().toString()} beendet")
//d3.log.statusBar("Script ${this.getClass().toString()} beendet")

return 0
