#include "readcfg.h"

#include <string.h>
#include <stdlib.h>
#include <errno.h>

#define COMMENT     ';'
#define MAXLEN  2048

static cstr error_message;   // Kann von decode gesetzt werden
                             // und wird dann als Fehlermeldung
                             // ausgegeben

static void scanKeywords(struct S_cfgLine line[], int *lineanz, int *maxlen) {
    //  Anzahl und maximale Laenge der Keywords bestimmen
    while (1) {
        cstr keyword    = line[*lineanz].keyword;
        int  keywordlen;

        if (!keyword) break;
        keywordlen = strlen(keyword);
        if (keywordlen>*maxlen) *maxlen = keywordlen;
        (*lineanz)++;
    }
}
static void cfgReadWarning(cstr fname, int lineno) {
    warningf("Error in line %i of '%s'", lineno, fname);
}
int readCfg(cstr fname, struct S_cfgLine line[]) {
    //  liest und dekodiert CFG-Datei
    FILE *in = fopen(fname, "r");
    int   ok = in!=NULL;

    if (!ok && errno==ENOENT) { // Datei nicht vorhanden
        FILE *out = fopen(fname, "w");

        if (out) {
            fprintf(out, ";\n; arb_treegen CFG-File '%s'\n;\n\n", fname);
            fclose(out);

            warningf("'%s' has been generated.", fname);

            in = fopen(fname, "r");
            ok = in!=NULL;
        }
    }

    if (ok) {
        char  linebuf[MAXLEN];
        int   readLines        = 0,                        // Anzahl gelesener Zeilen
              keywords         = 0,                        // Anzahl keywords
              maxKeywordlen    = 0,                        // Laenge des laengsten keywords
              lineno           = 0,                        // fortlaufende Zeilennummer
             *wordRead,                                    // welche Worte wurden in welcher Zeile gelesen
              x;

        scanKeywords(line, &keywords, &maxKeywordlen);

        wordRead = (int*)malloc(keywords*sizeof(int));
        for (x = 0; x<keywords; x++) wordRead[x] = 0;

        // ---------------------------------
        //      CFG lesen und decodieren

        while (1) {
            str firstWord;

            if (!fgets(linebuf, MAXLEN, in)) break;
            lineno++;

            firstWord = strtok(linebuf, " \n");

            if (firstWord && firstWord[0]!=COMMENT && firstWord[0]!=0) {
                int search;

                for (search = 0; search<keywords; search++) {
                    if (strcmp(line[search].keyword, firstWord)==0) {
                        str restDerZeile = strtok(NULL, "\n");
                        int decoded;

                        error_message = NULL;
                        decoded       = line[search].decode(restDerZeile, line[search].varPointer);

                        if (!decoded) {
                            cfgReadWarning(fname, lineno);
                            if (error_message) warning(error_message);
                            else               warningf("Can't interpret '%s'", line[search].keyword);
                            ok = 0;
                        }
                        else {
                            if (wordRead[search]) { // schonmal gelesen?
                                if (decoded!=2) { // mehrfache Verwendung erlaubt?
                                    cfgReadWarning(fname, lineno);
                                    warningf("Keyword '%s' duplicated (already specified in line %i)", firstWord, wordRead[search]);
                                    ok = 0;
                                }
                            }
                            else { // nein, dann merken!
                                wordRead[search] = lineno;
                                readLines++;
                            }
                        }

                        break;
                    }
                }

                if (search==keywords) { // keyword nicht gefunden!
                    cfgReadWarning(fname, lineno);
                    warningf("Unknown Keyword '%s'", firstWord);
                    ok = 0;
                }
            }
        }

        fclose(in);

        // ---------------------------------------------------
        //      Waren alle keywords im CFG-File vorhanden?

        if (ok && readLines<keywords) { // nein :-(
            FILE *out = fopen(fname, "a");

            if (out) {
                for (x = 0; x<keywords; x++) {
                    if (!wordRead[x]) {
                        fprintf(out, ";%s\n"
                                     "\n"
                                     "%-*s %s\n"
                                     "\n",
                                     line[x].description,
                                     maxKeywordlen,
                                     line[x].keyword,
                                     line[x].defaultVal);
                    }
                }

                fclose(out);
                warningf("Missing keywords appended to '%s'.", fname);
            }

            ok = 0;
        }

        free(wordRead);
    }

    return ok;
}
void setCfgError(cstr message) {
    error_message = message;
}


