/****************************************************************************
** Leistungsorientierte Krankenanstaltenfinanzierung (LKF)                 **
** Scoring-C-Sourcen V2026.1                                               **
** (C) 2026 BMASGPK                                                        **
*****************************************************************************
** context5.c - Routinen zur Verwendung des Scoring-Contexts               **
**                                                                         **
**		 Alex.Holzer@chello.at                                             **
**       Bernhard.Pesec@dothealth.at                                       **
***************************************************************************/

#include "lkfint5.h"
#include "lkfstru5.h"
#include <ctype.h>
#include <time.h>

/***************************************************************************************
** lkf_set_compatibilitymode (V8.1) - setzt den Compatibility-Modus:                  **
**     0 = neu                                                                        **
**     1 = alte Errorcodes                                                            **
**     2 = alte Errorcodes + alte Errortexte                                          **
***************************************************************************************/

_SCORING_EXPORT void lkf_set_compatibilitymode (LKF_CONTEXT *pContext, unsigned int compatibility)
{
}

static void lkf_context_setPatIdPos (LKF_CONTEXT *pContext) {
    
    const static char longIDName[] = "AUFID";
    
    const static SATZART_FELD m01_pos =     {0, TYP_ALPHA,   80, LKF_AUFENTHALT_LONGID_LEN, 0, 0, longIDName},
                              m02_pos_lf  = {0, TYP_ALPHA,   96, LKF_AUFENTHALT_LONGID_LEN, 0, 0, longIDName},
                              m02_pos_nlf = {0, TYP_ALPHA,   74, LKF_AUFENTHALT_LONGID_LEN, 0, 0, longIDName},
                              m03_pos =     {0, TYP_ALPHA,   28, LKF_AUFENTHALT_LONGID_LEN, 0, 0, longIDName},
                              m04_pos =     {0, TYP_ALPHA,   55, LKF_AUFENTHALT_LONGID_LEN, 0, 0, longIDName},
                              m05_pos =     {0, TYP_ALPHA,   23, LKF_AUFENTHALT_LONGID_LEN, 0, 0, longIDName},
                              m06_pos =     {0, TYP_ALPHA,  102, LKF_AUFENTHALT_LONGID_LEN, 0, 0, longIDName},
                              m07_pos =     {0, TYP_ALPHA,  233, LKF_AUFENTHALT_LONGID_LEN, 0, 0, longIDName},
                              m08_pos =     {0, TYP_ALPHA, 1219, LKF_AUFENTHALT_LONGID_LEN, 0, 0, longIDName},
                              i11_pos =     {0, TYP_ALPHA,  116, LKF_AUFENTHALT_LONGID_LEN, 0, 0, longIDName},
                              i12_pos =     {0, TYP_ALPHA,   59, LKF_AUFENTHALT_LONGID_LEN, 0, 0, longIDName};
    
    const static SATZART_FELD *patidPos2015_lf[]  = {0, &m01_pos, &m02_pos_lf, &m03_pos, &m04_pos,
                                    &m05_pos, &m06_pos, &m07_pos, &m08_pos, 0, 0,
                                    &i11_pos, &i12_pos};
    const static SATZART_FELD *patidPos2015_nlf[] = {0, &m01_pos, &m02_pos_nlf, &m03_pos, &m04_pos,
                                    &m05_pos, &m06_pos, &m07_pos, &m08_pos, 0, 0,
                                    &i11_pos, &i12_pos};
    
    if (!pContext->isBM)
        pContext->patidPos = 0;
    else if (pContext->flags & LKFCONTEXT_NICHTFONDSKA) {
        pContext->patidPos = patidPos2015_nlf;
    }
    else {
        pContext->patidPos = patidPos2015_lf;
    }
}

static void initContextFields (LKF_CONTEXT *pContext, unsigned int modelljahr);

_SCORING_EXPORT unsigned int lkf_set_statjahr (LKF_CONTEXT *pContext, unsigned int abrechjahr, const char *input_path, char *error) {
    unsigned int ret;
    char input[1024];
    
    if (abrechjahr  > LKF_YEAR_LATEST) {
        pContext->modelljahr = LKF_YEAR_LATEST;
    }
    else if (abrechjahr >= 2020) {
        pContext->modelljahr = abrechjahr;
    }
    else if (abrechjahr == 2019) {
        pContext->modelljahr = 2019;
    }
    else {
        pContext->modelljahr = 2018;
    }
    if (input_path) {
        build_path (input, input_path, abrechjahr);
    }
    else {
        *input = 0;
    }
    pContext->pStamm2001 = allocStamm2001 (pContext, input, pContext->modelljahr);
    pContext->pStamm2001->pScoringContext = pContext;
	pContext->pStamm2001->nNPDisabled = 0;
	pContext->pStamm2001->nOSGDisabled = 0;
    ret = stamm_read_statonly(pContext->pStamm2001, input, error, pContext->modelljahr);
    if (!ret) {
        if (error) {
            *error = 0;
        }
        initContextFields(pContext, pContext->modelljahr);
    }
    pContext->noStamm = 1;
    return ret;
}

/*************************************************************************
** lkf_set_modelljahr: Setzt/Ändert das Jahr, nach dem abgerechnet wird **
*************************************************************************/

_SCORING_EXPORT void lkf_set_modelljahr_stamm (LKF_CONTEXT *pContext, LKF_METADATA *pStamm) {
    if (pContext->privateStamm == 1 && pContext->pStamm2001) {
        freeStamm2001(pContext->pStamm2001);
    }
    pContext->stammAddLineFunc = 0;
    pContext->stammFilePathFunc = 0;
    pContext->modelljahr = pStamm->modelYear;
    pContext->pStamm2001 = pStamm->pStamm;
    pContext->privateStamm = 2;
    initContextFields(pContext, pContext->modelljahr);
}

_SCORING_EXPORT unsigned int lkf_set_modelljahr (LKF_CONTEXT *pContext, unsigned int modelljahr, const char *input_path, char *error) {
	char sInternalError[2048];
	pContext->modelljahr = (int) modelljahr;

	sInternalError[0] = 0;

    if (pContext->privateStamm == 1) {
        if (pContext->pStamm2001) {
            freeStamm2001(pContext->pStamm2001);
        }
    }
    else {
        pContext->stammAddLineFunc = 0;
        pContext->stammFilePathFunc = 0;
    }
    
	switch (modelljahr)
	{
#ifdef SUPPORT_PRE2017
		case 2009:
			pContext->pStamm2001 = getStamm2009 (pContext, input_path, sInternalError);
			break;
		case 2010:
			pContext->pStamm2001 = getStamm2010 (pContext, input_path, sInternalError);
			break;
		case 2011:
			pContext->pStamm2001 = getStamm2011 (pContext, input_path, sInternalError);
			break;
		case 2012:
			pContext->pStamm2001 = getStamm2012 (pContext, input_path, sInternalError);
			break;
		case 2013:
			pContext->pStamm2001 = getStamm2013 (pContext, input_path, sInternalError);
			break;
		case 2014:
			pContext->pStamm2001 = getStamm2014 (pContext, input_path, sInternalError);
			break;
        case 2015:
            pContext->pStamm2001 = getStamm2015 (pContext, input_path, sInternalError);
            break;
        case 2016:
            pContext->pStamm2001 = getStamm2016 (pContext, input_path, sInternalError);
            break;
#endif
        case 2017:
            pContext->pStamm2001 = getStamm2017 (pContext, input_path, sInternalError);
            break;
        case 2018:
            pContext->pStamm2001 = getStamm2018 (pContext, input_path, sInternalError);
            break;
        case 2019:
            pContext->pStamm2001 = getStamm2019 (pContext, input_path, sInternalError);
            break;
        case 2020:
            pContext->pStamm2001 = getStamm2020 (pContext, input_path, sInternalError);
            break;
        case 2021:
            pContext->pStamm2001 = getStamm2021 (pContext, input_path, sInternalError);
            break;
        case 2022:
            pContext->pStamm2001 = getStamm2022 (pContext, input_path, sInternalError);
            break;
        case 2023:
            pContext->pStamm2001 = getStamm2023 (pContext, input_path, sInternalError);
            break;
        case 2024:
            pContext->pStamm2001 = getStamm2024 (pContext, input_path, sInternalError);
            break;
        case 2025:
            pContext->pStamm2001 = getStamm2025 (pContext, input_path, sInternalError);
            break;
        case 2026:
            pContext->pStamm2001 = getStamm2026 (pContext, input_path, sInternalError);
            break;
		default:
			sprintf (error, "Ungueltiges Jahr - das LKF-Abrechnungsmodell %d wird nicht unterstuetzt.", modelljahr);
			return 2;

	}

	if (!pContext->pStamm2001) {
		if (sInternalError[0]) sprintf (error, "Die Stammdaten fuer das Jahr %d konnten nicht ermittelt werden (%s)!", modelljahr, sInternalError);
		else sprintf (error, "Die Stammdaten fuer das Jahr %d konnten nicht ermittelt werden!", modelljahr); 
		return 4;
	}
    pContext->privateStamm = 0;
    if (error) error[0] = 0;
    initContextFields(pContext, pContext->modelljahr);
    return 0;
    
}

static void initContextFields (LKF_CONTEXT *pContext, unsigned int modelljahr)
{
    if (pContext->flags & LKFCONTEXT_MODUS_BMG) {
        pContext->isBM = modelljahr >= 2014 ? 1 : 0;
        if (pContext->flags & 2) pContext->isBM = 2;
        if (pContext->isBM) lkf_context_setPatIdPos (pContext);
    } else {
        pContext->isBM = 0;
    }
    if (pContext->flags & LKFCONTEXT_NICHTFONDSKA) {
        pContext->m02_intlen = LKF_AUFENTHALT_ABT_INTSATZ_LEN_NICHTFONDS;
    }
    else {
        pContext->m02_intlen = LKF_AUFENTHALT_ABT_INTSATZ_LEN_FONDS;
    }
    
    pContext->standortInfo = 0;
    if (modelljahr <= 2014 && (pContext->flags & LKFCONTEXT_STANDORT)) pContext->standortInfo = 1; /* V19.1: auch Modelle < 2014 */
    else if (modelljahr >= 2015 && !(pContext->flags & LKFCONTEXT_STANDORT)) pContext->standortInfo = 1;
	
    
    if (modelljahr >= 2017) {
        pContext->pSatzartDefs = lkf_Satzart_getDefinition(modelljahr);
        
        if (pContext->pSatzartDefs && pContext->pSatzartDefs->ppX) {
            const SATZART_INFO **ppX = pContext->pSatzartDefs->ppX;
            pContext->pX01 = ppX[1];
            pContext->pX02 = ppX[2];
            pContext->pX03 = ppX[3];
            pContext->pX04 = ppX[4];
            pContext->pX05 = ppX[5];
            pContext->pX06 = ppX[6];
            pContext->pX07 = ppX[7];
        }
    }

    
#ifdef SUPPORT_PRE2017
    if (pContext->flags & LKFCONTEXT_UTF8) {
        pContext->utf8_mode = (pContext->modelljahr >= 2017) ? 0 : 1;
    } else {
        pContext->utf8_mode = (pContext->modelljahr >= 2017) ? 1 : 0;
    }
#else
    pContext->utf8_mode = (pContext->flags & LKFCONTEXT_UTF8) ? 0 : 1;
#endif
    pContext->model2017errors = (pContext->modelljahr >= 2017 && !(pContext->flags & LKFCONTEXT_IGNORE_2017ERRORS));
    if (pContext->spezMels)
    {
        LKF_FREE(pContext, "initContextFields", pContext->spezMels);
        pContext->spezMels = 0;
        pContext->spezMelCount = 0;
    }
    if (pContext->otherKASpezMel) {
        LKF_FREE(pContext, "initContextFields", pContext->otherKASpezMel);
        pContext->otherspezalloc = 0;
        pContext->otherspezcount = 0;
        pContext->otherKASpezMel = 0;
    }

}

/**********************************************************************
** lkf_alloc_context: Legt einen neuen LKF-CONTEXT an.               **
**********************************************************************/

_SCORING_EXPORT LKF_CONTEXT *lkf_alloc_context (unsigned int modelljahr, const char *input_path, char *error)
{
	LKF_CONTEXT *pContext;

	if ((modelljahr < 2009 || modelljahr > 2026) && modelljahr != 0) {
        if (error) {
            sprintf (error, "Ungueltiges Jahr - das LKF-Abrechnungsmodell %d wird nicht unterstuetzt.", modelljahr);
        }
		return 0;
	}

    pContext = (LKF_CONTEXT*)LKF_CALLOC(0, "lkf_alloc_context", 1, sizeof(LKF_CONTEXT));
    if (!pContext) {
        if (error) {
            strcpy (error, "OutOfMemory: lkf_alloc_context");
        }
        return 0;
    }
	pContext->modelljahr = (int) modelljahr;
	pContext->patient_alloc = LKF_AUFENTHALT_EXTEND_PAT;
	pContext->ppAufenthalt = (LKF_AUFENTHALT **) LKF_CALLOC (0, "lkf_alloc_context.aufenthalt", pContext->patient_alloc, sizeof (LKF_AUFENTHALT *));
    if (!pContext->ppAufenthalt) {
        LKF_FREE(0, "lkf_alloc_context", pContext);
        if (error) {
            strcpy (error, "OutOfMemory: lkf_alloc_context.aufenthalt");
        }
        return 0;
    }
	pContext->ka_alloc = 1;
	pContext->ka = (STAT_KA *) LKF_CALLOC (0, "lkf_alloc_context.ka", pContext->ka_alloc, sizeof (STAT_KA));
    if (!pContext->ka) {
        LKF_FREE(0, "lkf_alloc_context", pContext->ppAufenthalt);
        LKF_FREE(0, "lkf_alloc_context", pContext);
        if (error) {
            strcpy (error, "OutOfMemory: lkf_alloc_context.ka");
        }
        return 0;
    }
	lkf_init_context_counters (pContext);

	if (modelljahr && input_path) {
        if (lkf_set_modelljahr (pContext, modelljahr, input_path, error)) {
            return 0;
        }
	}
	else pContext->pStamm2001 = 0;

	LKFTRACE_INIT(pContext); /* V10.2 */
	return pContext;
}

/***********************************************************************
** lkf_free_context: Gibt den LKF-CONTEXT frei.                       **
***********************************************************************/ 

_SCORING_EXPORT void lkf_free_context (LKF_CONTEXT *pContext)
{	
	unsigned int i; 
	lkf_reset_aufenthalte (pContext);

	if (pContext->custom_field_anz) LKF_FREE (pContext, "lkf_free_context", pContext->custom_fields);

	
	for (i = 0; i < LKF_FAC_ALLOC; i++) {
		if (pContext->pErrorFormats[i]) {
			if (pContext->pErrorFormats[i]->fields) LKF_FREE (pContext, "lkf_free_context", pContext->pErrorFormats[i]->fields);
			LKF_FREE (pContext, 0, pContext->pErrorFormats[i]);
			pContext->pErrorFormats[i] = 0;
		}
	}

	if (pContext->spezMels)
	{
		LKF_FREE(pContext, "lkf_free_context", pContext->spezMels);
		pContext->spezMels = 0;
		pContext->spezMelCount = 0;
	}
    
    if (pContext->pSatzartDefs) {
        lkf_Satzart_getDefinition(0);
    }
    
    if (pContext->pExpLineBuffer) {
        lkf_free_expandedLines(pContext->pExpLineBuffer);
        pContext->pExpLineBuffer = 0;
    }
    
    if (pContext->otherKASpezMel) {
        LKF_FREE(pContext, "lkf_free_context", pContext->otherKASpezMel);
        pContext->otherspezalloc = 0;
        pContext->otherspezcount = 0;
        pContext->otherKASpezMel = 0;
    }
    
    if (pContext->abtFCStat) {
        LKF_FREE(pContext, "lkf_free_context", pContext->abtFCStat);
    }
    
    if (pContext->pLKFStat)
    { /* V21.0 */
        lkf_free_context_lkfstat(pContext);
    }

    if (pContext->privateStamm == 1 && pContext->pStamm2001) {
        freeStamm2001(pContext->pStamm2001);
    }
    
 	LKF_FREE (pContext, "lkf_free_context", pContext);
}

#ifdef SUPPORT_PRE2017
static const char *spezMels2012[] =  {"LH020", "AJ140", "AK010", "DB020", "LH010", "LH021", "DB021", "XN020", "XN030", "XN040", "XN050", "XN060", "XN070"};
static const char *spezMelKZ2012[] = {"01",    "02",    "03",    "04",    "05",    "06",    "07",    "X1",    "X2",    "X3",    "X4",    "X5",    "X6"};

/* V17.0 */
static const char *spezMels2013[] =  {"LH020", "AJ140", "AK010", "DB020", "LH010", "LH021", "DB021", "XN020", "XN030", "XN040", "XN050", "XN060", "XN070", "XN080", "XN090"};
static const char *spezMelKZ2013[] = {"01",    "02",    "03",    "04",    "05",    "06",    "07",    "X1",    "X2",    "X3",    "X4",    "X5",    "X6",    "X7",    "X8"};
#endif

/* V20.0 */
static const char *spezMels2016[] =  {"LH020", "AJ140", "AK010", "DB020", "LH010", "LH021", "DB025", "DB026", "XN020", "XN030", "XN040", "XN050", "XN060", "XN070", "XN080", "XN090", "XN055", "XN100", "XN110", "XN120"};
static const char *spezMelKZ2016[] = {"01",    "02",    "03",    "04",    "05",    "06",    "08",    "09",    "X1",    "X2",    "X3",    "X4",    "X5",    "X6",    "X7",    "X8",    "X9",    "XA",    "XB",    "XC"};

/* V2019.0 */
static const char *spezMels2019[] =  {"LH020", "AJ140", "AK010", "DB020", "LH010", "LH021", "DB025", "DB026",
                                      "XN020", "XN030", "XN050", "XN060", "XN080", "XN090", "XN055", "XN100", "XN110", "XN120",
                                      "DE112", "EA050", "GF210", "GF220", "ZZ710"};
static const char *spezMelKZ2019[] = {"01",    "02",    "03",    "04",    "05",    "06",    "08",    "09",
                                      "X1",    "X2",    "X4",    "X5",    "X7",    "X8",    "X9",    "XA",    "XB",    "XC",
                                      "XD",    "XE",    "XF",    "XG",    "Z1"};

static const char *spezMels2020[] =  {"LH020", "?????", "AK010", "DB020", "LH010", "LH021", "DB025", "DB026",
    /*"XN020",*/ "XN030", "XN050", "XN060", "XN080", "XN090", "XN055", "XN100", "XN110", "XN120",
    "DE112", "EA050", "GF210", "GF220", "ZZ710", "ZZ720", "FZ120"};
static const char *spezMelKZ2020[] = {"01",    "02",    "03",    "04",    "05",    "06",    "08",    "09",
    /* "X1", */    "X2",    "X4",    "X5",    "X7",    "X8",    "X9",    "XA",    "XB",    "XC",
    "XD",    "XE",    "XF",    "XG",    "Z1",    "Z2",    "XH"};

static const char *spezMels2021[] =  {"LH020", "?????", "AK010", "DB020", "LH010", "LH021", "DB025", "DB026",
    /*"XN020",*/ "XN030", "XN050", "XN060", "XN080", "XN090", "XN055", "XN100", "XN110", "XN120",
    "DE112", "EA050", "GF210", "GF220", "ZZ710", "ZZ720", "FZ120",
    "XN051", "XN130", "XN140"
};
static const char *spezMelKZ2021[] = {"01",    "02",    "03",    "04",    "05",    "06",    "08",    "09",
    /* "X1", */    "X2",    "X4",    "X5",    "X7",    "X8",    "X9",    "XA",    "XB",    "XC",
    "XD",    "XE",    "XF",    "XG",    "Z1",    "Z2",    "XH",
    "XI",    "XJ",    "XK"
};

static const char *spezMels2022[] =  {"LH020", "?????", "AK010", "DB020", "LH010", "LH021", "DB025", "DB026",
    /*"XN020",*/ "XN030", "XN050", "XN060", "XN080", "XN090", "XN055", "XN100", "XN110", "XN120",
    "DE112", "EA050", "GF210", "GF220", "ZZ710", "ZZ720", "FZ120",
    "XN051", "XN130", "XN140", "AA011", "AN010", "AN011", "XN160", "XN170", "?????", "ZZ721", "ZZ722", "ZZ723"
};

static const char *spezMelKZ2022[] = {"01",    "02",    "03",    "04",    "05",    "06",    "08",    "09",
    /* "X1", */    "X2",    "X4",    "X5",    "X7",    "X8",    "X9",    "XA",    "XB",    "XC",
    "XD",    "XE",    "XF",    "XG",    "Z1",    "Z2",    "XH",
    "XI",    "XJ",    "XK",    "XL",    "XM",    "XN",    "XO",    "XP",    "Z2",    "Z3",    "Z4",    "Z5"
};

static const char *spezMels2023[] =  {"LH020", "?????", "AK010", "DB020", "LH010", "LH021", "DB025", "DB026",
    /*"XN020",*/ "XN030", "XN050", "XN060", "XN080", "XN090", "XN055", "XN100", "XN110", "XN120",
    "DE112", "EA050", "GF210", "GF220", "ZZ710", "ZZ720", "FZ120",
    "XN051", "XN130", "XN140", "AA011", "AN010", "AN011", "XN160", "XN170", "?????", "ZZ721", "ZZ722", "ZZ723",
    "XN190", "XN200", "XN210", "XN220", "XN230", "DD105", "FZ123", "FZ124"
};

static const char *spezMelKZ2023[] = {"01",    "02",    "03",    "04",    "05",    "06",    "08",    "09",
    /* "X1", */    "X2",    "X4",    "X5",    "X7",    "X8",    "X9",    "XA",    "XB",    "XC",
    "XD",    "XE",    "XF",    "XG",    "Z1",    "Z2",    "XH",
    "XI",    "XJ",    "XK",    "XL",    "XM",    "XN",    "XO",    "XP",    "Z2",    "Z3",    "Z4",    "Z5",
    "XT", "XU", "XV", "XW", "XX", "XQ", "XR", "XS"
};

static const char *spezMels2024[] =  {"LH020", "?????", "AK010", "DB020", "LH010", "LH021", "DB025", "DB026",
    /*"XN020",*/ "XN030", "XN050", "XN060", "XN080", "XN090", "XN055", "XN100", "XN110", "XN120",
    "DE112", "EA050", "GF210", "GF220", "ZZ710", "ZZ720", "FZ120",
    "XN051", "XN130", "XN140", "AA011", "AN010", "AN011", /* "XN160", */ "XN170", "?????", "ZZ721", "ZZ722", "ZZ723",
    "XN190", "XN200", "XN210", "XN220", "XN230", "DD105", "FZ123", "FZ124", "AA180"
};

static const char *spezMelKZ2024[] = {"01",    "02",    "03",    "04",    "05",    "06",    "08",    "09",
    /* "X1", */    "X2",    "X4",    "X5",    "X7",    "X8",    "X9",    "XA",    "XB",    "XC",
    "XD",    "XE",    "XF",    "XG",    "Z1",    "Z2",    "XH",
    "XI",    "XJ",    "XK",    "XL",    "XM",    "XN",  /*  "XO", */   "XP",    "Z2",    "Z3",    "Z4",    "Z5",
    "XT", "XU", "XV", "XW", "XX", "XQ", "XR", "XS", "XY"
};

static const char *spezMels2025[] =  {"LH020", "?????", "AK010", "DB020", "LH010", "LH021", "DB025", "DB026",
    /*"XN020",*/ "XN030", "XN050", "XN060", "XN080", "XN090", "XN055", "XN100", "XN110", "XN120"
    "DE112", "EA050", "GF210", "GF220", "ZZ710", "ZZ720", "FZ120",
    "XN051", "XN130", "XN140", "AA011", "AN010", "AN011", /* "XN160", */ "XN170", "?????", "ZZ721", "ZZ722", "ZZ723",
    "XN190", "XN200", "XN210", "XN220", "XN230", "DD105", "FZ123", "FZ124", "AA180"
};

static const char *spezMelKZ2025[] = {"01",    "02",    "03",    "04",    "05",    "06",    "08",    "09",
    /* "X1", */    "X2",    "X4",    "X5",    "X7",    "X8",    "X9",    "XA",    "XB",    "XC"
    "XD",    "XE",    "XF",    "XG",    "Z1",    "Z2",    "XH",
    "XI",    "XJ",    "XK",    "XL",    "XM",    "XN",  /*  "XO", */   "XP",    "Z2",    "Z3",    "Z4",    "Z5",
    "XT", "XU", "XV", "XW", "XX", "XQ", "XR", "XS", "XY"
};

static const char *spezMels2026[] =  {"LH020", "?????", "AK010", "DB020", "LH010", "LH021", "DB025", "DB026",
    /*"XN020",*/ "XN030", "XN050", "XN060", "XN080", "XN090", "XN055", "XN100", "XN110", "XN120"
    "DE112", "EA050", "GF210", "GF220", "ZZ710", "ZZ720", "FZ120",
    "XN051", "XN130", "XN140", "AA011", "AN010", "AN011", /* "XN160", */ "XN170", "?????", "ZZ721", "ZZ722", "ZZ723",
    "XN190", "XN200", "XN210", "XN220", "XN230", "DD105", "FZ123", "FZ124", "AA180", "XN056", "XN057"
};

static const char *spezMelKZ2026[] = {"01",    "02",    "03",    "04",    "05",    "06",    "08",    "09",
    /* "X1", */    "X2",    "X4",    "X5",    "X7",    "X8",    "X9",    "XA",    "XB",    "XC"
    "XD",    "XE",    "XF",    "XG",    "Z1",    "Z2",    "XH",
    "XI",    "XJ",    "XK",    "XL",    "XM",    "XN",  /*  "XO", */   "XP",    "Z2",    "Z3",    "Z4",    "Z5",
    "XT", "XU", "XV", "XW", "XX", "XQ", "XR", "XS", "XY", "XZ", "Y1"
};




static int sort_context_spezmels (const void *m1, const void *m2)
{
	return memcmp ( ((const LKF_CONTEXT_SPEZMEL *)m1)->mel, ((const LKF_CONTEXT_SPEZMEL *)m2)->mel, 5);
}

static int sort_context_otherspezmels (const void *m1, const void *m2)
{
	int cmp;
    const LKF_CONTEXT_OTHERKA_SPEZMEL *s1, *s2;
    s1 = (const LKF_CONTEXT_OTHERKA_SPEZMEL *)m1;
    s2 = (const LKF_CONTEXT_OTHERKA_SPEZMEL *)m2;
    
    cmp =  memcmp(s1->ka, s2->ka, 4);
    if (cmp != 0)
        return cmp;
    
    if (s1->spezmelindex > s2->spezmelindex)
        return 1;
    else if (s1->spezmelindex < s2->spezmelindex)
        return -1;
    else
        return 0;
}


static int search_context_spezmels (const void *m, const void *c)
{
	return memcmp (m, ((const LKF_CONTEXT_SPEZMEL *)c)->mel, 5);
}

extern const LKF_SATZART_ERRORDEF LKFErrorSPEZAbt2024;

static void reportFATTError (LKF_CONTEXT *pContext, const char *kanr, const char bereich, const char *abtfc) {
    const SATZART_INFO *l01S = lkf_GetSatzartL01Internal (pContext);
    const SATZART_FELD *abt = l01S ? l01S->ppRef[GEN_ABTFC] : 0;
    char infobuf[20];
    if (bereich == 'M') {
        sprintf (infobuf, "%4.4s: M-%2.2s", kanr, abtfc);
    }
    else {
        sprintf (infobuf, "%4.4s: %c-%8.8s", kanr, bereich, abtfc);
    }
    Satzart_ReportErrorExp(pContext, pContext->pCheckContext, 0, l01S, abt, &LKFErrorSPEZAbt2024, infobuf);

}

static void lkf_initSpezMels (LKF_CONTEXT *pContext)
{ /* V16.0 */
    int modelljahr;
	const char *spezList;
	unsigned int spezListCount;
	unsigned int j, i, spezMelCount;
	const char **spezMels, **spezMelKz;
	spezList = (const char *) pContext->spez_list;
	if (spezList)
		spezListCount = pContext->spez_gesamt;
	else
	{
		spezList = (const char *) pContext->pStamm2001->spez_list;
		spezListCount = pContext->pStamm2001->spez_gesamt;
	}
	
    modelljahr = pContext->modelljahr;
    
    switch (modelljahr) {
        case 2026:
            spezMelCount = sizeof (spezMels2026) / sizeof (const char *);
            spezMels = spezMels2026;
            spezMelKz = spezMelKZ2026;
            break;
        case 2025:
            spezMelCount = sizeof (spezMels2025) / sizeof (const char *);
            spezMels = spezMels2025;
            spezMelKz = spezMelKZ2025;
            break;
        case 2024:
            spezMelCount = sizeof (spezMels2024) / sizeof (const char *);
            spezMels = spezMels2024;
            spezMelKz = spezMelKZ2024;
            break;
        case 2023:
            spezMelCount = sizeof (spezMels2023) / sizeof (const char *);
            spezMels = spezMels2023;
            spezMelKz = spezMelKZ2023;
            break;
        case 2022:
            spezMelCount = sizeof (spezMels2022) / sizeof (const char *);
            spezMels = spezMels2022;
            spezMelKz = spezMelKZ2022;
            break;
        case 2021:
            spezMelCount = sizeof (spezMels2021) / sizeof (const char *);
            spezMels = spezMels2021;
            spezMelKz = spezMelKZ2021;
            break;
        case 2020:
            spezMelCount = sizeof (spezMels2020) / sizeof (const char *);
            spezMels = spezMels2020;
            spezMelKz = spezMelKZ2020;
            break;
        case 2019:
            spezMelCount = sizeof (spezMels2019) / sizeof (const char *);
            spezMels = spezMels2019;
            spezMelKz = spezMelKZ2019;
            break;
#ifdef SUPPORT_PRE2017
        case 2017:
        case 2018:
        case 2016:
            spezMelCount = sizeof (spezMels2016) / sizeof (const char *);
            spezMels = spezMels2016;
            spezMelKz = spezMelKZ2016;
        case 2013:
        case 2014:
        case 2015:
            spezMelCount = sizeof (spezMels2013) / sizeof (const char *);
            spezMels = spezMels2013;
            spezMelKz = spezMelKZ2013;
            break;
        default:
            spezMelCount = sizeof (spezMels2012) / sizeof (const char *);
            spezMels = spezMels2012;
            spezMelKz = spezMelKZ2012;
            break;
#else
        default:
            spezMelCount = sizeof (spezMels2016) / sizeof (const char *);
            spezMels = spezMels2016;
            spezMelKz = spezMelKZ2016;
            break;

#endif
        
    }
    
	pContext->spezMelCount = spezMelCount;
	pContext->spezMels = (LKF_CONTEXT_SPEZMEL *) LKF_CALLOC (pContext, "lkf_initSpezMels", spezMelCount, sizeof (LKF_CONTEXT_SPEZMEL));
    if (!pContext->spezMels) {
        pContext->spezMelCount = 0;
        return;
    }

	for (i = 0; i < spezMelCount; i++)
	{
        LKF_CONTEXT_SPEZMEL *pSpezMel = pContext->spezMels + i;
        pSpezMel->mel = spezMels[i];
        pSpezMel->melkz = spezMelKz[i];
		pSpezMel->ok = 0;
	}
    qsort (pContext->spezMels, spezMelCount, sizeof (LKF_CONTEXT_SPEZMEL), sort_context_spezmels);

	for (i = 0; i < spezListCount; i++)
	{
        if (spezList[0] == 'M') {
            for (j = 0; j < spezMelCount; j++)
            {
                if (!memcmp (pContext->spezMels[j].melkz, spezList + 27, 2))
                {
                    if (!memcmp (spezList + 5, pContext->KANR, 4))
                    {
                        if (pContext->spezMels[j].ok && modelljahr >= 2024) {
                            reportFATTError(pContext, spezList + 5, 'M', spezList + 27);
                        }
                        else {
                            pContext->spezMels[j].ok = 1;
                        }
                    }
                    else if (!IsBlank(spezList + 5, 4)) {
                        LKF_CONTEXT_OTHERKA_SPEZMEL *pOtherKASpezMel;
                        if (pContext->otherspezalloc == pContext->otherspezcount) {
                            LKF_CONTEXT_OTHERKA_SPEZMEL *pOld = pContext->otherKASpezMel;
                            pContext->otherKASpezMel = LKF_CALLOC(pContext, "lkf_initSpezMels", sizeof(LKF_CONTEXT_OTHERKA_SPEZMEL), pContext->otherspezalloc += 10);
                            if (!pContext->otherKASpezMel) {
                                LKF_FREE (pContext, "lkf_initSpezMels", pOld);
                                return;
                            }
                            if (pOld) {
                                memcpy (pContext->otherKASpezMel, pOld, sizeof(LKF_CONTEXT_OTHERKA_SPEZMEL) * pContext->otherspezcount);
                                LKF_FREE (pContext, "lkf_initSpezMels", pOld);
                            }
                        }
                        pOtherKASpezMel = pContext->otherKASpezMel + pContext->otherspezcount++;
                        memcpy (pOtherKASpezMel->ka, spezList + 5, 4);
                        pOtherKASpezMel->spezmelindex = j;
                    }
                    break;
                }
            }
        }
		spezList += sizeof (SPEZ_LIST_STRING);
	}

    if (pContext->otherKASpezMel) {
        qsort (pContext->otherKASpezMel, pContext->otherspezcount, sizeof (LKF_CONTEXT_OTHERKA_SPEZMEL), sort_context_otherspezmels);
        
        if (modelljahr >= 2024)
        { // FATT check
            unsigned int i;
            LKF_CONTEXT_OTHERKA_SPEZMEL *pCmp, *pCur;
            pCmp = pContext->otherKASpezMel;
            pCur = pContext->otherKASpezMel + 1;
            for (i = 1; i < pContext->otherspezcount; i++) {
                
                if (pCmp->spezmelindex == pCur->spezmelindex &&
                    !memcmp (pCmp->ka, pCur->ka, 4)) {
                    reportFATTError(pContext, pCur->ka, 'M', pContext->spezMels[pCur->spezmelindex].melkz);
                }
                
                ++pCmp;
                ++pCur;
            }
        }
    }
}

void lkf_SpezListCheck (LKF_CONTEXT *pContext)
{ /* V2024.0 */
    unsigned int i, count;
    const SPEZ_LIST_STRING *pComp, *pCur;
    if (pContext->spez_list)
    {
        pComp = (const SPEZ_LIST_STRING *) pContext->spez_list;
        pCur = pComp + 1;
        count = pContext->spez_gesamt;
        for (i = 0; i < count; i++) {
            if ((*pCur)[0] != 'M') {
                if (!memcmp ((*pCur) + 5, (*pComp) + 5, 12)) {
                    reportFATTError(pContext, (*pCur) + 5, (*pCur)[0], (*pCur) + 9);
                }
            }
            ++pComp;
            ++pCur;
        }
    }
    else if (pContext->pStamm2001) {
        pComp = (const SPEZ_LIST_STRING *) pContext->pStamm2001->spez_list;
        pCur = pComp + 1;
        count = pContext->pStamm2001->spez_gesamt;
        
        for (i = 0; i < count; i++) {
            if ((*pCur)[0] != 'M') {
                if (!memcmp ((*pCur) + 5, (*pComp) + 5, 12) && !memcmp ((*pCur) + 5, pContext->KANR, 4)) {
                    reportFATTError(pContext, (*pCur) + 5, (*pCur)[0], (*pCur) + 9);
                }
            }
            ++pComp;
            ++pCur;
        }
    }
    
    if (pContext->spezMels) {
        LKF_FREE(pContext, "lkf_SpezListCheck", pContext->spezMels);
        pContext->spezMels = 0;
        pContext->spezMelCount = 0;
    }
    lkf_initSpezMels(pContext);
}

int lkf_SpezMelOhneGenehmigung (LKF_AUFENTHALT *pAufenthalt, unsigned int melindex, unsigned int *spezmelindex)
{ /* V16.0 */
	const LKF_CONTEXT_SPEZMEL *spezMelbuf;
    const LKF_AUFENTHALT_MEL *pMel;
	LKF_CONTEXT *pContext = pAufenthalt->pScoringContext;
    if (!pContext->spezMels) {
        lkf_initSpezMels(pContext);
        if (!pContext->spezMels) return 0;
    }
    pMel = pAufenthalt->mel + melindex;
    spezMelbuf = (const LKF_CONTEXT_SPEZMEL *) bsearch  (pMel->MEL, pContext->spezMels, pContext->spezMelCount, sizeof (LKF_CONTEXT_SPEZMEL), search_context_spezmels);
    if (spezMelbuf)
    {
        if (pContext->modelljahr < 2020 || IsBlank(pMel->KALEIST, 6) || !memcmp(pMel->KALEIST, pAufenthalt->KANR, 4)) {
            if (!spezMelbuf->ok)
            {
                if (pContext->modelljahr < 2019 || IsBlank(pMel->KALEIST, 6)) {
                    *spezmelindex = (unsigned int) (spezMelbuf - pContext->spezMels);
                    return 1;
                }
            }
            else {
                return 0;
            }
        }
        else {
            LKF_CONTEXT_OTHERKA_SPEZMEL spezmel;
            memcpy (spezmel.ka, pMel->KALEIST, 4);
            spezmel.spezmelindex = (unsigned int) (spezMelbuf - pContext->spezMels);
            
            if (pContext->otherKASpezMel && bsearch(&spezmel, pContext->otherKASpezMel, pContext->otherspezcount, sizeof(LKF_CONTEXT_OTHERKA_SPEZMEL), sort_context_otherspezmels)) {
                return 0;
            }
            return 1;
        }
    }
    return 0;
    
}

_SCORING_EXPORT int lkf_get_amb_counter (LKF_CONTEXT *pContext, unsigned int ambIndex) {
    
    if (!pContext->scoring_stat_initialized) {
        lkf_scoring_mbdsstat (pContext);
    }
    
    return pContext->lAmbCounter[ambIndex];
}

_SCORING_EXPORT unsigned int lkf_get_amb_kostenstelle_count(LKF_CONTEXT *pContext)
{ /* V2020.1 */
    if (!pContext->scoring_stat_initialized) {
        lkf_scoring_mbdsstat (pContext);
    }
    return pContext->abtfcstatcount;
}

_SCORING_EXPORT int lkf_get_amb_kostenstelle_value (LKF_CONTEXT *pContext, unsigned int index, unsigned int ambIndex)
{ /* V2020.1 */
    if (ambIndex < 4) {
        return pContext->abtFCStat[index].lAmbCounter[ambIndex];
    }
    return 0;
}

_SCORING_EXPORT void lkf_get_amb_kostenstelle_stringvalue (LKF_CONTEXT *pContext, unsigned int index, unsigned int ambIndex, char *buffer, unsigned int buflen)
{ /* V2020.1 */
    char internalBuf[32];
    if (ambIndex < 4) {
        sprintf (internalBuf, "%d", lkf_get_amb_kostenstelle_value(pContext, index, ambIndex));
    }
    else {
        switch (ambIndex) {
            case LKF_AMBCOUNT_ABTFC:
                memcpy (internalBuf, pContext->abtFCStat[index].abtfc, 8);
                internalBuf[8] = 0;
                break;
            default:
                internalBuf[0] = 0;
        }
    }
    
    strncpy (buffer, internalBuf, buflen);
}

static int compare_amtstat_kostenstelle (const void *value, const void *candidate)
{ /* V2020.1 */
    const LKF_CONTEXT_ABTFC_STAT *pCand = (const LKF_CONTEXT_ABTFC_STAT *) candidate;
    return memcmp(value, pCand->abtfc, 8);
}

_SCORING_EXPORT int lkf_get_amb_kostenstelle_counter (LKF_CONTEXT *pContext, const char *kostenstelle, unsigned int ambIndex)
{ /* V2020.1 */
    if (!pContext->scoring_stat_initialized) {
        lkf_scoring_mbdsstat (pContext);
    }
    if (pContext->abtFCStat) {
        const LKF_CONTEXT_ABTFC_STAT *found = bsearch(kostenstelle, pContext->abtFCStat, pContext->abtfcstatcount, sizeof(LKF_CONTEXT_ABTFC_STAT), compare_amtstat_kostenstelle);
        if (found) {
            return found->lAmbCounter[ambIndex];
        }
    }
    return 0;
}

_SCORING_EXPORT int lkf_get_amb_kostenstelle_index(LKF_CONTEXT *pContext, const char *kostenstelle) {
	if (!pContext->scoring_stat_initialized) {
		lkf_scoring_mbdsstat(pContext);
	}
	if (pContext->abtFCStat) {
		const LKF_CONTEXT_ABTFC_STAT *found = bsearch(kostenstelle, pContext->abtFCStat, pContext->abtfcstatcount, sizeof(LKF_CONTEXT_ABTFC_STAT), compare_amtstat_kostenstelle);
		if (found) {
			return (int) (found - pContext->abtFCStat);
		}
	}
	return -1;
}

_SCORING_EXPORT void lkf_reset_aufenthalt_package (LKF_CONTEXT *pContext)
{
    unsigned int i;
    
    if (!pContext->pCheckContext) {
        pContext->pCheckContext = lkf_get_contextcheckcontext (pContext);
    }
    if (!pContext->pCheckContext->pKKContext) {
        pContext->pCheckContext->pKKContext = lkf_alloc_kk_context (pContext);
    }
    k03_mbdsstat(pContext->pCheckContext, 1);
    lkf_scoring_mbdsstat (pContext);
    if (pContext->pIntScoring) {
        lkf_int_free_structure (pContext);
    }

    if (pContext->ppAufenthalt) {
        for (i = 0; i < pContext->patient_anz; i++) {
            lkf_free_aufenthalt (pContext->ppAufenthalt[i]);
        }
        LKF_FREE (pContext, "lkf_reset_aufenthalt_package", pContext->ppAufenthalt);
    }
    
    pContext->ppAufenthalt = 0;
    pContext->patient_alloc = 0;
    pContext->patient_anz = 0;

    pContext->plaus_work_count = 0;
    pContext->scor_work_count = 0;
    
    /*
    if (pContext->pImportError)
    {
        LKF_FREE (pContext->pImportError);
        pContext->pImportError = 0;
    }
    pContext->nImportErrorAlloc = 0;
    pContext->nImportErrorCount = 0;
    
    if (pContext->pErrorLineBuffer)
    {
        lkf_drop_linebuffer (pContext->pErrorLineBuffer);
        pContext->pErrorLineBuffer = 0;
    }
    */
    if (pContext->pSatzartErrors) {
        Satzart_FreeErrorStructure (pContext, pContext->pSatzartErrors);
        pContext->pSatzartErrors = 0;
    }
    
    if (pContext->ppFilteredErrors) {
        LKF_FREE (pContext, "lkf_reset_aufenthalt_package", (void *)pContext->ppFilteredErrors);
        pContext->ppFilteredErrors = 0;
        pContext->nFilteredErrors = 0;
    }
    
    if (pContext->pFilterErrorInfo)
    {
        lkf_free_errorinfo (pContext->pFilterErrorInfo);
        pContext->pFilterErrorInfo = 0;
    }
    
    if (pContext->pNPPlausContext) {
        lkf_reset_npplaus_context_package (pContext->pNPPlausContext);
    }
    
    if (pContext->pTraceLineBuffer)
    {
        lkf_drop_linebuffer (pContext, pContext->pTraceLineBuffer);
        pContext->pTraceLineBuffer = 0;
    }
    
    if (pContext->pTraceSettings)
    {
        LKF_FREE (pContext, "lkf_reset_aufenthalt_package", pContext->pTraceSettings);
        pContext->pTraceSettings = 0;
    }
    LKFTRACE_INIT(pContext); /* V10.2 */
    
}

_SCORING_EXPORT void lkf_reset_aufenthalte (LKF_CONTEXT *pContext)
{
	unsigned int i;

	if (pContext->pIntScoring) {
		lkf_int_free_structure (pContext);	
	}

	pContext->KANR[0] = 0;

	if (pContext->ppAufenthalt) {
		for (i = 0; i < pContext->patient_anz; i++) {
			lkf_free_aufenthalt (pContext->ppAufenthalt[i]);
		}
		LKF_FREE (pContext, "lkf_reset_aufenthalte", pContext->ppAufenthalt);
	}

	pContext->ppAufenthalt = 0;
	pContext->patient_alloc = 0;
	pContext->patient_anz = 0;

	lkf_reset_ka (pContext);

	if (pContext->kost_list) {
		LKF_FREE (pContext, "lkf_reset_aufenthalte", pContext->kost_list);
		LKF_FREE (pContext, "lkf_reset_aufenthalte", pContext->kost_list2);
		pContext->kost_list = 0;
		pContext->kost_list2 = 0;
		pContext->kost_gesamt = 0;
	}
	
	if (pContext->spez_list) {
		LKF_FREE (pContext, "lkf_reset_aufenthalte", pContext->spez_list);
		pContext->spez_list = 0;
		pContext->spez_gesamt = 0;
	}

	if (pContext->mel_ka) {
		LKF_FREE (pContext, "lkf_reset_aufenthalte", pContext->mel_ka);
		pContext->mel_ka = 0;
		pContext->mel_ka_gesamt = 0;
        pContext->mel_ka_alloc = 0;
	}

	if (pContext->mel_tkl)
	{ 
		LKF_FREE (pContext, "lkf_reset_aufenthalte", pContext->mel_tkl);
		pContext->mel_tkl = 0;
		pContext->mel_tkl_gesamt = 0;
	}
    
    if (pContext->oemelka)
    {
        LKF_FREE (pContext, "lkf_reset_aufenthalte", pContext->oemelka);
        pContext->oemelka_gesamt = 0;
        pContext->oemelka = 0;        
    }

	pContext->systeminfo[0] = 0;

	if (pContext->npplaus_tracefile) { /* V7.2 */
		fclose (pContext->npplaus_tracefile);
		pContext->npplaus_tracefile = 0;
	}

	lkf_init_context_counters (pContext);

	if (pContext->pLineBuffer) {
		lkf_drop_linebuffer (pContext, pContext->pLineBuffer);
		pContext->pLineBuffer = 0;
	}
    
    /* V21.0 */
    if (pContext->pExpLineBuffer) {
        lkf_free_expandedLines(pContext->pExpLineBuffer);
        pContext->pExpLineBuffer = 0;
    }

	
	if (pContext->pImportError) 
	{
		LKF_FREE (pContext, "lkf_reset_aufenthalte", pContext->pImportError);
		pContext->pImportError = 0;
	}
	pContext->nImportErrorAlloc = 0;
	pContext->nImportErrorCount = 0;

	if (pContext->pErrorLineBuffer)
	{
		lkf_drop_linebuffer (pContext, pContext->pErrorLineBuffer);
		pContext->pErrorLineBuffer = 0;
	}

	if (pContext->pCheckContext)
	{
		lkf_free_checkcontext (pContext, pContext->pCheckContext);
		pContext->pCheckContext = 0;
	}

	if (pContext->pSatzartErrors) {
		Satzart_FreeErrorStructure (pContext, pContext->pSatzartErrors);
		pContext->pSatzartErrors = 0;
	}

	if (pContext->ppFilteredErrors) {
		LKF_FREE (pContext, "lkf_reset_aufenthalte", (void *)pContext->ppFilteredErrors);
		pContext->ppFilteredErrors = 0;
		pContext->nFilteredErrors = 0;
	}

	if (pContext->pFilterErrorInfo)
	{
		lkf_free_errorinfo (pContext->pFilterErrorInfo);
		pContext->pFilterErrorInfo = 0;
	}
    
    if (pContext->pFullErrorCounters) {
        lkf_free_errorinfo (pContext->pFullErrorCounters);
        pContext->pFullErrorCounters = 0;
        pContext->sumErrorCount = 0;
        pContext->sumWarningCount = 0;
    }

	if (pContext->pNPPlausContext) {
		lkf_free_npplaus_context (pContext->pNPPlausContext);
		pContext->pNPPlausContext = 0;
	}

	if (pContext->pTraceLineBuffer)
	{
		lkf_drop_linebuffer (pContext, pContext->pTraceLineBuffer);
		pContext->pTraceLineBuffer = 0;
	}

	if (pContext->pTraceSettings)
	{
		LKF_FREE (pContext, "lkf_reset_aufenthalte", pContext->pTraceSettings);
		pContext->pTraceSettings = 0;
	}
	LKFTRACE_INIT(pContext); /* V10.2 */

	if (pContext->pAbt)
	{ /* V11.0 */
		LKF_FREE (pContext, "lkf_reset_aufenthalte", pContext->pAbt);
		pContext->pAbt = 0;
		pContext->nAbtAlloc = 0;
		pContext->nAbtAnz = 0;
	}

	if (pContext->spezMels)
	{ /* V16.0 */
		LKF_FREE(pContext, "lkf_reset_aufenthalte", pContext->spezMels);
		pContext->spezMels = 0;
		pContext->spezMelCount = 0;
	}
    
    pContext->isBM = 0;
    pContext->standortInfo = 0;
    
    pContext->nReplaceSummensatz = 0; /* V21.0 */

    pContext->scoring_stat_initialized = 0; /* V22.0 */
}

/****************************************************************************
** alloc_kost_list, alloc_spez_list und alloc_mel_ka_list belegen in der   **
**    LKF_CONTEXT-Struktur Speicher für die privaten Stammdaten-Listen     **
****************************************************************************/


/************************************************************************
** Suchroutinen für private Stammdaten                                 **
************************************************************************/

const SPEZ_LIST_STRING *SpezInArray (const LKF_CONTEXT *pContext, const char *spez)
{
    if (pContext->spez_list)
    {
        return (const SPEZ_LIST_STRING *) bsearch (spez, pContext->spez_list, pContext->spez_gesamt, sizeof (SPEZ_LIST_STRING), spez_compare);
    }
    return SpezInArrayStamm (pContext->pStamm2001, spez);
}

const SPEZ_LIST_STRING *FirstSpezInArray (const LKF_CONTEXT *pContext, const SPEZ_LIST_STRING *pSpez, const char *spez)
{ /* V14.1 - liefert den ersten SPEZ passenden SPEZ-Eintrag */
    const SPEZ_LIST_STRING *pSpezList = (const SPEZ_LIST_STRING *) pContext->pStamm2001->spez_list;
	if (pSpez > pSpezList && pSpez < pSpezList + pContext->pStamm2001->spez_gesamt)
	{
		while (pSpez >= pSpezList && !spez_compare (pSpez-1, spez))
			--pSpez;
	}
	else 
	{
		pSpezList = (const SPEZ_LIST_STRING *) pContext->spez_list;
		if (pSpez > pSpezList && pSpez < pSpezList + pContext->spez_gesamt)
		{
			while (pSpez >= pSpezList && !spez_compare (pSpez-1, spez))
				--pSpez;
		}
	}
	return pSpez;
}

const SPEZ_LIST_STRING *NextSpezInArray (const LKF_CONTEXT *pContext, const SPEZ_LIST_STRING *pSpez, const char *spez)
{ /* V14.1 - liefert den ersten SPEZ passenden SPEZ-Eintrag */
    const SPEZ_LIST_STRING *pSpezList = (const SPEZ_LIST_STRING *) pContext->pStamm2001->spez_list;
	if (pSpez >= pSpezList && pSpez < pSpezList + pContext->pStamm2001->spez_gesamt - 1 && !spez_compare(pSpez+1, spez))
		return pSpez + 1;
	pSpezList = (const SPEZ_LIST_STRING *) pContext->spez_list;
	if (pSpez >= pSpezList && pSpez < pSpezList + pContext->spez_gesamt - 1 && !spez_compare(pSpez+1,spez))
		return pSpez + 1;
	return 0;
}

unsigned int SpezAnz (const LKF_CONTEXT *pContext)
{
    if (pContext->spez_list) return pContext->spez_gesamt;
    else return SpezAnzStamm (pContext->pStamm2001);
}

KOST_LIST_STRING *KostInArray (const LKF_CONTEXT *pContext, const char *kost)
{
    if (pContext->kost_list)
    {
        return (KOST_LIST_STRING *) bsearch (kost, pContext->kost_list, pContext->kost_gesamt, sizeof (KOST_LIST_STRING), kost_compare);
    }
    return KostInArrayStamm (pContext->pStamm2001, kost);
}

void *KostInArray2 (const LKF_CONTEXT *pContext, const char *kost)
{
    if (pContext->kost_list2)
    {
        return bsearch (&kost, pContext->kost_list2, pContext->kost_gesamt, sizeof (KOST_LIST_STRING *), kost2_compare);
    }
    return KostInArray2Stamm (pContext->pStamm2001, kost);
}

MEL_KA_STRING *GetMELKA (const LKF_CONTEXT *pContext, const char *melka)
{
    if (pContext->mel_ka)
    {
        return (MEL_KA_STRING *) bsearch (melka, pContext->mel_ka, pContext->mel_ka_gesamt, sizeof (MEL_KA_STRING), mel_ka_compare2009);
    }
    return GetMELKAStamm2009 (pContext->pStamm2001, melka);
}

MEL_KA_STRING *GetMELKATKLContext (const LKF_CONTEXT *pContext, const char *melka)
{
    if (pContext->mel_tkl)
    {
        return (MEL_KA_STRING *) bsearch (melka, pContext->mel_tkl, pContext->mel_tkl_gesamt, sizeof (MEL_KA_STRING), mel_ka_compare2009);
    }
    return GetMELKATKL2009 (pContext->pStamm2001, melka);
}

/************************************************************************
** Routinen zur Hinzufügung privater Stammdaten                        **
************************************************************************/

_SCORING_EXPORT int lkf_context_add_spez (LKF_CONTEXT *pContext, const char *line)
{
	char buf[36];
	if (!pContext->spez_list)
	{
		pContext->spez_alloc = 100;
		pContext->spez_list = (SPEZ_LIST_STRING *) lkf_alloc_stamm_array (pContext, sizeof (SPEZ_LIST_STRING), pContext->spez_alloc, "alloc: lkf_context_add_spez");
	}
	else if (pContext->spez_alloc == pContext->spez_gesamt)
	{
		pContext->spez_alloc *= 2;
		pContext->spez_list = (SPEZ_LIST_STRING *) lkf_realloc_stamm_array (pContext, sizeof (SPEZ_LIST_STRING), pContext->spez_alloc, (char *) pContext->spez_list, pContext->spez_gesamt, "realloc: lkf_context_add_spez");
        if (pContext->spez_list == 0) {
            pContext->spez_alloc = pContext->spez_gesamt = 0;
            return LKF_OUTOFMEMORY_ERROR;
        }
	}


	if (line[0] == 'L') line+=2; 
	sprintf (buf, "%c%8.8s%8.8s          %8.8s", line[19], line + 1, line + 11, line + 20);

	memcpy (pContext->spez_list[pContext->spez_gesamt], buf, 35);
	pContext->spez_sorted = 0;
	return (int) pContext->spez_gesamt++;
}

_SCORING_EXPORT int lkf_context_add_kost (LKF_CONTEXT *pContext, const char *line)
{ /* V11.0: Umbau auf dynamische Speicherbelegung */
	if (!pContext->kost_list) 
	{
		pContext->kost_alloc = 100;
		pContext->kost_list  = (KOST_LIST_STRING *) lkf_alloc_stamm_array (pContext, sizeof (KOST_LIST_STRING), pContext->kost_alloc, "alloc: lkf_context_add_kost");
        if (pContext->kost_list == 0) {
            pContext->kost_alloc = 0;
            return LKF_OUTOFMEMORY_ERROR;
        }

		pContext->kost_list2 = (char **) lkf_alloc_stamm_array (pContext, sizeof (char *), pContext->kost_alloc, "alloc: lkf_context_add_kost");
        if (pContext->kost_list2 == 0) {
            LKF_FREE(pContext, "alloc: lkf_context_add_kost", pContext->kost_list);
            pContext->kost_alloc = 0;
            return LKF_OUTOFMEMORY_ERROR;
        }

	}
	else if (pContext->kost_gesamt == pContext->kost_alloc)
	{
		pContext->kost_alloc *= 2;
		pContext->kost_list = (KOST_LIST_STRING *) lkf_realloc_stamm_array (pContext, sizeof (KOST_LIST_STRING), pContext->kost_alloc, (char *) pContext->kost_list, pContext->kost_gesamt, "realloc: lkf_context_add_kost");
        if (pContext->kost_list == 0) {
            LKF_FREE(pContext, "alloc: lkf_context_add_kost", pContext->kost_list2);
            pContext->kost_list2 = 0;
            pContext->kost_alloc = pContext->kost_gesamt = 0;
            return LKF_OUTOFMEMORY_ERROR;
        }
		pContext->kost_list2 = (char **) lkf_realloc_stamm_array (pContext, sizeof (char *), pContext->kost_alloc, (char *) pContext->kost_list2, pContext->kost_gesamt, "realloc: lkf_context_add_kost");
        if (!pContext->kost_list) {
            LKF_FREE(pContext, "alloc: lkf_context_add_kost", pContext->kost_list2);
            pContext->kost_list = 0;
            pContext->kost_alloc = pContext->kost_gesamt = 0;
            return LKF_OUTOFMEMORY_ERROR;
        }
	}

	if (line[0] == 'L')
		sprintf (pContext->kost_list[pContext->kost_gesamt], "K%4.4s%3.3s%c",  line + 3, line + 13, line[16]);
	else 
		sprintf (pContext->kost_list[pContext->kost_gesamt], "K%4.4s1%2.2s%c", line + 1, line + 11, line[14]);

	if (pContext->kost_list[pContext->kost_gesamt][7] == ' ')
	{ /* V9.4 */
		char *sBuf = pContext->kost_list[pContext->kost_gesamt];
		sBuf[7] = sBuf[6];
		sBuf[6] = sBuf[5];
		sBuf[5] = ' ';
	}

	memset (pContext->kost_list[pContext->kost_gesamt] + 9, ' ', 50);
	pContext->kost_sorted = 0;
	return (int) pContext->kost_gesamt++;
}

_SCORING_EXPORT int lkf_context_add_melka_tkl (LKF_CONTEXT *pContext, const char *line)
{
	char buf[12]; /* V14.1 */
	if (!pContext->mel_tkl)
	{
		pContext->mel_tkl_alloc = 1000;
		pContext->mel_tkl = (MEL_KA_STRING *) lkf_alloc_stamm_array (pContext, sizeof (MEL_KA_STRING), pContext->mel_tkl_alloc, "alloc: lkf_context_add_melka_tkl");
        if (!pContext->mel_tkl) {
            pContext->mel_tkl_alloc = 0;
            return LKF_OUTOFMEMORY_ERROR;
        }
	}
	else if (pContext->mel_tkl_gesamt == pContext->mel_tkl_alloc) {
		pContext->mel_tkl_alloc *= 2;
		pContext->mel_tkl = (MEL_KA_STRING *) lkf_realloc_stamm_array (pContext, sizeof (MEL_KA_STRING), pContext->mel_tkl_alloc, (char *) pContext->mel_tkl, pContext->mel_tkl_gesamt, "realloc: lkf_context_add_melka_tkl");
        if (!pContext->mel_tkl) {
            pContext->mel_tkl_alloc = pContext->mel_tkl_gesamt = 0;
            return LKF_OUTOFMEMORY_ERROR;
        }
	}

    sprintf (buf, "%4.4s %5.5s", line + 7, line + 13);
	memcpy (pContext->mel_tkl[pContext->mel_tkl_gesamt], buf, sizeof(MEL_KA_STRING));
 	pContext->mel_tkl_sorted = 0;
	return (int) pContext->mel_tkl_gesamt++;
}

_SCORING_EXPORT int lkf_context_add_melka (LKF_CONTEXT *pContext, const char *line)
{
	char buf[12]; /* V14.1 */
	if (!pContext->mel_ka) 
	{
		pContext->mel_ka_alloc = 200;
		pContext->mel_ka = (MEL_KA_STRING *) lkf_alloc_stamm_array (pContext, sizeof (MEL_KA_STRING), pContext->mel_ka_alloc, "alloc: lkf_context_add_melka");
        if (!pContext->mel_ka) {
            pContext->mel_ka_alloc = 0;
            return LKF_OUTOFMEMORY_ERROR;
        }
	}
	else if (pContext->mel_ka_gesamt == pContext->mel_ka_alloc)
	{
		pContext->mel_ka_alloc *= 2;
		pContext->mel_ka = (MEL_KA_STRING *) lkf_realloc_stamm_array (pContext, sizeof (MEL_KA_STRING), pContext->mel_ka_alloc, (char *) pContext->mel_ka, pContext->mel_ka_gesamt, "realloc: lkf_context_add_melka");
        if (!pContext->mel_ka) {
            pContext->mel_ka_alloc = pContext->mel_ka_gesamt = 0;
            return LKF_OUTOFMEMORY_ERROR;
        }
	}

	if (line[0] == 'L') line += 2;
    
    sprintf (buf, "%4.4s %5.5s", line + 5, line + 11); /* V14.1 */
	memcpy (pContext->mel_ka[pContext->mel_ka_gesamt], buf, sizeof(MEL_KA_STRING));
	pContext->mel_ka_sorted = 0;
	return (int) pContext->mel_ka_gesamt++;
}

_SCORING_EXPORT int lkf_context_add_systeminfo (LKF_CONTEXT *pContext, const char *line)
{
	strncpy (pContext->systeminfo, line, 399);
	pContext->systeminfo[399] = 0;
	return 0;
}

_SCORING_EXPORT const char *lkf_get_systeminfo (const LKF_CONTEXT *pContext)
{
	if (pContext->systeminfo[0]) return pContext->systeminfo;
	else return 0;
}

_SCORING_EXPORT int lkf_context_sort_private_stamm (LKF_CONTEXT *pContext)
{
	unsigned int i;

	if (pContext->spez_list && pContext->spez_gesamt && !pContext->spez_sorted) 
	{ /* V8.1 - Bedingung geändert */
		qsort (pContext->spez_list, pContext->spez_gesamt, sizeof (SPEZ_LIST_STRING), spez_compare);
		pContext->spez_sorted = 1;
	}

	if (pContext->kost_list && pContext->kost_gesamt && !pContext->kost_sorted) 
	{ /* V8.1 - Bedingung geändert */
		qsort (pContext->kost_list, pContext->kost_gesamt, sizeof (KOST_LIST_STRING), kost_compare);
		for (i = 0; i < pContext->kost_gesamt; i++) pContext->kost_list2[i] = pContext->kost_list[i] + 6;
		qsort (pContext->kost_list2, pContext->kost_gesamt, sizeof (char *), kost2_compare);
		pContext->kost_sorted = 1;
	}

	if (pContext->mel_ka && pContext->mel_ka_gesamt && !pContext->mel_ka_sorted) 
	{ /* V8.1 - Bedingung geändert */
		
		if (pContext->modelljahr >= 2013)
			qsort (pContext->mel_ka, pContext->mel_ka_gesamt, sizeof (MEL_KA_STRING), mel_ka_compare2009);
		else	
			qsort (pContext->mel_ka, pContext->mel_ka_gesamt, sizeof (MEL_KA_STRING), mel_ka_compare_old);
		pContext->mel_ka_sorted = 1;
	}

	if (pContext->mel_tkl && pContext->mel_tkl_gesamt && !pContext->mel_tkl_sorted)
	{
		if (pContext->modelljahr >= 2013)
			qsort (pContext->mel_tkl, pContext->mel_tkl_gesamt, sizeof (MEL_KA_STRING), mel_ka_compare2009);
		else
			qsort (pContext->mel_tkl, pContext->mel_tkl_gesamt, sizeof (MEL_KA_STRING), mel_ka_compare_old);
		pContext->mel_tkl_sorted = 1;
	}
    
    if (pContext->oemelka && pContext->oemelka_gesamt && !pContext->oemelka_sorted) {
        qsort (pContext->oemelka, pContext->oemelka_gesamt, sizeof (OEMELKA_STRING), oemelka_compare_2009);
        pContext->oemelka_sorted = 1;
    }

	return 0;
}

/***************************************************************************
** lkf_set_contextflags (V8.1): Setzt die Context-Flags.                  **                                           **
***************************************************************************/

_SCORING_EXPORT void lkf_set_contextflags (LKF_CONTEXT *pContext, int flags)
{
	if (flags != -1) pContext->flags = flags;
    pContext->standortInfo = 0;
    if (pContext->modelljahr <= 2014 && (pContext->flags & LKFCONTEXT_STANDORT)) pContext->standortInfo = 1;/* V19.1: auch Modelle < 2014 */   
	if (pContext->modelljahr > 2014) {
        pContext->isBM = (pContext->flags & LKFCONTEXT_MODUS_BMG) ? 1 : 0;
        if (pContext->isBM) {
            if (pContext->flags & 2) pContext->isBM = 2;
            lkf_context_setPatIdPos (pContext);
        }
        if (!(pContext->flags & LKFCONTEXT_STANDORT)) pContext->standortInfo = 1; /* V21.3 - ausschalten Standortinfo ueber flag */
    }
    if (pContext->flags & LKFCONTEXT_NICHTFONDSKA) {
        pContext->m02_intlen = LKF_AUFENTHALT_ABT_INTSATZ_LEN_NICHTFONDS;
    }
    else {
        pContext->m02_intlen = LKF_AUFENTHALT_ABT_INTSATZ_LEN_FONDS;
    }
#ifdef SUPPORT_PRE2017
    if (flags & LKFCONTEXT_UTF8) {
        pContext->utf8_mode = (pContext->modelljahr >= 2017) ? 0 : 1;
    } else {
        pContext->utf8_mode = (pContext->modelljahr >= 2017) ? 1 : 0;
    }
    
    
#else
    pContext->utf8_mode = (pContext->flags & LKFCONTEXT_UTF8) ? 0 : 1;
#endif
    pContext->model2017errors = (pContext->modelljahr >= 2017 && !(flags & LKFCONTEXT_IGNORE_2017ERRORS));
}


_SCORING_EXPORT int lkf_get_contextflags (LKF_CONTEXT *pContext) 
{ /* V2025.0 */
    return pContext->flags;
}

/************************************************************************
** lkf_set_abrechnungsjahr (V8.1):                                     **
************************************************************************/

_SCORING_EXPORT void lkf_set_abrechnungsjahr (LKF_CONTEXT *pContext, int abrechnungsjahr)
{
	pContext->cmb_jahr = abrechnungsjahr;
	pContext->period_val = 1;
	pContext->period_type = 'J';
	pContext->lfdnr = 1;

	lkf_set_contextflags (pContext, -1);
}

/************************************************************************
** lkf_set_contextparameters: Setzt abrechnungsspezifische Parameter   **
************************************************************************/

_SCORING_EXPORT void lkf_set_contextparameters (LKF_CONTEXT *pContext, int cmb_jahr, int period_val, int lfdnr, char period_type, int flags)
{
	pContext->cmb_jahr = cmb_jahr;
	pContext->period_val = period_val;
	pContext->period_type = period_type;
	pContext->lfdnr = lfdnr;

	lkf_set_contextflags (pContext, flags);
}

_SCORING_EXPORT int lkf_get_PeriodYear (LKF_CONTEXT *pContext)
{ /* V2024.0 */
    return pContext->cmb_jahr;
}

_SCORING_EXPORT int lkf_set_contextparametersFromString (LKF_CONTEXT *pContext, const char *periodString, int flags) {
    

    int cmb_jahr;
    int period_val;
    int lfdnr;
    char period_type;
    int periodStringLen;
    
    periodStringLen = (int) (periodString ? strlen(periodString) : 0);
    
    
    if (periodStringLen < 4) {
        return -1;
    }
    cmb_jahr = (int) lkf_str2int (periodString, 4);
    if (cmb_jahr < 1000 || cmb_jahr > 2500) {
        return -2;
    }
    
    if (periodStringLen < 8) {
        lkf_set_contextparameters(pContext, cmb_jahr, 1, 1, 'J', flags);
        return cmb_jahr;
    }
    
    period_type = periodString[4];
    period_val = (int) lkf_str2int(periodString + 5, 3);
    
    if (periodStringLen >= 9) {
        lfdnr = (int) lkf_str2int(periodString + 8, 2);
    }
    else {
        lfdnr = 1;
    }
    
    lkf_set_contextparameters(pContext, cmb_jahr, period_val, lfdnr, period_type, flags);
    return cmb_jahr;
}



_SCORING_EXPORT const char *lkf_context_get_errortext (const LKF_CONTEXT *pContext)
{
	return pContext->errortext;
}

_SCORING_EXPORT const char *lkf_context_get_outOfMemoryText (const LKF_CONTEXT *pContext)
{
    if (pContext && pContext->outOfMemory[0]) {
        return pContext->outOfMemory;
    }
    return 0;
}

void lkf_set_outOfMemory (LKF_CONTEXT *pContext, const char *comment, size_t size) {
    if (pContext) {
        if (size > 0) {
            sprintf (pContext->outOfMemory, "%s (%ld bytes)", comment, (long) size);
        }
        else {
            strcpy (pContext->outOfMemory, comment);
        }
        sprintf (pContext->errortext, "out of memory: %s", comment);
    }
}


/************************************************************************
** lkf_search_aufenthalt: Sucht im LKF-CONTEXT nach einem Aufenthalt mit**
**    angeg. KANR und Aufnahmezahl; es wird der Index des Patienten    **
**    bzw. der Index des nächstgrößeren Patienten, wenn nicht vorhan-  **
**    den, zurückgeliefert.                                            **
************************************************************************/

static unsigned int lkf_search_aufenthalt (LKF_CONTEXT *pContext, const char *kanr, const char *aufnahmezahl, int *exact_match)
{
	unsigned int minimum, maximum, median;

	int compare_value, i;
    
    minimum = 0;
    maximum = pContext->patient_anz;

    if (!pContext->isBM) {
        char sUCasePATID[LKF_AUFENTHALT_PATID_LEN];
        for (i = 0; i < LKF_AUFENTHALT_PATID_LEN; i++)
            sUCasePATID[i] = (char) toupper (aufnahmezahl[i]);

        while (minimum < maximum) {
            median = (maximum + minimum) >> 1;

            compare_value = strncmp (pContext->ppAufenthalt[median]->KANR, kanr, 4);

            if (compare_value > 0) maximum = median;
            else if (compare_value < 0) {
                if (median == minimum) minimum++;
                else minimum = median;
            }
            else {
                compare_value = strncmp (pContext->ppAufenthalt[median]->UCASE_PATID, sUCasePATID, LKF_AUFENTHALT_PATID_LEN);
                if (compare_value > 0) maximum = median;
                else if (compare_value < 0) {
                    if (median == minimum) minimum++;
                    else minimum = median;
                }
                else {
                    if (exact_match) *exact_match = 1;
                    return median;
                }
            }
        }
    } else {
        while (minimum < maximum) {
            median = (maximum + minimum) >> 1;
            
            compare_value = strncmp (pContext->ppAufenthalt[median]->KANR, kanr, 4);
            
            if (compare_value > 0) maximum = median;
            else if (compare_value < 0) {
                if (median == minimum) minimum++;
                else minimum = median;
            }
            else {
                compare_value = strncmp (pContext->ppAufenthalt[median]->UCASE_PATID, aufnahmezahl, LKF_AUFENTHALT_LONGID_LEN);
                if (compare_value > 0) maximum = median;
                else if (compare_value < 0) {
                    if (median == minimum) minimum++;
                    else minimum = median;
                }
                else {
                    if (exact_match) *exact_match = 1;
                    return median;
                }
            }
        }
        
    }
	if (exact_match) *exact_match = 0;
	return minimum;
}

unsigned int lkf_search_aufenthalt_2017 (LKF_CONTEXT *pContext, const char *key, int *exact_match, unsigned int matchLength)
{
    unsigned int minimum, maximum, median;
    
    int compare_value;
    
    minimum = 0;
    maximum = pContext->patient_anz;
    
    while (minimum < maximum) {
        median = (maximum + minimum) >> 1;
        
        compare_value = strncmp (pContext->ppAufenthalt[median]->UCASE_PATID, key, matchLength);
        if (compare_value > 0) maximum = median;
        else if (compare_value < 0) {
            if (median == minimum) minimum++;
            else minimum = median;
        }
        else {
            if (exact_match) *exact_match = 1;
            return median;
        }
    }
    
    if (exact_match) *exact_match = 0;
    return minimum;
}


/************************************************************************
** lkf_search_kanr: Sucht im LKF-Context nach der Krankenanstalt.      **
************************************************************************/

unsigned int lkf_search_kanr (LKF_CONTEXT *pContext, const char *kanr)
{
    int ret;
    unsigned int index;
    if (pContext->noStamm) {
        if (pContext->ka_gesamt == 1) {
            return 0;
        }
        index = 0;
    }
    else {
        unsigned int minimum, maximum, median;
        int compare_value;
        minimum = 0;
        maximum = pContext->ka_gesamt;
        
        while (minimum < maximum) {
            median = (maximum + minimum) >> 1;
            
            compare_value = strncmp (pContext->ka[median].ka, kanr, 4);
            
            if (compare_value > 0) maximum = median;
            else if (compare_value < 0) {
                if (median == minimum) minimum++;
                else minimum = median;
            }
            else return median;
        }
        
        index = minimum;
        /* Neu anlegen */
    }
    
	if (pContext->ka_alloc == pContext->ka_gesamt) {
		pContext->ka_alloc += LKF_EXTEND_KA;
		pContext->ka = (STAT_KA *) LKF_REALLOC (pContext, "lkf_search_kanr", pContext->ka, sizeof (STAT_KA) * pContext->ka_alloc);
        if (!pContext->ka) {
            pContext->ka_alloc = pContext->ka_gesamt = 0;
            return LKF_OUTOFMEMORY_UINTERROR;
        }
    }

	if (index < pContext->ka_gesamt) {
		memmove (pContext->ka + index + 1, pContext->ka + index, sizeof (STAT_KA) * (pContext->ka_gesamt - index));
	}

	ret = lkf_init_ka (pContext, pContext->ka + index, kanr, 1);
    if (ret == LKF_OUTOFMEMORY_ERROR) {
        if (index < pContext->ka_gesamt) {
            memmove (pContext->ka + index, pContext->ka + index + 1, sizeof (STAT_KA) * (pContext->ka_gesamt - index));
        }
        return LKF_OUTOFMEMORY_UINTERROR;
    }
	pContext->ka_gesamt++;
	return index;
}

/*******************************************************************************************************************************************************
** lkf_get_context_ka_optimized: Gibt statistische Werte über den Grad der Optimierung aus.                                                           **
*******************************************************************************************************************************************************/

_SCORING_EXPORT double lkf_get_context_ka_optimized (const LKF_CONTEXT *pContext, unsigned int i, unsigned int *anz, unsigned int *opt, double *maxpkt, double *actpkt)
{

	if (anz) *anz = (unsigned int) pContext->ka[i].optimizeable;
	if (opt) *opt = (unsigned int) pContext->ka[i].optimized;
	if (maxpkt) *maxpkt = pContext->ka[i].optimized_maxpunkte;
	if (actpkt) *actpkt = pContext->ka[i].optimized_actpunkte;


	if (pContext->ka[i].SCGES > 0) return pContext->ka[i].optimized_actpunkte / pContext->ka[i].optimized_maxpunkte;
	else return 0;

}


/************************************************************************
** lkf_find_patient: Sucht im LKF-CONTEXT nach einem Patienten mit     **
**    angeg. KANR und Aufnahmezahl.                                    **
************************************************************************/

LKF_AUFENTHALT *lkf_find_aufenthalt (LKF_CONTEXT *pContext, const char *kanr, const char *aufnahmezahl)
{
	int exact_match;
	unsigned int index;

    if (pContext->modelljahr >= 2017)
        index = lkf_search_aufenthalt_2017(pContext, aufnahmezahl, &exact_match, LKF_AUFENTHALT_LONGID_LEN_AB2017);
    else
        index = lkf_search_aufenthalt (pContext, kanr, aufnahmezahl, &exact_match);
	if (exact_match) return pContext->ppAufenthalt[index];
	else return 0;
}

#ifdef SUPPORT_PRE2017
static LKF_AUFENTHALT *lkf_find_aufenthaltM (LKF_CONTEXT *pContext, const char *kanr, const char *aufnahmezahl)
{
    int exact_match;
    unsigned int index;
    index = lkf_search_aufenthalt (pContext, kanr, aufnahmezahl, &exact_match);
    if (exact_match) return pContext->ppAufenthalt[index];
    else return 0;
}
#endif

/**************************************************************
** lkf_insert_aufenthalt: Trägt einen neuen Patienten in den **
**     LKF_CONTEXT ein.                                      **
**************************************************************/

_SCORING_EXPORT int lkf_insert_aufenthalt (LKF_CONTEXT *pContext, LKF_AUFENTHALT *pAufenthalt)
{
	int exact_match;
    unsigned int index, ka_index;
	int i;
    if (!pContext->isBM) {
        if (pContext->modelljahr >= 2017) {
            if (!pAufenthalt->UCASE_PATID[0]) {
                // TODO: direkter Aufruf von lkf_insert_aufenthalt 2017
                lkf_aufenthalt_key_lf (pAufenthalt->UCASE_PATID, pAufenthalt->PATID, pAufenthalt->AUFDAT);
            }
        }
        else {
            for (i = 0; i < LKF_AUFENTHALT_PATID_LEN; i++)
                pAufenthalt->UCASE_PATID[i] = (char) toupper (pAufenthalt->PATID[i]);
        }
    }

    if (!pContext->KANR[0]) {
        lkf_importcheck_kanr(pContext, pAufenthalt->KANR, 0);
    }
    
    if (pContext->modelljahr >= 2017) {
        index = lkf_search_aufenthalt_2017 (pContext, pAufenthalt->UCASE_PATID, &exact_match, LKF_AUFENTHALT_LONGID_LEN_AB2017);
    }
    else {
        index = lkf_search_aufenthalt (pContext, pAufenthalt->KANR, pAufenthalt->UCASE_PATID, &exact_match);
    }
    
	if (exact_match) return -1; /* Fehler -> Patient existiert schon */

	if (pContext->patient_alloc == pContext->patient_anz) {
        if (pContext->patient_alloc > 0) {
            pContext->patient_alloc += LKF_AUFENTHALT_EXTEND_PAT;
            pContext->ppAufenthalt = (LKF_AUFENTHALT **) LKF_REALLOC (pContext, "lkf_insert_aufenthalt", pContext->ppAufenthalt, sizeof (LKF_AUFENTHALT *) * pContext->patient_alloc);
        }
        else {
            pContext->patient_alloc = LKF_AUFENTHALT_EXTEND_PAT;
            pContext->ppAufenthalt = (LKF_AUFENTHALT **) LKF_MALLOC (pContext, "lkf_insert_aufenthalt", sizeof (LKF_AUFENTHALT *) * pContext->patient_alloc);
        }
        if (pContext->ppAufenthalt == 0) {
            pContext->patient_alloc = pContext->patient_anz = 0;
            return LKF_OUTOFMEMORY_ERROR;
        }
	}

	if (index < pContext->patient_anz) {
        memmove (pContext->ppAufenthalt + index + 1, pContext->ppAufenthalt + index, sizeof (LKF_AUFENTHALT *) * (pContext->patient_anz - index));
	}

	ka_index = lkf_search_kanr (pContext, pAufenthalt->KANR);
    if (ka_index == LKF_OUTOFMEMORY_UINTERROR) {

        if (index < pContext->patient_anz) {
            memmove (pContext->ppAufenthalt + index, pContext->ppAufenthalt + index + 1, sizeof (LKF_AUFENTHALT *) * (pContext->patient_anz - index));
        }
        return LKF_OUTOFMEMORY_ERROR;
    }
    
    pAufenthalt->nr = pContext->patient_anz++;
    pContext->ppAufenthalt[index] = pAufenthalt;
	pContext->ka[ka_index].anz++;
	pContext->ka[ka_index].filter_anz++;
    
    if (pAufenthalt->abt_anz > 0) { /* V20.1 */
        pContext->Count_M[0]++;
        pContext->Count_M[1] += pAufenthalt->abt_anz;
        pContext->Count_M[2] += pAufenthalt->diag_anz;
        pContext->Count_M[3] += pAufenthalt->mel_anz;
        pContext->Count_M[4]++;
        pContext->Count_M[5]++;
        pContext->Count_M[6] += pAufenthalt->akwarn_anz;
        pContext->Count_M[7] += pAufenthalt->kommentar_anz;
        
        if (pAufenthalt->pLineBuffer) {
			unsigned long j;
            for (j = 0; j < pAufenthalt->pLineBuffer->lLineCount; j++) {
                const char *l = pAufenthalt->pLineBuffer->pBuf + pAufenthalt->pLineBuffer->plOffsets[j];
                if (!strncmp (l, "I11", 3)) pContext->Count_I[10]++;
                else if (!strncmp(l, "I12", 3)) pContext->Count_I[11]++;
            }
        }
    }

	return (int) index;

}


/***********************************************************************************
** lkf_init_ka: Initialisiert die Struktur für eine KA                            **
**    V8.1: Zusätzlicher Parameter pContext, error- und warning-counter dynamisch **
***********************************************************************************/

void lkf_free_ka (LKF_CONTEXT *pContext, STAT_KA *pKA)
{
	if (pKA->abt) LKF_FREE (pContext, "lkf_free_ka", pKA->abt);

	if (pKA->error_counts) {
		LKF_FREE (pContext, "lkf_free_ka", pKA->error_counts);
		pKA->error_counts = 0;
	}

	if (pKA->warning_counts) {
		LKF_FREE (pContext, "lkf_free_ka", pKA->warning_counts);
		pKA->warning_counts = 0;
	}
}

int lkf_init_ka (LKF_CONTEXT *pContext, STAT_KA *pKA, const char *ka, int complete)
{

	if (ka) {
		pKA->anz = 0;
		pKA->filter_anz = 0;
		memcpy (pKA->ka, ka, 4);
		pKA->ka[4] = 0;
	}
	
	pKA->LDFPTK = 0;
	pKA->LDFPLK = 0;
	pKA->SCUTK = 0;
	pKA->SCULK = 0;
	pKA->VDZU = 0;
	pKA->INTZU = 0;
	pKA->MELZU = 0;
	pKA->SCSPEZ = 0;
	pKA->SCGES = 0;
    pKA->SCGES_AMB = 0; /* V2022.1 */
	pKA->SCGES_EXLKF = 0;
	pKA->SCGES_INLKF = 0;
	pKA->SCUTK_TKL = 0;
	pKA->SCGES_INLKF_TKL = 0;
	pKA->SCGES_EXLKF_TKL = 0;
	pKA->optimizeable = 0;
	pKA->optimized = 0;
	pKA->optimized_maxpunkte = 0;
	pKA->optimized_actpunkte = 0;

	if (complete && pContext->pStamm2001 && pContext->pStamm2001->pMBDSErrors) {
		unsigned int i;

        pKA->error_code_min = pContext->pStamm2001->pMBDSErrors->min_error;
        pKA->error_code_max = pContext->pStamm2001->pMBDSErrors->max_error;
        pKA->warning_code_min = pContext->pStamm2001->pMBDSErrors->min_warning;
        pKA->warning_code_max = pContext->pStamm2001->pMBDSErrors->max_warning;

		pKA->error_counts = (unsigned int *) LKF_CALLOC (pContext, "lkf_init_ka", pKA->error_code_max - pKA->error_code_min + 1, sizeof (unsigned int));
        if (!pKA->error_counts) return LKF_OUTOFMEMORY_ERROR;
        
        pKA->warning_counts = (unsigned int *) LKF_CALLOC (pContext, "lkf_init_ka", pKA->warning_code_max - pKA->warning_code_min + 1, sizeof (unsigned int));
        if (!pKA->warning_counts) {
            LKF_FREE (pContext, "lkf_init_ka", pKA->error_counts);
            return LKF_OUTOFMEMORY_ERROR;
        }
		for (i = 0; i < pKA->error_code_max - pKA->error_code_min + 1; i++)
			pKA->error_counts[i] = 0;

		for (i = 0; i < pKA->warning_code_max - pKA->warning_code_min + 1; i++)
			pKA->warning_counts[i] = 0;

		pKA->abt = 0;
		pKA->abt_alloc = 0;
		pKA->abt_gesamt = 0;
        return 0;
	}
    return -1;
}

_SCORING_EXPORT unsigned int lkf_add_ka_stats (LKF_CONTEXT *pContext, LKF_AUFENTHALT *pAufenthalt, int modus)
{
	unsigned int j;
	
    j = lkf_search_kanr (pContext, pAufenthalt->KANR);
    if (j == LKF_OUTOFMEMORY_UINTERROR) return LKF_OUTOFMEMORY_UINTERROR;
	if (modus & 1) {
		pContext->ka[j].anz++;
		pContext->ka[j].filter_anz++;
	}

	if (modus & 2) {
		pContext->ka[j].error_anz += pAufenthalt->plaus_err;
		pContext->ka[j].warning_anz += pAufenthalt->plaus_warn;
		pContext->ka[j].akwarn_anz += pAufenthalt->akwarn_count;
		pContext->ka[j].akerr_anz += pAufenthalt->akerr_count;
		pContext->ka[j].melde_count += pAufenthalt->melde_count;
		pContext->ka[j].akinfo_anz += pAufenthalt->akinfo_count;
		pContext->ka[j].info_anz += pAufenthalt->plaus_info;
	}

	if (modus & 4) {

		pContext->ka[j].LDFPTK += (double) pAufenthalt->LDFPTK;
		pContext->ka[j].LDFPLK += pAufenthalt->LDFPLK;
		pContext->ka[j].SCUTK += pAufenthalt->SCUTK;
		pContext->ka[j].SCULK += pAufenthalt->SCULK;
		pContext->ka[j].VDZU += pAufenthalt->VDZU;
		pContext->ka[j].INTZU += pAufenthalt->INTZU;
		pContext->ka[j].MELZU += pAufenthalt->MELZU;
		pContext->ka[j].SCSPEZ += pAufenthalt->SCSPEZ;
		pContext->ka[j].SCGES += pAufenthalt->SCGES;

        pContext->ka[j].SCUTK_TKL += pAufenthalt->SCUTK_TKL;

        if (pAufenthalt->FLAG & 1)
                pContext->ka[j].SCGES_EXLKF_TKL += pAufenthalt->SCGES_TKL;
        else pContext->ka[j].SCGES_INLKF_TKL += pAufenthalt->SCGES_TKL;

		if (pAufenthalt->FLAG & 1)
			 pContext->ka[j].SCGES_EXLKF += pAufenthalt->SCGES;
		else pContext->ka[j].SCGES_INLKF += pAufenthalt->SCGES;
        
        if (pAufenthalt->isAmb)
            pContext->ka[j].SCGES_AMB += pAufenthalt->SCGES; /* V21.1 */

		if (pContext->flags & LKFCONTEXT_OPTIMIZER) {
		
			if (pAufenthalt->optimizeable) {
				pContext->ka[j].optimizeable++;
				if (pAufenthalt->optimized_subgruppe == pAufenthalt->max_index) pContext->ka[j].optimized++;
				pContext->ka[j].optimized_maxpunkte += pAufenthalt->subgruppe[pAufenthalt->optimized_subgruppe].SCGES;
				pContext->ka[j].optimized_actpunkte += pAufenthalt->SCGES; 
			}
		
		}
	}
	
	return j;
}

_SCORING_EXPORT void lkf_reset_ka (LKF_CONTEXT *pContext)
{
	unsigned int i;
	
	for (i = 0; i < pContext->ka_gesamt; i++) {
		lkf_free_ka (pContext, pContext->ka + i);
	}

	pContext->ka_alloc = pContext->ka_gesamt = 0;

	if (pContext->ka) {
		LKF_FREE (pContext, "lkf_reset_ka", pContext->ka);
		pContext->ka = 0;
	}

} 

_SCORING_EXPORT unsigned int  lkf_get_context_ka_abtanz (const LKF_CONTEXT *pContext, unsigned int i)
{
	if (i >= pContext->ka_gesamt) return 0;
	else return pContext->ka[i].abt_gesamt;
}

_SCORING_EXPORT const char *  lkf_get_context_ka_abtstat (const LKF_CONTEXT *pContext, unsigned int ka, unsigned int abt, unsigned int *anz, unsigned int *bd, unsigned int *err)
{
	STAT_ABTEILUNG *pAbt;

	if (ka >= pContext->ka_gesamt) return 0;
	if (abt >= pContext->ka[ka].abt_gesamt) return 0;
	pAbt = pContext->ka[ka].abt + abt;

	if (anz) *anz = pAbt->abt_patanz;
	if (bd) *bd = pAbt->abt_bd;
	if (err) *err = pAbt->abt_error;

	return pAbt->abt_fc;

}

_SCORING_EXPORT double lkf_get_context_scorvalue (const LKF_CONTEXT *pContext, unsigned int kanr, unsigned int field)
{ 
	switch (field) {
		
		case SCORFIELD_LDFPTK: return pContext->ka[kanr].LDFPTK;
		case SCORFIELD_LDFPLK: return pContext->ka[kanr].LDFPLK;
		case SCORFIELD_SCUTK:  return pContext->ka[kanr].SCUTK;
		case SCORFIELD_SCULK:  return pContext->ka[kanr].SCULK;
		case SCORFIELD_VDZU:   return pContext->ka[kanr].VDZU;
		case SCORFIELD_INTZU:  return pContext->ka[kanr].INTZU;
		case SCORFIELD_MELZU:  return pContext->ka[kanr].MELZU;
		case SCORFIELD_SCSPEZ: return pContext->ka[kanr].SCSPEZ;
		case SCORFIELD_SCGES:  return pContext->ka[kanr].SCGES;
		case SCORFIELD_SCGES_INLKF:
							   return pContext->ka[kanr].SCGES_INLKF;
		case SCORFIELD_SCGES_EXLKF:
							   return pContext->ka[kanr].SCGES_EXLKF;
		case SCORFIELD_SCUTK_TKL:  
							   return pContext->ka[kanr].SCUTK_TKL;
		case SCORFIELD_SCGES_INLKF_TKL:
							   return pContext->ka[kanr].SCGES_INLKF_TKL;
		case SCORFIELD_SCGES_EXLKF_TKL:
							   return pContext->ka[kanr].SCGES_EXLKF_TKL;
        case SCORFIELD_SCGES_STAT:
                               return pContext->ka[kanr].SCGES - pContext->ka[kanr].SCGES_AMB;
        case SCORFIELD_SCGES_AMB:
                               return pContext->ka[kanr].SCGES_AMB;

		default: return 0;
	}
}

_SCORING_EXPORT unsigned int lkf_context_GetErrorAnz (const LKF_CONTEXT *pContext, unsigned int kanr, int *accepted)
{
	if (accepted) *accepted = (int) pContext->ka[kanr].akerr_anz;
	return (unsigned int) pContext->ka[kanr].error_anz;
}

_SCORING_EXPORT unsigned int lkf_context_getSatzartErrorAnz (const LKF_CONTEXT *pContext, unsigned int flags)
{
    unsigned int count = 0;

    if (!pContext->pSatzartErrors)
        return 0;
    
    if (!flags) {
        return pContext->pSatzartErrors->nCount;
    }

	if (flags & LKF_SEV_INFO)
		count += pContext->pSatzartErrors->nInfoCount;
	if (flags & LKF_SEV_WARNING)
		count += pContext->pSatzartErrors->nWarningCount;
	if (flags & LKF_SEV_ERROR)
		count += pContext->pSatzartErrors->nErrorCount;
	if (flags & LKF_SEV_FATAL)
		count += pContext->pSatzartErrors->nFatalCount;
	/*
    for (i = 0; i < pContext->pSatzartErrors->nCount; i++) {
        if (pContext->pSatzartErrors->pErrors[i].pErrorDef->nSeverity & flags) ++count;
    }
	*/
    return count;
}

_SCORING_EXPORT unsigned int lkf_context_GetWarningAnz (const LKF_CONTEXT *pContext, unsigned int kanr, int *accepted)
{
	if (accepted) *accepted = (int) pContext->ka[kanr].akwarn_anz;
	return (unsigned int) pContext->ka[kanr].warning_anz;
}

_SCORING_EXPORT unsigned int lkf_context_GetHinweisAnz (const LKF_CONTEXT *pContext, unsigned int kanr, int *accepted)
{ /* V13.0 */
	if (accepted) *accepted = (int) pContext->ka[kanr].akinfo_anz;
	return (unsigned int) pContext->ka[kanr].info_anz;
}


_SCORING_EXPORT unsigned int  lkf_context_GetMeldeDiagAnz (const LKF_CONTEXT *pContext, unsigned int kanr)
{   /* V7.0 */
	return (unsigned int) pContext->ka[kanr].melde_count;
}



/************************************************************************
** lkf_get_context_ka_anz: Liefert die Anzahl Krankenanstalten der     **
**    Aufenthalte im Aufenthalts-Array.                                **
************************************************************************/

_SCORING_EXPORT unsigned int lkf_get_context_ka_anz (const LKF_CONTEXT *pContext)
{
	return pContext->ka_gesamt;
}


/*************************************************************************
** lkf_get_context_ka: Liefert die i. Krankenanstalt (und die Anzahl    **
**    Aufenthalte) aus dem Aufenthalts-Array.                           **
*************************************************************************/ 

_SCORING_EXPORT const char *lkf_get_context_ka (const LKF_CONTEXT *pContext, unsigned int i, unsigned int *anz, unsigned int *filter_anz)
{

	if (pContext->isKTR)
		return pContext->KANR; /* V14.2 */

	if (i < pContext->ka_gesamt) {
	
		if (anz) *anz = pContext->ka[i].anz;
		if (filter_anz) *filter_anz = pContext->ka[i].filter_anz;
		return pContext->ka[i].ka;
	}
	else return 0;
}


/************************************************************************
** lkf_get_aufenthalt_anz: Liefert die Anzahl Aufenthalte im LKF-      **
**     Context.                                                        **
************************************************************************/

_SCORING_EXPORT unsigned int lkf_get_aufenthalt_anz (const LKF_CONTEXT *pContext)
{
	return pContext->patient_anz;
}


/************************************************************************
** lkf_get_aufenthalt: Liefert einen Aufenthalt aus dem Aufenthalts-   **
**      Array des LKF-Contexts zurück.                                 **
************************************************************************/

_SCORING_EXPORT LKF_AUFENTHALT *lkf_get_aufenthalt (const LKF_CONTEXT *pContext, unsigned int i)
{
	if (i < pContext->patient_anz) return pContext->ppAufenthalt[i];
	else return 0;
}

/*************************************************************************
** function lkf_add_context_linebuf_line (V8.1):                        **
**     Fügt dem Context-Linebuffer eine Zeile hinzu.                    **
*************************************************************************/

unsigned int lkf_add_context_linebuf_line (LKF_CONTEXT *pContext, const char *line)
{
    if (!pContext->pLineBuffer) {
        pContext->pLineBuffer = lkf_create_linebuffer(pContext);
        if (!pContext->pLineBuffer) return LKF_OUTOFMEMORY_UINTERROR;
    }
	return lkf_add_dynamic_line (pContext, pContext->pLineBuffer, line);
}

unsigned int lkf_add_context_expLine (LKF_CONTEXT *pContext, LKF_EXPANDED_LINE *pLine) {
    unsigned int ret;
    if (!pContext->pExpLineBuffer) {
        pContext->pExpLineBuffer = lkf_create_expandedLines(pContext, 20);
        if (!pContext->pExpLineBuffer) return LKF_OUTOFMEMORY_UINTERROR;
    }
    ret = lkf_add_expandLine(pContext->pExpLineBuffer, pLine);
    if (ret == LKF_OUTOFMEMORY_UINTERROR) return ret;
    return 0;
}

unsigned int lkf_add_context_linebuf_line_error (LKF_CONTEXT *pContext, const char *line)
{
    if (pContext->nSumImportErrors > LKF_MAX_IMPORTERRORS) return 0;
    if (!pContext->pErrorLineBuffer) {
        pContext->pErrorLineBuffer = lkf_create_linebuffer(pContext);
        if (!pContext->pErrorLineBuffer) return LKF_OUTOFMEMORY_UINTERROR;
    }
	return lkf_add_dynamic_line (pContext, pContext->pErrorLineBuffer, line);
}


/******************************************************
** lkf_add_line: Fuegt eine beliebige Satzart hinzu. **
******************************************************/
#ifdef SUPPORT_PRE2017
static unsigned int getSatzartNr (const char *ascii_nr)
{
	return (unsigned int) ((ascii_nr[0]-'0') * 10 + (ascii_nr[1]-'0'));
}
#endif

extern const LKF_SATZART_ERRORDEF LKFErrorM01fehlt, LKFErrorM02fehlt, LKFErrorSatzartKZfalsch, LKFErrorSatzartKZfehlt,
LKFErrorM01AUFNRmehrfach, LKFErrorM02PosMehrfach, LKFErrorM05FCmehrfach, LKFErrorM06FCmehrfach, LKFErrorM08FCmehrfach;


SATZART_FELD FeldSatzart  =  {0, TYP_ALPHA,  1,  3, 0, 0, "SATZART"},
			 MBDSFeldKANR =  {0, TYP_ALPHA,  4,  6, 0, 0, "KANR"},
             MBDSFeldPATID = {0, TYP_ALPHA, 10, 10, 0, 0, "AUFNR"},
			 MBDSFeldABTPOS ={0, TYP_ALPHA, 20,  3, 0, 0, "ABTPOS"};


void lkf_context_create_demo_aufid (char *dest, const char *source)
{
    sprintf(dest, "%-10.10s                                                     ", source);
    dest[63] = ' ';
}

int lkf_add_lines(LKF_CONTEXT *pContext, const char *buffer)
{
	return lkf_add_lines2(pContext, buffer, 0, 0);
}

int lkf_add_lines2(LKF_CONTEXT *pContext, const char *buffer, int *pCharCount, int *pErrorCount)
{
	const char *curPos = buffer;
	const char *nextPos = 0;
	char buf[2050];

	int count = 0;
	int errorCount = 0;

    if (pCharCount) *pCharCount = 0;
    if (pErrorCount) *pErrorCount = 0;


	while (curPos) {
		nextPos = curPos;
		while (*nextPos && *nextPos != 10 && *nextPos != 13)
			++nextPos;
		if (nextPos > curPos) {
			int buflen = (int) (nextPos - curPos);
			if (buflen > 2048) buflen = 2048;
			memcpy(buf, curPos, buflen);
			buf[buflen] = 0;
			if (lkf_add_line(pContext, buf)) {

                errorCount++;

                if (*pContext->outOfMemory) {
                    if (pErrorCount) *pErrorCount = (int)errorCount;
                    if (pCharCount) *pCharCount = (int)(nextPos - buffer);
                    //return LKF_OUTOFMEMORY_ERROR;
                }
			}
			++count;
		}

		if (!*nextPos) break;
		curPos = nextPos + 1;
	}

	return count;
}

#ifdef SUPPORT_PRE2017
int lkf_add_line (LKF_CONTEXT *pContext, const char *line)
{
	LKF_AUFENTHALT *pAufenthalt;
	char patid[LKF_AUFENTHALT_LONGID_LEN];
	unsigned int nSatzartNr;
	char kanr[LKF_AUFENTHALT_KANR_LEN + 1];
	const LKF_SATZART_ERRORDEF *pErrorDef;
	const SATZART_INFO *pSatzartInfo;
	char feldbuffer[128];
	unsigned int i, len, nError;

	char sPos[5];

    if (!line || !line[0] || line[0] == 10 || line[0] == 13 || line[0] == ' ')
        return -1;

    if (pContext->modelljahr >= 2017) {
        if (line[0] != 'M' || !(pContext->flags & LKFCONTEXT_SATZART_INPUT_M))
            return lkf_add_xline(pContext, line);
    }
    

	if (!pContext->pStamm2001)
	{ /* V13.0 - Abbruch, wenn Stammdaten noch nicht geladen wurden */
		if (!pContext->modelljahr)
			strcpy (pContext->errortext, "Modelljahr muss gesetzt sein, um diese Funktion aufzurufen");
		else
			sprintf (pContext->errortext, "Stammdaten fuer Modelljahr %d sind nicht geladen", pContext->modelljahr);
		return -3;
	}

	if (IsEmpty (line, 3))
	{
		if (IsEmpty (line, (int) strlen(line))) return -1;
		lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), &FeldSatzart, &LKFErrorSatzartKZfehlt, 0);
		return -1;
	}
    
	switch (*line) {

		case '0':
		case '$':  /* Alte Summensätze */
			return -1;

            
        case 'X':

            if (pContext->modelljahr < 2017)
            { /* als private Satzart erlaubt */
                lkf_add_context_linebuf_line (pContext, line);
                return 0;
            }
            
            return lkf_add_xline(pContext, line);

		case 'M':  /* MBDS-Satz */
			
            if (pContext->modelljahr >= 2017 && !(pContext->flags & LKFCONTEXT_SATZART_INPUT_M)) {
                lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), &FeldSatzart, &LKFErrorSatzartKZfalsch, 0);
                return -1;
            }
            
            
            if (line[1] == '0') {
			
				CopyUCaseLTrim (kanr, line + 3, LKF_AUFENTHALT_KANR_LEN);


				pErrorDef = lkf_importcheck_kanr (pContext, kanr, 0);
				if (pErrorDef) 
				{
					lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), &MBDSFeldKANR, pErrorDef, 0);
					return -1;
				}

				if (line[2] == '1') /* Neuer Patient */ 
				{
					pContext->Count_M[0]++; 

					pAufenthalt = lkf_alloc_aufenthalt ();
					pAufenthalt->pScoringContext = pContext; 
					memcpy (pAufenthalt->KANR, kanr, LKF_AUFENTHALT_KANR_LEN);
                    
                    simLTrim (pAufenthalt->PATID, line + 9, LKF_AUFENTHALT_PATID_LEN); /* V9.4 statt CopyUCaseLTrim */
                    if (pContext->isBM) {

                        if (pContext->isBM == 2) {
                            lkf_context_create_demo_aufid (pAufenthalt->UCASE_PATID, pAufenthalt->PATID);
                            memset (pAufenthalt->PATID, ' ', 10);
                        }
                        else
                            strncpy (pAufenthalt->UCASE_PATID, line + pContext->patidPos[1]->nPos, LKF_AUFENTHALT_LONGID_LEN );
                    }
                    
                    if (pContext->modelljahr >= 2017) {
                        memcpy (pAufenthalt->AUFDAT, line + 52, 8);
                        if (pContext->isBM) {
                            memcpy (pAufenthalt->UCASE_PATID + 64, pAufenthalt->AUFDAT, 8);
                            pAufenthalt->UCASE_PATID[72] = 0;
                        }
                    }
    
					if (lkf_insert_aufenthalt(pContext, pAufenthalt) == -1) {
						lkf_free_aufenthalt (pAufenthalt);
                        if (pContext->isBM)
                            lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), pContext->patidPos[1], &LKFErrorM01AUFNRmehrfach, 0);
                        else
                            lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), &MBDSFeldPATID, &LKFErrorM01AUFNRmehrfach, 0);
						return -1;
					}

				  if (!pContext->cmb_jahr && (pContext->flags & LKFCONTEXT_IMPLICIT_YEAR))
				  {
					  int nYear;
					  char sYear[5];
					  strncpy (sYear, line + 67, 4);
					  sYear[4] = 0;
					  nYear = atoi (sYear);
					  if (nYear >= LKF_YEAR_FIRST && nYear <= LKF_YEAR_LATEST )
						  pContext->cmb_jahr = nYear;
				  }


					return lkf_add_line_auf_bypass_check (pAufenthalt, line, pContext->modelljahr);
				}
				else if (line[2] >= '2' && line[2] <= '8') /* Zusatzdaten zu best. Patienten */
				{
                    nSatzartNr = (unsigned int) (line[2] - '0');
					CopyUCaseLTrim (kanr, line + 3, LKF_AUFENTHALT_KANR_LEN);
                    if (pContext->isBM)
                        if (pContext->isBM == 2)
                            lkf_context_create_demo_aufid (patid, line + 9);
                        else
                            memcpy (patid, line + pContext->patidPos[nSatzartNr]->nPos, LKF_AUFENTHALT_LONGID_LEN);
                    else {
                        CopyUCaseLTrim (patid, line + 9, LKF_AUFENTHALT_PATID_LEN);
                    }
					pAufenthalt = lkf_find_aufenthaltM (pContext, kanr, patid);
					if (pAufenthalt) 
					{
						if (nSatzartNr == 2)
						{
							nError = 0;
							sprintf (sPos, "%2.2s", line + 19);
							for (i = 0; !nError && i < pAufenthalt->abt_anz; i++)
							{
								if (!memcmp (sPos, pAufenthalt->abt[i].ABTPOS, 2)) nError = 1;
							}

							if (nError)
							{
								lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), &MBDSFeldABTPOS, &LKFErrorM02PosMehrfach, 0);
								return -1;
							}
						}
						else if (nSatzartNr == 5 && (pAufenthalt->nSatzartFlags&(1<<5)))
						{
							lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), 0, &LKFErrorM05FCmehrfach, 0);
							return -1;
						}
						else if (nSatzartNr == 6 && (pAufenthalt->nSatzartFlags&(1<<6)))
						{
							lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), 0, &LKFErrorM06FCmehrfach, 0);
							return -1;
						}
						else if (nSatzartNr == 8 && (pAufenthalt->nSatzartFlags&(1<<8)) && pAufenthalt->pScoringContext->modelljahr < 2017)
						{
							lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), 0, &LKFErrorM08FCmehrfach, 0);
							return -1;
						}
						pAufenthalt->nSatzartFlags |= (1<<nSatzartNr);
						pContext->Count_M[nSatzartNr - 1]++; 
						return lkf_add_line_auf_bypass_check (pAufenthalt, line, pContext->modelljahr);
					}
					else
					{
                        if (pContext->isBM)
                            lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line),
                                                        pContext->patidPos[nSatzartNr], &LKFErrorM01fehlt, 0);
                        else
                            lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), &MBDSFeldPATID, &LKFErrorM01fehlt, 0);
						return -1;
					}
				}
			}

			lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), &FeldSatzart, &LKFErrorSatzartKZfalsch, 0);
			return -1;
	
		case 'I': /* Intensiv-Satz */
			  nSatzartNr = getSatzartNr (line + 1);
			  pSatzartInfo = lkf_GetSatzartI (pContext, nSatzartNr);
			  if (pSatzartInfo) {

				  CopyUCaseLTrim (kanr, line + 3, LKF_AUFENTHALT_KANR_LEN);
                  if (pContext->isBM) {
                      memcpy (patid, line + pContext->patidPos[nSatzartNr]->nPos, LKF_AUFENTHALT_LONGID_LEN);
                      if (pContext->isBM == 2) {
                          lkf_context_create_demo_aufid (patid, line + 9);
                      }
                  }
                  else
                      CopyUCaseLTrim (patid, line + 9, LKF_AUFENTHALT_PATID_LEN);
				
				  pErrorDef = lkf_importcheck_kanr (pContext, kanr, 0);
				  if (pErrorDef) 
				  {
				      lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), &MBDSFeldKANR, pErrorDef, 0);
					  return -1;
				  }

				  pAufenthalt = lkf_find_aufenthalt (pContext, kanr, patid);
				  if (pAufenthalt) 
				  {

					  len = (unsigned int) strlen (line);
					  Satzart_GetValueString (line, len, pSatzartInfo->ppRef[GEN_ABTPOS], feldbuffer, 128);

					  for (i = 0; i < pAufenthalt->abt_anz && memcmp (pAufenthalt->abt[i].ABTPOS, feldbuffer, 2); i++) ;
					  if (i < pAufenthalt->abt_anz)
					  {
						  pContext->Count_I[nSatzartNr-1]++;
						  lkf_add_linebuf_line (pAufenthalt, line);
						  return 0;
					  }
					  else
					  {
						  lkf_context_addimporterror  (pContext, lkf_add_context_linebuf_line_error (pContext, line), pSatzartInfo->ppRef[GEN_ABTPOS], &LKFErrorM02fehlt, pSatzartInfo);
						  return -1;		
					  }
				  }
				  else 
				  {
                      if (pContext->isBM) {
                          lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), pContext->patidPos[nSatzartNr], &LKFErrorM01fehlt, pSatzartInfo);
                      }
                      else {
                          lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), pSatzartInfo->ppRef[GEN_AUFNR], &LKFErrorM01fehlt, pSatzartInfo);                          
					  }
                      return -1;
				  }
			  }
			  else 
			  {
				  lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), &FeldSatzart, &LKFErrorSatzartKZfalsch, 0);
				  return -1;
			  }

		case 'L':
			  nSatzartNr = getSatzartNr (line + 1);
			  if (nSatzartNr > 0 && nSatzartNr <= MAX_L_SATZART_NUM) {	

				  pSatzartInfo = lkf_GetSatzartL (pContext, nSatzartNr);
				  len = (unsigned int) strlen (line);
				  Satzart_GetValueString (line, len, pSatzartInfo->ppRef[GEN_KANR], feldbuffer, 128);
				  pErrorDef = lkf_importcheck_kanr (pContext, feldbuffer, 0);
				  if (pErrorDef) 
				  {
				      /* kein Error für andere KAs bei L-Sätzen 
					  lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), pSatzartInfo->ppRef[GEN_KANR], pErrorDef, pSatzartInfo);
					  */
					  return -1;
				  }
				  
				  pContext->Count_L[nSatzartNr-1]++;
				  lkf_add_context_linebuf_line (pContext, line);

				  switch (nSatzartNr) 
				  {
					case 1:
						lkf_context_add_spez (pContext, line);
						break;
					case 2:
						lkf_context_add_kost (pContext, line);
						break;
					case 3:
						lkf_context_add_melka (pContext, line);
						break;
					case 4:
						lkf_context_add_melka_tkl (pContext, line);
						break;
				  }

				  return 0;
			  }
			  else 
			  {
				  lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), &FeldSatzart, &LKFErrorSatzartKZfalsch, 0);
				  return -1;
			  }

		case 'B':

			  nSatzartNr = getSatzartNr (line + 1);
			  if (nSatzartNr > 0 && nSatzartNr <= MAX_B_SATZART_NUM) {
				  pSatzartInfo = lkf_GetSatzartB (pContext, nSatzartNr);
				  len = (unsigned int) strlen (line);
	
				  Satzart_GetValueString (line, len, pSatzartInfo->ppRef[GEN_KANR], feldbuffer, 128);
				  pErrorDef = lkf_importcheck_kanr (pContext, feldbuffer, 1);
				  if (pErrorDef) 
				  {
				      lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), pSatzartInfo->ppRef[GEN_KANR], pErrorDef, pSatzartInfo);
					  return -1;
				  }
				  pContext->Count_B[nSatzartNr-1]++;

				  if (!pContext->cmb_jahr && (pContext->flags & LKFCONTEXT_IMPLICIT_YEAR))
				  { /* V12.1 */
					  int nYear = 0;
					  if (Satzart_GetValueInt (line, len, pSatzartInfo->ppRef[GEN_JAHR],&nYear) != LKF_FIELD_ERROR && nYear >= LKF_YEAR_FIRST && nYear <= LKF_YEAR_LATEST )
						  pContext->cmb_jahr = nYear;
				  }

				  lkf_add_context_linebuf_line (pContext, line);
				  return 0;
			  }
			  else 
			  {
				  lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), &FeldSatzart, &LKFErrorSatzartKZfalsch, 0);
				  return -1;
			  }

		case 'K':
			  nSatzartNr = getSatzartNr (line + 1);
			  if (nSatzartNr > 0 && nSatzartNr <= MAX_K_SATZART_NUM) {
				  pSatzartInfo = lkf_GetSatzartK (pContext, nSatzartNr);
				  len = (unsigned int) strlen (line);
	
				  Satzart_GetValueString (line, len, pSatzartInfo->ppRef[GEN_KANR], feldbuffer, 128);
				  pErrorDef = lkf_importcheck_kanr (pContext, feldbuffer, 0);
				  if (pErrorDef) 
				  {
				      lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), pSatzartInfo->ppRef[GEN_KANR], pErrorDef, pSatzartInfo);
					  return -1;
				  }
				  pContext->Count_K[nSatzartNr-1]++;					

				  if (!pContext->cmb_jahr && (pContext->flags & LKFCONTEXT_IMPLICIT_YEAR))
				  { /* V12.1 */
					  int nYear = 0;
					  if (Satzart_GetValueInt (line, len, pSatzartInfo->ppRef[GEN_JAHR],&nYear) != LKF_FIELD_ERROR && nYear >= LKF_YEAR_FIRST && nYear <= LKF_YEAR_LATEST )
						  pContext->cmb_jahr = nYear;
				  }

				  lkf_add_context_linebuf_line (pContext, line);
				  return 0;
			  }
			  else 
			  {
				  lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), &FeldSatzart, &LKFErrorSatzartKZfalsch, 0);
				  return -1;
			  }

		case 'G':
			  nSatzartNr = getSatzartNr (line + 1);
			  if (nSatzartNr > 0 && nSatzartNr <= MAX_G_SATZART_NUM) {
				  lkf_GetSatzartG (pContext, nSatzartNr);
				  pContext->Count_G[nSatzartNr-1]++;
				  lkf_add_context_linebuf_line (pContext, line);
				  return 0;
			  }
			  else 
			  {
				  lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), &FeldSatzart, &LKFErrorSatzartKZfalsch, 0);
				  return -1;
			  }

		case 'R': /* ab 2009 keine Satzart R mehr */
                lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), &FeldSatzart, &LKFErrorSatzartKZfalsch, 0);
                return -1;

		case 'S': /* Summensatz */
			  nSatzartNr = getSatzartNr (line + 1);
			  if (nSatzartNr == 1 || (nSatzartNr == 11 && pContext->modelljahr >= 2012)) 
			  {	/* V16.0 */
				  pSatzartInfo = lkf_GetSatzartS (pContext, nSatzartNr);
				  if (pSatzartInfo)
				  { /* V16.0 - ignore S01 */
					  len = (unsigned int) strlen (line);
					  Satzart_GetValueString (line, len, pSatzartInfo->ppRef[GEN_KANR], feldbuffer, 128);
					  pErrorDef = lkf_importcheck_kanr (pContext, feldbuffer, 0);
					  if (pErrorDef) 
					  {
						  lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), pSatzartInfo->ppRef[GEN_KANR], pErrorDef, pSatzartInfo);
						  return -1;
					  }
					  pContext->Count_S[nSatzartNr-1]++;					
					  lkf_add_context_linebuf_line (pContext, line);
		  			  pContext->nReplaceSummensatz = 1;
				  }
				  return 0;
			  }
			  else 
			  {
				  lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), &FeldSatzart, &LKFErrorSatzartKZfalsch, 0);
				  return -1;
			  }

		case 'U': case 'V': case 'W':
		case 'Y': case 'Z':	/* V8.1 - private Satzarten */
			lkf_add_context_linebuf_line (pContext, line);
			return 0;

		case '1': /* Satzart 1: Aufenthalts-Stammsatz */

				  pContext->Count_M[0]++; 

				  CopyUCaseLTrim (kanr, line + 2, LKF_AUFENTHALT_KANR_LEN);

				  pErrorDef = lkf_importcheck_kanr (pContext, kanr, 0);
				  if (pErrorDef) 
			  	  {
					  lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), &MBDSFeldKANR, pErrorDef, 0);
					  return -1;
				  }

				  pAufenthalt = lkf_alloc_aufenthalt ();
				  pAufenthalt->pScoringContext = pContext; 
				  memcpy (pAufenthalt->KANR, kanr, LKF_AUFENTHALT_KANR_LEN);
				  CopyUCaseLTrim (pAufenthalt->PATID, line + 8, LKF_AUFENTHALT_PATID_LEN);


				  if (lkf_insert_aufenthalt(pContext, pAufenthalt) == -1) {
					  lkf_free_aufenthalt (pAufenthalt);
					  return -1;
				  }

				  /* pContext->pLatestPatient = pAufenthalt; */
				  return lkf_add_line_auf_bypass_check (pAufenthalt, line, pContext->modelljahr);

		case '2': /* Satzart 2: Verlegungs-Daten */
		case '3': /* Satzart 3: Diagnosen */
		case '4': /* Satzart 4: MELs */
		case '5': /* Satzart 5: Kostenträger */
		case '6': /* Satzart 6: Akzeptierte Warnings */
		case '7': /* Satzart 7: Scoring-Werte */
		case '8': /* Satzart 8: Kommentare */

				  CopyUCaseLTrim (kanr, line + 1, LKF_AUFENTHALT_KANR_LEN);

				  pErrorDef = lkf_importcheck_kanr (pContext, kanr, 0);
				  if (pErrorDef) 
			  	  {
					  lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), &MBDSFeldKANR, pErrorDef, 0);
					  return -1;
				  }

				  CopyUCaseLTrim (patid, line + 7, LKF_AUFENTHALT_PATID_LEN);

				  pAufenthalt = lkf_find_aufenthalt (pContext, kanr, patid);
				  if (pAufenthalt) {
					  pContext->Count_M[*line - '1']++; 
					  return lkf_add_line_auf_bypass_check (pAufenthalt, line, pContext->modelljahr);
				  }
				  else return -1;
				  
		case 'A': /* for compatibility */
				  {
					  char sLocalLine[256];
				      pContext->Count_L[0]++; 	
					  strcpy (sLocalLine, "L0");
					  strncpy (sLocalLine + 2, line, 254);
					  sLocalLine[255] = 0;
				      lkf_add_context_linebuf_line (pContext, sLocalLine);
				      return lkf_context_add_spez (pContext, sLocalLine);
				  }

		case 'C': /* for compatibility */
			      {
					  char sLocalLine[256];
				      pContext->Count_L[2]++; 
					  strcpy (sLocalLine, "L0");
					  strncpy (sLocalLine + 2, line, 254);
					  sLocalLine[255] = 0;
				      lkf_add_context_linebuf_line (pContext, sLocalLine);
				      return lkf_context_add_melka (pContext, sLocalLine);
				  }
		case 'D': /* for compatibility - not supported with V8.1 */
				  return lkf_context_add_systeminfo (pContext, line);

		 default:
				  lkf_context_addimporterror (pContext, lkf_add_context_linebuf_line_error (pContext, line), &FeldSatzart, &LKFErrorSatzartKZfalsch, 0);
				  return -1;
 return -1;
	}
}
#else
int lkf_add_line (LKF_CONTEXT *pContext, const char *line)
{
    return lkf_add_xline(pContext, line);
}
#endif

/* function Plaus_GetErrorCodeCount *****************************************
**     Liefert zum Errorcode die Anzahl Vorkommnisse aller verarbeiteter   **
**     Patienten.                                                          **
****************************************************************************/

_SCORING_EXPORT unsigned int lkf_plaus_GetErrorCodeCount (LKF_CONTEXT *pContext, unsigned int kanr, unsigned int nr)
{
    if (((unsigned int)nr) < pContext->ka[kanr].error_code_min || ((unsigned int)nr) > pContext->ka[kanr].error_code_max) return 0;
    return pContext->ka[kanr].error_counts[nr - pContext->ka[kanr].error_code_min];
}

/* function Plaus_GetWarningCodeCount ***************************************
**     Liefert zum Warningcode die Anzahl Vorkommnisse aller verarbeiteter **
**     Patienten.                                                          **
****************************************************************************/

_SCORING_EXPORT unsigned int lkf_plaus_GetWarningCodeCount (LKF_CONTEXT *pContext, unsigned int kanr, unsigned int nr)
{
	if (((unsigned int)nr) < pContext->ka[kanr].warning_code_min || ((unsigned int)nr) > pContext->ka[kanr].warning_code_max) return 0;
	return pContext->ka[kanr].warning_counts[nr - pContext->ka[kanr].warning_code_min];
}



/* lkf_init_context_counters ************************************************
**     Initialisiert die Arrays error_counters und warning_counters mit 0. **
****************************************************************************/

void lkf_init_context_counters (LKF_CONTEXT *pContext)
{

	pContext->plaus_count = 0;
	pContext->scor_count = 0;
	pContext->plaus_work_count = 0;
	pContext->scor_work_count = 0;

	lkf_Satzart_Counter_Clear (pContext);
}

int lkf_read_inputfile (const char *input_file, LKF_CONTEXT *pContext, char *error)
{
	char line[2048]; /* V12.0 */
	FILE *fp;

	fp = fopen (input_file, "r");
	if (!fp) {
		sprintf (error, "File %s konnte nicht geöffnet werden: %s", input_file, strerror (errno)); /* V18.2 */
		return 2;

	}

	while (fgets (line, 2047, fp)) /* V12.0 */
	{
	
		lkf_add_line (pContext, line);
		
	}

	fclose (fp);
	return 0;
}

/********************************************************************
** Funktion lkf_sort_input_order: Sortiert die Datensätze nach der **
**         Reihenfolge, in der sie eingelesen wurden.              **
********************************************************************/

static int search_pat_nr (const void *p1, const void *p2)
{
	return (int) (*(LKF_AUFENTHALT **) p1)->nr - (int) (*(LKF_AUFENTHALT **) p2)->nr;
}

_SCORING_EXPORT void lkf_sort_input_order (LKF_CONTEXT *pContext)
{
	qsort (pContext->ppAufenthalt, pContext->patient_anz, sizeof (LKF_AUFENTHALT *), search_pat_nr);
}

/********************************************************************
** Funktion lkf_sort_patid_order: Sortiert die Datensätze nach der **
**          Aufenthaltsnummer.                                     **
********************************************************************/

static int search_pat_patid (const void *p1, const void *p2)
{
	return memcmp ((*(LKF_AUFENTHALT **) p1)->UCASE_PATID, (*(LKF_AUFENTHALT **) p2)->UCASE_PATID, 10);
}

static int search_pat_patid_2017 (const void *p1, const void *p2)
{
    return memcmp ((*(LKF_AUFENTHALT **) p1)->UCASE_PATID, (*(LKF_AUFENTHALT **) p2)->UCASE_PATID, 12);
}

void _SCORING_EXPORT lkf_sort_patid_order (LKF_CONTEXT *pContext)
{
    if (pContext->modelljahr >= 2017)
        qsort (pContext->ppAufenthalt, pContext->patient_anz, sizeof (LKF_AUFENTHALT *), search_pat_patid_2017);
    else
        qsort (pContext->ppAufenthalt, pContext->patient_anz, sizeof (LKF_AUFENTHALT *), search_pat_patid);
}


/*********************************************************************
** Funktion lkf_define_custom_line: Definiert, welche Felder im     **
**    Custom-Output aufscheinen sollen.                             **
*********************************************************************/

_SCORING_EXPORT int lkf_define_custom_line (LKF_CONTEXT *pContext, unsigned int fa, unsigned int *f, int fl, char c)
{
	if (pContext->custom_fields) LKF_FREE (pContext, "lkf_define_custom_line", pContext->custom_fields);
	pContext->custom_field_anz = fa;

	if (fa) {
		pContext->custom_fields = (unsigned int *) LKF_CALLOC (pContext, "lkf_define_custom_line", fa, sizeof (unsigned int));
        if (!pContext->custom_fields) {
            return LKF_OUTOFMEMORY_ERROR;
        }
		memcpy (pContext->custom_fields, f, sizeof (unsigned int) * fa);
		pContext->custom_char = c;
		pContext->custom_flags = fl;
	}
	else {
		pContext->custom_fields = 0;
	}
    return 0;
}

/*********************************************************************
** Funktion lkf_write_file: Erzeugt das relationale Output-Format   **
*********************************************************************/

_SCORING_EXPORT int lkf_write_file (const char *filename, LKF_CONTEXT *pContext, unsigned int kanr, int flags, char *error)
{
	char buf[512];
	char savbuf[512];
    int hd_written = 0;

	unsigned int i, j, patanz, anz = 0;
	LKF_AUFENTHALT *pAufenthalt;
	FILE *fp;
	const char *ka;
	unsigned int scoring_anz;

	unsigned int linecount;

	int satzart;
	int ignore_line;
	
    if (!pContext->pStamm2001) {
        sprintf (error, "Ausgabe-File '%s' kann nicht erzeugt werden - Modell-Stammdaten nicht korrekt geladen", filename);
        return 3;
    }
    
	ka = pContext->ka[kanr].ka;

	fp = fopen (filename, "w");
	if (!fp) {
		sprintf (error, "Ausgabe-File '%s' konnte nicht geöffnet werden!", filename);
		return 2;
	}

	patanz = pContext->patient_anz;
	scoring_anz = 0;
	linecount = 0;

	for (satzart = 1; satzart < 11; satzart++) {
		
		if (flags & (1<<satzart)) continue; /* Satzarten ausblenden */

		for (i = 0; (i < patanz) && (satzart < 10 || i < 1); i++) {
			pAufenthalt = pContext->ppAufenthalt[i];

			if (satzart < 10 && !(pAufenthalt->mark & 1)) continue;


			if (!ka || !memcmp (pAufenthalt->KANR, ka, 4)) {

				switch (satzart) {
					case  1: anz = 1; break;
					case  2: anz = lkf_auf_get_abtanz (pAufenthalt); break;
					case  3: anz = lkf_auf_get_diaganz (pAufenthalt); break;
					case  4: anz = lkf_auf_get_melanz (pAufenthalt); break;
					case  5: anz = lkf_auf_get_kostanz (pAufenthalt); break;
					case  6: anz = lkf_auf_get_scoringanz (pAufenthalt); 
						 	 ++scoring_anz; 
							 break;
					case  7: anz = lkf_auf_get_akwarnanz (pAufenthalt); break;
					case  8: anz = lkf_auf_get_kommentaranz (pAufenthalt); break;
					case  9: anz = lkf_auf_get_customanz (pAufenthalt); break;
                    case 10: anz = lkf_get_systeminfo (pContext) ? 1 : 0; break;
				}
	
				linecount += anz;
		
				ignore_line = 0;
				for (j = 0; j < anz; j++) {

					switch (satzart) {
						case  1: lkf_auf_line_root (pAufenthalt, buf); break;
						case  2: lkf_auf_line_abt (pAufenthalt, j, buf); break;
						case  3: lkf_auf_line_diag (pAufenthalt, j, buf); break;
						case  4: lkf_auf_line_mel (pAufenthalt, j, buf); break;
						case  5: lkf_auf_line_kost (pAufenthalt, j, buf); break;
						case  6: lkf_auf_line_scoring (pAufenthalt, buf); break;
						case  7: lkf_auf_line_akwarn (pAufenthalt, j, buf); break;
						case  8: lkf_auf_line_kommentar (pAufenthalt, j, buf); break;
						case 9:  lkf_auf_line_custom (pAufenthalt, buf); break;
						case 10: strcpy (buf, lkf_get_systeminfo(pContext));
								 break;
					
					}

					if (satzart == 3) {
					
						if (!j) {
							strcpy (savbuf, buf);
							hd_written = 0;
						}
						else {
							if (!hd_written && strcmp (savbuf, buf) < 0) {
								hd_written = 1;
								fprintf (fp, "%s\n", savbuf);
							}
							fprintf (fp, "%s\n", buf);
						}
					
					}
					else if (!ignore_line) fprintf (fp, "%s\n", buf);
				}
			}
			if (satzart == 3 && anz && !hd_written) fprintf (fp, "%s\n", savbuf);
		}
	}

	if (!(flags&1)) {

		if (scoring_anz && !(flags&(1<<6))) {

			double scutk, scges_inlkf, scges_exlkf;

            scutk = pContext->ka[kanr].SCUTK_TKL;
            scges_inlkf = pContext->ka[kanr].SCGES_INLKF_TKL;
            scges_exlkf = pContext->ka[kanr].SCGES_EXLKF_TKL;

			fprintf (fp, "0%4.4s  %4d%c%03d%02d%10d%10ld%10ld%12.0f%12.0f%12.0f%12.0f%12.0f%12.0f%12.0f%12.0f%12.0f%12.0f\n", 
					 ka, pContext->cmb_jahr, pContext->period_type,
					 pContext->period_val, pContext->lfdnr,
					 linecount, pContext->ka[kanr].error_anz, pContext->ka[kanr].warning_anz,
					 pContext->ka[kanr].LDFPLK, pContext->ka[kanr].LDFPTK,
					 pContext->ka[kanr].SCULK, scutk,
					 pContext->ka[kanr].VDZU, pContext->ka[kanr].INTZU,
					 pContext->ka[kanr].MELZU, pContext->ka[kanr].SCSPEZ, 
					 scges_inlkf, scges_exlkf);
		}
		else {
			fprintf (fp, "0%4.4s  %4d%c%03d%02d%10d%10ld%10ld\n", 
					 ka, pContext->cmb_jahr, pContext->period_type,
					 pContext->period_val, pContext->lfdnr,
				 linecount, pContext->ka[kanr].error_anz, pContext->ka[kanr].warning_anz);
		}
	}
	fclose (fp);
	return 0;
}

/*********************************************************************
** Funktion lkf_write_svnrfile: Erzeugt das Sozialversicherungs-    **
**     format.                                                      **
*********************************************************************/


_SCORING_EXPORT int  lkf_write_svnrfile (const char *filename, LKF_CONTEXT *pContext, unsigned int kanr, int flags, char *error)
{
	char buf[1024];

	unsigned int i, anz;
	FILE *fp;
	const char *ka;
		
	ka = pContext->ka[kanr].ka;

	fp = fopen (filename, "w");
	if (!fp) {
		sprintf (error, "Ausgabe-File '%s' konnte nicht geöffnet werden!", filename);
		return 2;
	}

	anz = pContext->patient_anz;

	for (i = 0; i < anz; i++) {
		if (!ka || !memcmp (pContext->ppAufenthalt[i]->KANR, ka, 4)) {
			lkf_auf_line_svnr (pContext->ppAufenthalt[i], buf);
			fprintf (fp, "%s\n", buf);		
		}
	}

	fclose (fp);
	return 0;
}

#ifdef LKF_INCLUDE_DEPRECATED_FUNCTIONALITY

_SCORING_EXPORT int lkf_write_errorfile (const char *filename, LKF_CONTEXT *pContext, unsigned int kanr, int flags, const char *inputfile, const char *outputfile, char *error)
{
	unsigned int i, patanz;
	LKF_AUFENTHALT *pAufenthalt;
	FILE *fp;
	LKF_ERROR_LIST *pError;

	int is_warning;

	char line[513];
	const char *ka;

	is_warning  = (flags & 1);

	ka = pContext->ka[kanr].ka;
    fp = fopen (filename, "w");
	if (!fp) {
		sprintf (error, "Ausgabe-File '%s' konnte nicht geöffnet werden!", filename);
		return 2;
	}

	lkf_plaus_WriteWEHeader (pContext, is_warning ? 0 : fp, is_warning ? fp : 0, kanr, inputfile);

	patanz = pContext->patient_anz;

	/* Satzart 1 */
	for (i = 0; i < patanz; i++) {

		pAufenthalt = pContext->ppAufenthalt[i];

		if (!memcmp (pAufenthalt->KANR, ka, 4)) {

			if (is_warning) {
				pError = lkf_auf_firstwarning (pAufenthalt); 
			}
			else {
	 			pError = lkf_auf_firsterror (pAufenthalt);
			}

			while (pError) {
			
				if (is_warning) {
					lkf_plaus_GetWarningText (pAufenthalt, pError, line, 512);
					pError = lkf_auf_nextwarning (pError);
				}
				else {
					lkf_plaus_GetErrorText   (pAufenthalt, pError, line, 512);
					pError = lkf_auf_nexterror (pError);
				}

				fprintf (fp, "%s\n", line);

			}
		}
	
	}

	if (is_warning) lkf_plaus_WriteWEFooter (pContext, 0, fp, kanr, outputfile);
	else            lkf_plaus_WriteWEFooter (pContext, fp, 0, kanr, outputfile);
	fclose (fp);
	return 0;

}

#endif

/******************************************************************************************************************
** lkf_write_meldediagfile: Schreibt das MELDEDIAG-File                                                          **
******************************************************************************************************************/

_SCORING_EXPORT int lkf_write_meldediagfile (const char *filename, LKF_CONTEXT *pContext, unsigned int kanr, char *error)
{
	unsigned int i, patanz;
	LKF_AUFENTHALT *pAufenthalt;
	FILE *fp;
	LKF_ERROR_LIST *pMeldeDiag;

	char line[513];
	const char *ka;

    if (!pContext->pStamm2001) {
        sprintf (error, "Ausgabe-File '%s' kann nicht erzeugt werden - Stammdaten nicht korrekt", filename);
        return 3;
    }
    
	ka = pContext->ka[kanr].ka;

	fp = fopen (filename, "w");
	if (!fp) {
		sprintf (error, "Ausgabe-File '%s' konnte nicht geöffnet werden!", filename);
		return 2;
	}

	patanz = pContext->patient_anz;


	lkf_plaus_WriteFileHeader (pContext, fp, LKF_FILE_MELDEDIAG, kanr, filename, 0);

	for (i = 0; i < patanz; i++) {

		pAufenthalt = pContext->ppAufenthalt[i];

		if (!memcmp (pAufenthalt->KANR, ka, 4)) {

			pMeldeDiag = lkf_auf_firstmeldediag (pAufenthalt); 

			while (pMeldeDiag) {
			
				lkf_plaus_GetMeldeDiagText (pAufenthalt, pMeldeDiag, line, 512);
				pMeldeDiag = lkf_auf_nextmeldediag (pMeldeDiag);
				fprintf (fp, "%s\n", line);
			}
		}
	}

	lkf_plaus_WriteFileFooter (pContext, fp, LKF_FILE_MELDEDIAG, kanr, filename, 0);

	fclose (fp);
	return 0;

}

/*************************************************************************
** lkf_write_errsumfile: Schreibt Errorsummenfile                       **
*************************************************************************/

_SCORING_EXPORT int lkf_write_errsumfile (const char *filename, LKF_CONTEXT *pContext, int flags, char *error)
{
	time_t tim;					/* Datentyp zur Ermittlung von akt. Uhrzeit und Datum */
	struct tm *tm;				/* Struktur fuer akt. Uhrzeit und Datum */
	int is_warning;
	FILE *fp;
	unsigned int act_error_anz;
	unsigned int ki, ka_anz, i, lower, upper;
	char ewcode[6], ewnewcode[4];
    char mCode;
    char utf8buf[512];

	unsigned int count, err_count, ak_count;

	char ka_text[32]; /* V14.2:  24->32 */

	is_warning  = (flags & 1);

	fp = fopen (filename, "w");
	if (!fp) {
		sprintf (error, "Summen-File '%s' konnte nicht geöffnet werden!", filename);
		return 2;
	}

	tim = time (0);
	tm = localtime (&tim);

	fprintf (fp, "LKF%4.4d                   ;        ;           ;\n", pContext->modelljahr);
	fprintf (fp, "                          ;        ;           ;\n");

	fprintf (fp, "%02d.%02d.%04d                ; %02d.%02d  ;           ;",
				  tm->tm_mday, tm->tm_mon+1, tm->tm_year + 1900,
				  tm->tm_hour, tm->tm_min);

	if (is_warning) 
		 fprintf (fp, "%s\n", lkf_context_formatted_text (pContext, " Warnungsummenprotokoll (scoref\xc3\xa4""hige F\xc3\xa4""lle)", utf8buf));
	else fprintf (fp, "%s\n", lkf_context_formatted_text (pContext, " Fehlersummenprotokoll (nicht scoref\xc3\xa4""hige F\xc3\xa4""lle)", utf8buf));

	fprintf (fp, "                          ;        ;           ;\n");
	fprintf (fp, "KANR                      ; ANZAHL ;");

	if (is_warning)
		 fprintf (fp, " WARNCODE  ; KOMMENTAR\n");
	else fprintf (fp, " ERRORCODE ; KOMMENTAR\n");
	
	/* Auflistung der Warningcodes nach Vorkommen ************************************************************/

	ka_anz = pContext->ka_gesamt;
	count = 0;
	ak_count = 0;
	err_count = 0;

	if (is_warning)
		lkf_getWarningCodeMinMax (pContext, &lower, &upper); 
	else
		lkf_getErrorCodeMinMax (pContext, &lower, &upper);   

	for (ki = 0; ki < pContext->ka_gesamt; ki++) {

		lkf_KA_to_Name (pContext, pContext->ka[ki].ka, ka_text);

		count += pContext->ka[ki].filter_anz;

		if (is_warning) {
			err_count += pContext->ka[ki].warning_anz;
			ak_count += pContext->ka[ki].akwarn_anz;
		}
		else {
			err_count += pContext->ka[ki].error_anz;
			ak_count += pContext->ka[ki].akerr_anz;
		}
        
        mCode = pContext->modelljahr >= 2017 ? 'X' : 'M';

		for (i = lower; i <= upper; i++) {

			if (is_warning) {

				act_error_anz = lkf_context_warningcode_count (pContext, 0, i);
				if (act_error_anz) 
                {
                    sprintf (ewcode, "W%c%s", mCode, lkf_getErrorCodeFromInt (i, ewnewcode));
                    fprintf (fp, "%-4.4s %-20.20s ; %6d ; %s      ; %s\n",
							 pContext->ka[ki].ka, ka_text, act_error_anz, ewcode, lkf_context_formatted_text (pContext, lkf_plaus_WarningCode2Text (pContext, (int) i), utf8buf));
				}

			}
			else {
				act_error_anz = lkf_context_errorcode_count (pContext, 0, i); 
				if (act_error_anz)
				{
                    sprintf (ewcode, "E%c%s", mCode, lkf_getErrorCodeFromInt (i, ewnewcode));
                    fprintf (fp, "%-4.4s %-20.20s ; %6d ; %s      ; %s\n",
                             pContext->ka[ki].ka, ka_text, act_error_anz, ewcode, lkf_context_formatted_text (pContext, lkf_plaus_ErrorCode2Text (pContext, (int) i), utf8buf));
				}
			}

		}
	}

	/* Fußzeilen */

    fprintf (fp, "                          ;        ;           ;\n");
	if (is_warning)
		 fprintf (fp, lkf_context_formatted_text (pContext, "Ergebnis                  ;        ;           ; %d Warnungen/ %d akzeptierte Warnungen/ %d Gepr\xc3\xbc""fte F\xc3\xa4""lle", utf8buf),
		 		      err_count, ak_count, count);
	else fprintf (fp, lkf_context_formatted_text (pContext, "Ergebnis                  ;        ;           ; %d Fehler/ %d akzeptierte Fehler/ %d Gepr\xc3\xbc""fte F\xc3\xa4""lle", utf8buf),
					  err_count, ak_count, count);


	fclose (fp);
	return 0;
}


_SCORING_EXPORT int lkf_write_errsumfile_fromFilter (const char *filename, LKF_CONTEXT *pContext, char *error)
{
    time_t tim;					/* Datentyp zur Ermittlung von akt. Uhrzeit und Datum */
    struct tm *tm;				/* Struktur fuer akt. Uhrzeit und Datum */
    FILE *fp;
    unsigned int i;
    char ewcode[6];
    char ecount[10];
    char etext[256];
    char utf8buf[512];
    
    unsigned int count, err_count, ak_count;
    
    char ka_text[32];
    
    fp = fopen (filename, "w");
    if (!fp) {
        sprintf (error, "Summen-File '%s' konnte nicht geoeffnet werden!", filename);
        return 2;
    }
    
    tim = time (0);
    tm = localtime (&tim);
    
    fprintf (fp, "LKF%4.4d                   ;        ;           ;\n", pContext->modelljahr);
    fprintf (fp, "                          ;        ;           ;\n");
    
    fprintf (fp, "%02d.%02d.%04d                ; %02d.%02d  ;           ;",
             tm->tm_mday, tm->tm_mon+1, tm->tm_year + 1900,
             tm->tm_hour, tm->tm_min);
    
    fprintf (fp, "\n");
    
    fprintf (fp, "                          ;        ;           ;\n");
    fprintf (fp, "KANR                      ; ANZAHL ;");
    
    fprintf (fp, " CODE      ; KOMMENTAR\n");
    
    /* Auflistung der Warningcodes nach Vorkommen ************************************************************/
    
    count = lkf_getSatzartErrorSum_Count (pContext);
    ak_count = 0;
    err_count = 0;
    
    lkf_KA_to_Name (pContext, pContext->ka[0].ka, ka_text);
        
    
    for (i = 0; i < count; i++) {
        
        lkf_getSatzartErrorSum_Field (pContext, i, 2, ecount, 10);
        lkf_getSatzartErrorSum_Field (pContext, i, 0, ewcode, 6);
        lkf_getSatzartErrorSum_Field (pContext, i, 1, etext, 256);
        
        fprintf (fp, "%-4.4s %-20.20s ; %6s ; %s      ; %s\n",
                 pContext->ka[0].ka, ka_text, ecount, ewcode, lkf_context_formatted_text (pContext, etext, utf8buf));
    }
    
    /* Fusszeilen */
    
    fprintf (fp, "                          ;        ;           ;\n");
//        fprintf (fp, "Ergebnis                  ;        ;           ; %d insgesamt / %d akzeptiert / %d Gepruefte Faelle", err_count, ak_count, count);

    fclose (fp);
    return 0;
}


/*************************************************************************
** lkf_write_abtfile: Schreibt den Abteilungssummenfile                 **
*************************************************************************/

_SCORING_EXPORT int lkf_write_abtfile (const char *filename, LKF_CONTEXT *pContext, unsigned int kanr, int flags, char *error)
{
	FILE *fp;

	fp = fopen (filename, "w");
	if (!fp) {
		sprintf (error, "Abteilungs-File '%s' konnte nicht geoeffnet werden!", filename);
		return 2;
	}

	lkf_plaus_WriteAbtHeader (pContext,fp, kanr);
	lkf_plaus_WriteAbtFooter (pContext, fp, kanr);

	fclose (fp);

	return 0;
}

_SCORING_EXPORT unsigned int lkf_context_get_plaused_anz (const LKF_CONTEXT *pContext, unsigned int *worked)
{
	if (worked) *worked = pContext->plaus_work_count;
	return pContext->plaus_count;
}

_SCORING_EXPORT unsigned int lkf_context_get_scored_anz (const LKF_CONTEXT *pContext, unsigned int *worked)
{
	if (worked) *worked = pContext->scor_work_count;
	return pContext->scor_count;
}

_SCORING_EXPORT int lkf_context_getValue (const LKF_CONTEXT *pContext, unsigned int field)
{
    switch (field) {
        case 99:
            return pContext->executionCalled;
        case 11:
            return (int) pContext->scor_work_count;
        case 10:
            return (int) pContext->scor_count;
        case 21:
            return (int) pContext->plaus_work_count;
        case 20:
            return (int) pContext->plaus_count;
        default:
            return 0;
    }
}

/*********************************************************************************************
** count errors for package handling (V21.5)                                                **
*********************************************************************************************/

int lkf_context_count_error (LKF_CONTEXT *pContext, LKF_SATZART_ERROR *pError) {
    
    if (!pContext->pFullErrorCounters) {
        pContext->pFullErrorCounters = lkf_alloc_errorinfo (pContext, LKF_ERRORFILTER_ALL);
        if (!pContext->pFullErrorCounters) {
            return LKF_OUTOFMEMORY_ERROR;
        }
    }
    
    lkf_errorinfo_increment (pContext->pFullErrorCounters, pError->pErrorDef);
    
    if (pError->pErrorDef->nSeverity & (LKF_SEV_ERROR|LKF_SEV_FATAL))
        ++pContext->sumErrorCount;
    else if (pError->pErrorDef->nSeverity & LKF_SEV_WARNING)
        ++pContext->sumWarningCount;
    return 0;
}

/*********************************************************************************************
** Semaphore-Implementierung                                                                **
*********************************************************************************************/

static ALLOC_SEMAPHORE_CALLBACK cb_new = 0;
static SEMAPHORE_CALLBACK cb_enter = 0;
static SEMAPHORE_CALLBACK cb_leave = 0;
static SEMAPHORE_CALLBACK cb_delete = 0;
static void *global_semaphore = 0;

static ALLOC_SEMAPHORE_CALLBACK2 cb_new2 = 0;
static SEMAPHORE_CALLBACK2 cb_enter2 = 0;
static SEMAPHORE_CALLBACK2 cb_leave2 = 0;
static SEMAPHORE_CALLBACK2 cb_delete2 = 0;
static long global_semaphore2 = 0;




_SCORING_EXPORT void lkf_semaphore_callbacks (ALLOC_SEMAPHORE_CALLBACK sem_new, SEMAPHORE_CALLBACK sem_enter, SEMAPHORE_CALLBACK sem_leave, SEMAPHORE_CALLBACK sem_delete)
{
	cb_new = sem_new;
	cb_enter = sem_enter;
	cb_leave = sem_leave;
	cb_delete = sem_delete;

	if (!global_semaphore) global_semaphore = lkf_new_semaphore ();
}

_SCORING_EXPORT void lkf_semaphore_callbacks2 (ALLOC_SEMAPHORE_CALLBACK2 sem_new, SEMAPHORE_CALLBACK2 sem_enter, SEMAPHORE_CALLBACK2 sem_leave,
                                               SEMAPHORE_CALLBACK2 sem_delete) /* V2021.2 */
{
    cb_new2 = sem_new;
    cb_enter2 = sem_enter;
    cb_leave2 = sem_leave;
    cb_delete2 = sem_delete;

    if (!global_semaphore2) global_semaphore2 = lkf_new_semaphore2 ();
}

void *lkf_new_semaphore (void)
{
    if (cb_new) return cb_new ();
    else return (void *) 1;
}

long lkf_new_semaphore2 (void)
{
    if (cb_new2) return cb_new2 ();
    else return -1;
}

void lkf_enter_semaphore (void *sem)
{
	if (cb_enter) {
		if (!sem) sem = global_semaphore;
		cb_enter (sem);
	}
    else if (cb_enter2) {
        long s;
        if (!sem) s = global_semaphore2;
        else s = (long) sem;
        cb_enter2 (s);
    }
}

void lkf_leave_semaphore (void *sem)
{
	if (cb_leave) {
		if (!sem) sem = global_semaphore;
		cb_leave (sem);
	}
    else if (cb_leave2) {
        long s;
        if (!sem) s = global_semaphore2;
        else s = (long) sem;
        cb_leave2(s);
    }
}

void lkf_delete_semaphore (void *sem)
{
	if (cb_delete) {
		if (!sem) sem = global_semaphore;
		cb_delete (sem);
	}
    else if (cb_delete2) {
        long s;
        if (!sem) s = global_semaphore2;
        else s = (long) sem;
        cb_delete2(s);
    }
}

_SCORING_EXPORT const char  *lkf_GetVersion (void)
{ return LKF_VERSION; }

_SCORING_EXPORT void lkf_GetVersion2(char *versionString, unsigned int buflen) {
    strncpy (versionString, lkf_GetVersion(), buflen);
}


_SCORING_EXPORT unsigned int lkf_GetYearFirst (void)
{ return LKF_YEAR_FIRST; }

_SCORING_EXPORT unsigned int lkf_GetYearLatest (void)
{ return LKF_YEAR_LATEST; }


/****************************************************************************
** lkf_getaddlineanz: Anzahl Zeilen der zusätzlichen Satzarten (V8.1)      **
****************************************************************************/

_SCORING_EXPORT unsigned int lkf_getaddlineanz (LKF_CONTEXT *pContext)
{
	unsigned int linecount = 0;
	if (pContext->pLineBuffer) linecount = (unsigned int) pContext->pLineBuffer->lLineCount;
    if (pContext->pExpLineBuffer) linecount += pContext->pExpLineBuffer->lineCount; /* V22.5 */
	if (pContext->pErrorLineBuffer) linecount += pContext->pErrorLineBuffer->lLineCount;
	if (pContext->Count_S[10] == 0) linecount++; /* Summensatz hinzufuegen */
	return linecount;
}

/********************************************************************************************
** lkf_auf_getaddline: Liefert eine Zeile der zusätzlichen Satzarten                       **
********************************************************************************************/


_SCORING_EXPORT int lkf_getaddline (LKF_CONTEXT *pContext, unsigned int i, char *l) {
    return lkf_getaddlineAndIdent(pContext, i, l, 0);
}

_SCORING_EXPORT int lkf_getaddlineAndIdent (LKF_CONTEXT *pContext, unsigned int i, char *l, char *ident)
{
	if (pContext->pLineBuffer) {
		if (pContext->pLineBuffer->lLineCount > i) 
		{

			if (i + 1 == pContext->pLineBuffer->lLineCount)
			{
				if (pContext->nReplaceSummensatz)
				{
					lkf_context_getSummensatz (pContext, l, 800);
                    if (ident) {
                        strcpy (ident, "OLS");
                    }
					return 0;
				}
			}

			strcpy (l, pContext->pLineBuffer->pBuf + pContext->pLineBuffer->plOffsets[i]);
            if (ident) {
                sprintf (ident, "OLL:%d", i);
            }
			return 0;
		}
		else i -= pContext->pLineBuffer->lLineCount;
    }
    if (pContext->pExpLineBuffer) { /* V22.5 */
        if (pContext->pExpLineBuffer->lineCount > i)
        {
            const LKF_EXPANDED_LINE *pLine;
            if (i + 1 == pContext->pExpLineBuffer->lineCount)
            {
                if (pContext->nReplaceSummensatz)
                {
                    lkf_context_getSummensatz (pContext, l, 800);
                    if (ident) {
                        strcpy (ident, "XLS:sum");
                    }
                    return 0;
                }
            }
            pLine = pContext->pExpLineBuffer->lines[i];
            lkf_write_expLine(l, pLine);
            if (ident) {
                sprintf (ident, "XLL:%3.3s:%d", pLine->fields[0], i);
            }
            return 0;
        }
        else i -= pContext->pExpLineBuffer->lineCount;
    }

	if (pContext->Count_S[10] == 0)
	{
		if (i == 0) { 
			lkf_context_getSummensatz (pContext, l, 800);
            if (ident) {
                strcpy (ident, "SUM");
            }
			return 0;
		}
		else i--;
	}

    if (pContext->pErrorLineBuffer && pContext->pErrorLineBuffer->lLineCount > i) {
        strcpy (l, pContext->pErrorLineBuffer->pBuf + pContext->pErrorLineBuffer->plOffsets[i]);
        if (ident) {
            sprintf (ident, "ERR:%d", i);
        }
        return 0;
    }
	else l[0] = 0;
	return 0;
}


_SCORING_EXPORT int lkf_getaddlineWithIdent (LKF_CONTEXT *pContext, const char *ident, char *l) {
    
    
    if (!memcmp (ident, "XLL:", 4)) {
        unsigned int index = atoi (ident + 8);
        if (pContext->pExpLineBuffer->lineCount > index) {
            lkf_write_expLine(l, pContext->pExpLineBuffer->lines[index]);
            return 0;
        }
        return LKFCERROR_OUTOFBOUNDS;
    }
    
    if (!memcmp (ident, "AUF:", 4)) {
        LKF_AUFENTHALT *pAufenthalt = lkf_getAufenthaltFromLine (pContext, l);
        if (pAufenthalt) {
            return lkf_auf_getLineWithIdent(pAufenthalt, ident, l);
        }
        return LKFCERROR_NOCASE;
    }
    else if (!memcmp (ident, "INX:", 4)) {
        LKF_AUFENTHALT *pAufenthalt = lkf_getAufenthaltFromLine (pContext, l);
        if (pAufenthalt) {
            return lkf_auf_getIntLineWithIdent(pAufenthalt, ident, l);
        }
        return LKFCERROR_NOCASE;
    }
    
    return LKFCERROR_INVALIDID;
    
}

/********************************************************************************************
** lkf_write_datafile (V8.1):                                                              **
**         Erzeugt ein Output-Datenfile.                                                   **
********************************************************************************************/

_SCORING_EXPORT int lkf_write_datafile (LKF_CONTEXT *pContext, const char *filename, unsigned int filetype, unsigned int flags)
{
	unsigned int nAufenthaltAnz, i, j, nCount;
	LKF_AUFENTHALT *pAufenthalt;
	FILE *fp;
	char l[2048];


    fp = fopen (filename, "w");
    
	if (fp) {
        nCount = lkf_getaddlineanz (pContext);
        for (i = 0; i < nCount; i++)
        {
            lkf_getaddline (pContext, i, l);
            if (memcmp (l, "K01", 3))
                continue;
            fprintf (fp, "%s\n", l);
        }
        
        nAufenthaltAnz = lkf_get_aufenthalt_anz (pContext);
		
		for (i = 0; i < nAufenthaltAnz; i++) {
			pAufenthalt = lkf_get_aufenthalt (pContext, i);
			if (lkf_auf_is_marked(pAufenthalt)) 
			{	
				nCount = lkf_auf_getlineanz (pAufenthalt);
				for (j = 0; j < nCount; j++) {	
					lkf_auf_getline (pAufenthalt, j, l);
					fprintf (fp, "%s\n", l);	
				}

				nCount = lkf_auf_getintlineanz (pAufenthalt);
				for (j = 0; j < nCount; j++) 
				{
					lkf_auf_getintline (pAufenthalt, j, l);
					fprintf (fp, "%s\n", l);
				}
			}
		}

        nCount = lkf_getaddlineanz (pContext);
		for (i = 0; i < nCount; i++) 
		{
			lkf_getaddline (pContext, i, l);
            if (!memcmp (l, "K01", 3))
                continue;
			fprintf (fp, "%s\n", l);
		}
		fclose (fp);
		return 0;
	}
	else return 1;
}

/******************************************************************************************
** lkf_context_addimporterror (V8.1):                                                    **
**           Fügt einen beim Import entdeckten Fehler hinzu.                             **
******************************************************************************************/

extern const LKF_SATZART_ERRORDEF LKFErrorKAfalsch, LKFErrorKAfehlt, LKFErrorKAmultibel; /* V12.0 */

int lkf_context_addimporterrorEx (LKF_CONTEXT *pContext, unsigned int nLine, const SATZART_FELD *pFeld, const LKF_SATZART_ERRORDEF *pErrorDef, const SATZART_INFO *pSatzartInfo, const char *buf, long buflen)
{
	LKF_IMPORTERROR_STRUC *pImportError;

    if (nLine == LKF_OUTOFMEMORY_UINTERROR) return LKF_OUTOFMEMORY_ERROR;
    
	if (!lkf_getErrorRelevance (pErrorDef, pContext))
		return 0; /* V10.1: Error disabled */

    if (pErrorDef == &LKFErrorKAfalsch)
    {
        if (pContext->nHasFAT0) return 0;
        pContext->nHasFAT0 = 1;
    }
    else if (pErrorDef == &LKFErrorKAfehlt)
    {
        if (pContext->nHasFAT1) return 0;
        pContext->nHasFAT1 = 1;
    }
    else if (pErrorDef == &LKFErrorKAmultibel)
    {
        if (pContext->nHasFAT5) return 0;
        pContext->nHasFAT5 = 1;
    }
    
    if (++pContext->nSumImportErrors > LKF_MAX_IMPORTERRORS) return 0; /* nicht mehr als 100x wegen Memory-Problem bei grossen falschen Dateien */

	if (pContext->nImportErrorCount == pContext->nImportErrorAlloc)
	{
		pImportError = pContext->pImportError;

		pContext->nImportErrorAlloc += 100;
		pContext->pImportError = (LKF_IMPORTERROR_STRUC *) LKF_MALLOC (pContext, "lkf_context_addimporterrorEx", sizeof (LKF_IMPORTERROR_STRUC) * pContext->nImportErrorAlloc);
        if (!pContext->pImportError) {
            if (pImportError) LKF_FREE(pContext, "lkf_context_addimporterrorEx", pImportError);
            pContext->nInputErrorCount = pContext->nImportErrorAlloc = 0;
            return LKF_OUTOFMEMORY_ERROR;
        }
		if (pImportError) memcpy (pContext->pImportError, pImportError, sizeof (LKF_IMPORTERROR_STRUC) * pContext->nImportErrorCount);
	}
	pImportError = pContext->pImportError + (pContext->nImportErrorCount++);
	pImportError->nLine = nLine;
	pImportError->pErrorDef = pErrorDef;
	pImportError->pFeld = pFeld;
	pImportError->pSatzartInfo = pSatzartInfo;
    
    if (buf && buflen) {
        if (pFeld && pSatzartInfo) {
            long copylen = buflen > 25 ? 25 : buflen;
            sprintf (pImportError->text, "#%03d:", pSatzartInfo->feldIndex[pFeld->nFieldNum]);
            memcpy (pImportError->text + 5, buf, copylen);
            pImportError->text[copylen + 5] = 0;
        }
        else {
            long copylen = buflen > 30 ? 30 : buflen;
            memcpy (pImportError->text, buf, copylen);
            pImportError->text[copylen] = 0;
        }
    }
    else
        pImportError->text[0] = 0;
    return 0;
}

void lkf_context_addimporterror (LKF_CONTEXT *pContext, unsigned int nLine, const SATZART_FELD *pFeld, const LKF_SATZART_ERRORDEF *pErrorDef, const SATZART_INFO *pSatzartInfo) {
    lkf_context_addimporterrorEx(pContext, nLine, pFeld, pErrorDef, pSatzartInfo, 0, 0);
}

/**************************************************************************
** Routinen zum Zugriff auf besondere Satzarten                          **
**************************************************************************/

const SATZART_INFO *lkf_GetSatzartI (LKF_CONTEXT *pContext, unsigned int nNr)
{
	if (pContext->modelljahr > 2011 && (nNr != 11 && nNr != 12))
		return 0; /* V16.0: ab Modell 2012 nur mehr I11 und I12 gestattet */
	if ((pContext->modelljahr < 2011 || (nNr != 11 && nNr != 12))
		&& (nNr < 1 || nNr > MAX_I_SATZART_NUM)) return 0;
	if (!pContext->pSatzartDefs) pContext->pSatzartDefs = SatzartDef_Init (pContext->modelljahr);
	if (pContext->pSatzartDefs) return pContext->pSatzartDefs->ppI[nNr];
	else return 0;
}

const SATZART_INFO *lkf_GetSatzartK (LKF_CONTEXT *pContext, unsigned int nNr)
{
	if (nNr < 1 || nNr > MAX_K_SATZART_NUM) return 0;
	if (!pContext->pSatzartDefs) pContext->pSatzartDefs = SatzartDef_Init (pContext->modelljahr);
	if (pContext->pSatzartDefs) return pContext->pSatzartDefs->ppK[nNr];
	else return 0;
}

const SATZART_INFO *lkf_GetSatzartB (LKF_CONTEXT *pContext, unsigned int nNr)
{
	if (nNr < 1 || nNr > MAX_B_SATZART_NUM) return 0;
	if (!pContext->pSatzartDefs) pContext->pSatzartDefs = SatzartDef_Init (pContext->modelljahr);
	if (pContext->pSatzartDefs && pContext->pSatzartDefs->ppB) return pContext->pSatzartDefs->ppB[nNr];
	else return 0;
}

const SATZART_INFO *lkf_GetSatzartG (LKF_CONTEXT *pContext, unsigned int nNr)
{
	if (nNr < 1 || nNr > MAX_G_SATZART_NUM) return 0;
	if (!pContext->pSatzartDefs) pContext->pSatzartDefs = SatzartDef_Init (pContext->modelljahr);
	if (pContext->pSatzartDefs) return pContext->pSatzartDefs->ppG[nNr];
	else return 0;	
}

const SATZART_INFO *lkf_GetSatzartL (LKF_CONTEXT *pContext, unsigned int nNr)
{
	if (nNr < 1 || nNr > MAX_L_SATZART_NUM) return 0;
	if (!pContext->pSatzartDefs) pContext->pSatzartDefs = SatzartDef_Init (pContext->modelljahr);
	if (pContext->pSatzartDefs) return pContext->pSatzartDefs->ppL[nNr];
	else return 0;
}

const SATZART_INFO *lkf_GetSatzartL01Internal (LKF_CONTEXT *pContext) /* V17.0 */
{
	if (!pContext->pSatzartDefs) pContext->pSatzartDefs = SatzartDef_Init (pContext->modelljahr);
	if (pContext->pSatzartDefs) return pContext->pSatzartDefs->pL01Internal;
	else return 0;
}

const SATZART_INFO *lkf_GetSatzartS (LKF_CONTEXT *pContext, unsigned int nNr)
{
	if (nNr < 1 || nNr > MAX_S_SATZART_NUM) return 0;
	if (!pContext->pSatzartDefs) pContext->pSatzartDefs = SatzartDef_Init (pContext->modelljahr);
	if (pContext->pSatzartDefs) return pContext->pSatzartDefs->ppS[nNr];
	else return 0;
}

/*******************************************************************************************
** lkf_context_getSummensatz:                                                             **
**      Erzeugt den Summensatz.                                                           **
*******************************************************************************************/

static unsigned int lkf_add_counter_to_buffer (char *sBuf, const unsigned int *pCounter, unsigned int nCount)
{
	unsigned int nPos, i;
	nPos = 0;
	for (i = 0; i < nCount; i++)
	{
		nPos += (unsigned int) sprintf (sBuf + nPos, "%10d", pCounter[i]);
	}
	return nPos;
}


static unsigned int lkf_xline_getSummensatz (LKF_CONTEXT *pContext, char *sBuf, unsigned int nBufLen)
{
    unsigned int nCount, i, nIntCount;
    unsigned int nMarkCount;                  /* V13.0 */
    unsigned int aMCounts[MAX_M_SATZART_NUM]; /* V13.0 */
    unsigned int aICounts[MAX_I_SATZART_NUM]; /* V13.0 */
    
    const SATZART_INFO *summenSatz = lkf_GetSatzartS(pContext, 11);
    
    int feldIndices[100];
    const char *feldWerte[100];
    char buf[1024];
    char sLocalBuf[1024];
    
    int bufpos = 0;
    
    feldWerte[0] = buf;
    feldIndices[0] = GEN_JAHR;
    bufpos += sprintf (buf, "%4.4d", pContext->cmb_jahr) + 1;
    
    feldWerte[1] = buf + bufpos;
    feldIndices[1] = GEN_KANR;
    bufpos += sprintf(buf + bufpos, "%4.4s", pContext->KANR) + 1;
    
    nCount = nMarkCount = 0;
    
    for (i = 0; i < pContext->patient_anz; i++)
    {
        if (pContext->ppAufenthalt[i]->status & 2) nCount++;
        if (pContext->ppAufenthalt[i]->mark & 1) nMarkCount++;
    }
    
    if (pContext->patient_anz == nMarkCount) {
        memcpy (aMCounts, pContext->Count_X, sizeof (unsigned int) * 7);
        memcpy (aICounts, pContext->Count_I, sizeof (unsigned int) * 2);
    }
    else
    { /* V13.0 */
        LKF_AUFENTHALT *pAufenthalt;
        for (i = 0; i < 7; i++) aMCounts[i] = 0;
        for (i = 0; i < 2; i++) aICounts[i] = 0;
        for (i = 0; i < pContext->patient_anz; i++)
        {
            pAufenthalt = pContext->ppAufenthalt[i];
            if (!(pAufenthalt->mark & 1))
                continue;
            aMCounts[0]++;
            aMCounts[1] += lkf_auf_get_abtanz (pAufenthalt);
            aMCounts[2] += lkf_auf_get_diaganz (pAufenthalt);
            aMCounts[3] += lkf_auf_get_melanz (pAufenthalt);
            aMCounts[4]++;
            aMCounts[5] += lkf_auf_get_akwarnanz (pAufenthalt);
            aMCounts[6] += lkf_auf_get_kommentaranz (pAufenthalt);
        }
        
        nIntCount = lkf_int_getIntAufenthaltCount (pContext);
        
        for (i = 0; i < nIntCount; i++)
        {
            pAufenthalt = lkf_int_getAufenthalt (pContext, i);
            if (!(pAufenthalt->mark & 1))
                continue;
            aICounts[0] += lkf_int_getIntAufenthaltSAPSCount (pContext, i);  /* I11 */
            aICounts[1] += lkf_int_getIntAufenthaltTISSCount (pContext, i);  /* I12 */
        }
        
    }

    for (i = 0; i < 7; i++) {
        feldWerte[2 + i] = buf + bufpos;
        feldIndices[2 + i] = (int) (S01_ANZAHL_M + 1 + i);
        bufpos += sprintf(buf + bufpos, "%10d", aMCounts[i]) + 1;
    }

    for (i = 0; i < 2; i++) {
        feldWerte[9 + i] = buf + bufpos;
        feldIndices[9 + i] = (int) (S01_ANZAHL_I + 1 + i);
        bufpos += sprintf(buf + bufpos, "%10d", aICounts[i]) + 1;
    }

    for (i = 0; i < 4; i++) {
        feldWerte[11 + i] = buf + bufpos;
        feldIndices[11 + i] = (int) (S01_ANZAHL_L + 1 + i);
        bufpos += sprintf(buf + bufpos, "%10d", pContext->Count_L[i]) + 1;
    }
    
    feldWerte[15] = feldWerte[16] = feldWerte[17] = "0";
    feldIndices[15] = S11_E01;
    feldIndices[16] = S11_P01;
    feldIndices[17] = S11_P02;
    
    for (i = 0; i < 16; i++) {
        feldWerte[18 + i] = buf + bufpos;
        feldIndices[18 + i] = (int) (S01_ANZAHL_K + 1 + i);
        bufpos += sprintf(buf + bufpos, "%10d", pContext->Count_K[i]) + 1;
    }

    for (i = 0; i < 2; i++) {
        feldWerte[34 + i] = buf + bufpos;
        feldIndices[34 + i] = (int) (S01_ANZAHL_G + 1 + i);
        bufpos += sprintf(buf + bufpos, "%10d", pContext->Count_G[i]) + 1;
    }

    for (i = 0; i < 6; i++) {
        feldWerte[36 + i] = buf + bufpos;
        feldIndices[36 + i] = (int) (S11_ANZAHL_B + 1 + i);
        bufpos += sprintf(buf + bufpos, "%10d", pContext->Count_B[i]) + 1;
    }
    
    feldWerte[42] = buf + bufpos;
    feldIndices[42] = S01_ANZAHL_FEHLER;
    bufpos += sprintf (buf + bufpos, "%10d", pContext->sumErrorCount) + 1;

    feldWerte[43] = buf + bufpos;
    feldIndices[43] = S01_ANZAHL_WARNINGS;
    bufpos += sprintf (buf + bufpos, "%10d", pContext->sumWarningCount) + 1;
    
    feldWerte[44] = buf + bufpos;
    feldIndices[44] = S01_PUNKTE_LDF_LEIST;
    bufpos += sprintf (buf + bufpos, "%10d", (unsigned int) pContext->ka[0].LDFPLK) + 1;
    
    feldWerte[45] = buf + bufpos;
    feldIndices[45] = S01_PUNKTE_LDF_TAG;
    bufpos += sprintf (buf + bufpos, "%10d", (unsigned int) pContext->ka[0].LDFPTK) + 1;

    feldWerte[46] = buf + bufpos;
    feldIndices[46] = S01_PUNKTE_BELAG_UNTEN_LEIST;
    bufpos += sprintf (buf + bufpos, "%10d", (unsigned int) pContext->ka[0].SCULK) + 1;
    
    feldWerte[47] = buf + bufpos;
    feldIndices[47] = S01_PUNKTE_BELAG_UNTEN_TAG;
    bufpos += sprintf (buf + bufpos, "%10d", (unsigned int) pContext->ka[0].SCUTK) + 1;
    
    feldWerte[48] = buf + bufpos;
    feldIndices[48] = S01_ZUSATZPUNKTE_BELAG_OBEN;
    bufpos += sprintf (buf + bufpos, "%10d", (unsigned int) pContext->ka[0].VDZU) + 1;
    
    feldWerte[49] = buf + bufpos;
    feldIndices[49] = S01_ZUSATZPUNKTE_INTENSIV;
    bufpos += sprintf (buf + bufpos, "%10d", (unsigned int) pContext->ka[0].INTZU) + 1;

    feldWerte[50] = buf + bufpos;
    feldIndices[50] = S01_ZUSATZPUNKTE_MEHRFACH_MEL;
    bufpos += sprintf (buf + bufpos, "%10d", (unsigned int) pContext->ka[0].MELZU) + 1;
    
    feldWerte[51] = buf + bufpos;
    feldIndices[51] = S01_PUNKTE_SPEZ;
    bufpos += sprintf (buf + bufpos, "%10d", (unsigned int) pContext->ka[0].SCSPEZ) + 1;

    feldWerte[52] = buf + bufpos;
    feldIndices[52] = S01_PUNKTE_TOT_INNERHALB_LKF;
    bufpos += sprintf (buf + bufpos, "%10d", (unsigned int) pContext->ka[0].SCGES_INLKF_TKL) + 1;
    
    feldWerte[53] = buf + bufpos;
    feldIndices[53] = S01_PUNKTE_TOT_AUSSERHALB_LKF;
    bufpos += sprintf (buf + bufpos, "%10d", (unsigned int) pContext->ka[0].SCGES_EXLKF_TKL) + 1;
    
    feldWerte[54] = "";
    feldIndices[54] = S01_KOMMENTAR;
    
    feldWerte[55] = "0";
    feldIndices[55] = S11_A01;
    
    lkf_write_satzart(pContext, summenSatz, 55, feldIndices, feldWerte, 0, sLocalBuf);
    
    strncpy (sBuf, sLocalBuf, nBufLen);
    return (unsigned int) strlen (sBuf);
}

_SCORING_EXPORT unsigned int lkf_context_getSummensatz (LKF_CONTEXT *pContext, char *sBuf, unsigned int nBufLen)
{
	char sLocalBuf[1024];
	unsigned int nCount, nPos, i, nIntCount;
	unsigned int nErrorCount, nWarningCount;
	unsigned int nMarkCount;                  /* V13.0 */
	unsigned int aMCounts[MAX_M_SATZART_NUM]; /* V13.0 */
	unsigned int aICounts[MAX_I_SATZART_NUM]; /* V13.0 */

    if (pContext->modelljahr >= 2017) {
        return lkf_xline_getSummensatz (pContext, sBuf, nBufLen);
    }
    
    
	nPos = (unsigned int) sprintf (sLocalBuf, "S%s%4d%-6.6s%c%03d%02d", pContext->modelljahr >= 2012 ? "11" : "01",
				pContext->cmb_jahr, pContext->KANR, pContext->period_type, pContext->period_val, pContext->lfdnr);


	nCount = nMarkCount = 0;
	for (i = 0; i < pContext->patient_anz; i++)
	{
		if (pContext->ppAufenthalt[i]->status & 2) nCount++;
		if (pContext->ppAufenthalt[i]->mark & 1) nMarkCount++;
	}

	if (pContext->patient_anz == nMarkCount)
		nPos += lkf_add_counter_to_buffer (sLocalBuf + nPos, pContext->Count_M, 5);
	else
	{ /* V13.0 */
		LKF_AUFENTHALT *pAufenthalt;
		for (i = 0; i < MAX_M_SATZART_NUM; i++) aMCounts[i] = 0;
		for (i = 0; i < MAX_I_SATZART_NUM; i++) aICounts[i] = 0;	
		for (i = 0; i < pContext->patient_anz; i++)
		{
			pAufenthalt = pContext->ppAufenthalt[i];
			if (!(pAufenthalt->mark & 1))
				continue;
			aMCounts[0] ++;
			aMCounts[1] += lkf_auf_get_abtanz (pAufenthalt);
			aMCounts[2] += lkf_auf_get_diaganz (pAufenthalt);
			aMCounts[3] += lkf_auf_get_melanz (pAufenthalt);
			aMCounts[4] += lkf_auf_get_kostanz (pAufenthalt);
			aMCounts[6] += lkf_auf_get_akwarnanz (pAufenthalt);
			aMCounts[7] += lkf_auf_get_kommentaranz (pAufenthalt);
		}
		nPos += lkf_add_counter_to_buffer (sLocalBuf + nPos, aMCounts, 5);
		
		nIntCount = lkf_int_getIntAufenthaltCount (pContext);

		for (i = 0; i < nIntCount; i++)
		{
			pAufenthalt = lkf_int_getAufenthalt (pContext, i);
			if (!(pAufenthalt->mark & 1))
				continue;
			aICounts[0] += lkf_int_getIntAufenthaltSAPSCount (pContext, i);  /* I01 oder I11 */
			aICounts[1] += lkf_int_getIntAufenthaltTISSCount (pContext, i);  /* I02 oder I12 */
			aICounts[2] += lkf_int_getIntAufenthaltTRISSCount (pContext, i); /* I03 bzw. 0 ab 2012 */
		}

	}

	nErrorCount = 0;
	nWarningCount = 0;
	if (pContext->pSatzartErrors && pContext->pSatzartErrors->nCount) 
	{
		const LKF_SATZART_ERROR *pError;
		for (i = 0; i < pContext->pSatzartErrors->nCount; i++)
		{
			pError = pContext->pSatzartErrors->pErrors + i;
			if (pError->pErrorDef) 
			{
				unsigned int nSev = lkf_getSeverity (pContext, pError->pErrorDef);
				if (nSev & LKF_SEV_WARNING) 
					++nWarningCount;
				else if ((nSev & LKF_SEV_ERROR) || (nSev & LKF_SEV_FATAL))
					++nErrorCount;
			}
		}
	}

	if (pContext->patient_anz == nMarkCount)
	{
		nPos += (unsigned int) sprintf (sLocalBuf + nPos, "%10d%10d%10d", nCount, pContext->Count_M[6], pContext->Count_M[7]); /* falsche Counter 7/8 auf 6/7 korrigiert */
	
		if (pContext->modelljahr >= 2011)
		{
			aICounts[0] = pContext->Count_I[0] + pContext->Count_I[10];
			aICounts[1] = pContext->Count_I[1] + pContext->Count_I[11];
			aICounts[2] = 0;
            nPos += lkf_add_counter_to_buffer (sLocalBuf + nPos, aICounts, MAX_I_SATZART_NUM); /* V20.1 */
		}
		else
			nPos += lkf_add_counter_to_buffer (sLocalBuf + nPos, pContext->Count_I, MAX_I_SATZART_NUM);
	}
	else
	{
		nPos += (unsigned int) sprintf (sLocalBuf + nPos, "%10d%10d%10d", nCount, aMCounts[6], aMCounts[7]);
		nPos += lkf_add_counter_to_buffer (sLocalBuf + nPos, aICounts, MAX_I_SATZART_NUM);
	}
	nPos += lkf_add_counter_to_buffer (sLocalBuf + nPos, pContext->Count_L, MAX_L_SATZART_NUM);
	nPos += lkf_add_counter_to_buffer (sLocalBuf + nPos, pContext->Count_K, MAX_K_SATZART_NUM);
	nPos += lkf_add_counter_to_buffer (sLocalBuf + nPos, pContext->Count_G, MAX_G_SATZART_NUM);
	/* nPos += lkf_add_counter_to_buffer (sLocalBuf + nPos, pContext->Count_B, MAX_B_SATZART_NUM);  V14.2, entfernt V20.1 */

	nPos += (unsigned int) sprintf (sLocalBuf + nPos, "%10d%10d", nErrorCount, nWarningCount);
	if (pContext->ka_gesamt > 0) 
	{
		nPos += (unsigned int) sprintf (sLocalBuf + nPos, "%10d%10d%10d%10d%10d%10d%10d%10d%10d%10d",
						 (unsigned int) pContext->ka[0].LDFPLK, (unsigned int) pContext->ka[0].LDFPTK,
						 (unsigned int) pContext->ka[0].SCULK, (unsigned int) pContext->ka[0].SCUTK,
						 (unsigned int) pContext->ka[0].VDZU, (unsigned int) pContext->ka[0].INTZU,
						 (unsigned int) pContext->ka[0].MELZU, (unsigned int) pContext->ka[0].SCSPEZ,
						 (unsigned int) pContext->ka[0].SCGES_INLKF_TKL, (unsigned int) pContext->ka[0].SCGES_EXLKF_TKL);
	}
	else 
	{
		nPos += (unsigned int) sprintf (sLocalBuf + nPos, "%10d%10d%10d%10d%10d%10d%10d%10d%10d%10d", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
	}

	strncpy (sBuf, sLocalBuf, nBufLen);
	if (nPos >= nBufLen) sLocalBuf[nBufLen-1] = 0;
	return nPos;
}

_SCORING_EXPORT const char *lkf_get_context_error (const LKF_CONTEXT *pContext)
{
	return pContext->errortext;
}

LKF_CONTEXT_ABTEILUNG *lkf_context_add_abteilung (LKF_CONTEXT *pContext, const char *sAbtFC, const char *sKst, const char *sKANR6 /* V11.1 */)
{ /* V11.0 - caching von Abteilungsspezifischen Informationen */
	LKF_CONTEXT_ABTEILUNG *pAbt;
	if (pContext->nAbtAlloc == pContext->nAbtAnz)
	{
		LKF_CONTEXT_ABTEILUNG *pOld = pContext->pAbt;
		pContext->nAbtAlloc += 10;
		pContext->pAbt = (LKF_CONTEXT_ABTEILUNG *) LKF_CALLOC (pContext, "lkf_context_add_abteilung", pContext->nAbtAlloc, sizeof (LKF_CONTEXT_ABTEILUNG));
        if (!pContext->pAbt) {
            pContext->nAbtAnz = pContext->nAbtAlloc = 0;
            if (pOld) LKF_FREE (pContext, "lkf_context_add_abteilung", pOld);
            return 0;
        }
		if (pOld)
		{
			memcpy (pContext->pAbt, pOld, sizeof (LKF_CONTEXT_ABTEILUNG) * pContext->nAbtAnz);
            LKF_FREE (pContext, "lkf_context_add_abteilung", pOld);
		}
	}
	pAbt = pContext->pAbt + pContext->nAbtAnz;
	pAbt->nEintrag = pContext->nAbtAnz++;
	strncpy (pAbt->sAbtFC, sAbtFC, 8);
	pAbt->sAbtFC[8] = 0;
	strncpy (pAbt->sKst8, sKst, 8); /* V2021.1 */
	pAbt->sKst8[8] = 0; /* V2021.1 */
	strncpy (pAbt->sKANR6, sKANR6, 6);
	pAbt->sKANR6[6] = 0;
	return pAbt;
}

static int context_abteilung_compare (const void *a1, const void *a2)
{

	return strcmp ( ((const LKF_CONTEXT_ABTEILUNG *)a1)->sAbtFC,
					((const LKF_CONTEXT_ABTEILUNG *)a2)->sAbtFC);
}

static int context_abteilung_find_compare (const void *c, const void *a1)
{
	return strncmp ((const char *)c, ((const LKF_CONTEXT_ABTEILUNG *)a1)->sAbtFC, 8);
}

void lkf_context_sort_abteilungen (LKF_CONTEXT *pContext)
{ /* V11.0 */
	if (pContext->pAbt)
	{
		qsort (pContext->pAbt, pContext->nAbtAnz, sizeof (LKF_CONTEXT_ABTEILUNG), context_abteilung_compare);
	}
}

LKF_CONTEXT_ABTEILUNG *lkf_context_find_abteilung (const LKF_CONTEXT *pContext, const char *sAbtFC)
{ /* V11.0 */
	if (pContext->pAbt)
		return (LKF_CONTEXT_ABTEILUNG *) bsearch (sAbtFC, pContext->pAbt, pContext->nAbtAnz, sizeof (LKF_CONTEXT_ABTEILUNG), context_abteilung_find_compare);
	else
		return 0;
}

_SCORING_EXPORT int lkf_context_GetGlobalInfo (const LKF_CONTEXT *pContext, unsigned int nType)
{ /* V14.2 */
	switch (nType)
	{
		case LKF_CONTEXTINFO_KTR:
			if (pContext->isKTR)
				return 1;
			return 0;
		default:
			return 0;
	}
}

_SCORING_EXPORT int lkf_context_getModellJahr (const LKF_CONTEXT *pContext) {
    return pContext->modelljahr;
}

_SCORING_EXPORT int lkf_context_getutf8mode (const LKF_CONTEXT *pContext) {
    return pContext->utf8_mode;
}

unsigned int lkf_numberOf2ByteCharaters (const LKF_CONTEXT *pContext, const char *utf8Text)
{ /* V21.0 */
    const char *pos = utf8Text;
    unsigned int count = 0;
    while (*pos) {
        if (*(pos++) == (const char) -61) count++;
    }
    return count;
}

const char *lkf_context_formatted_text (const LKF_CONTEXT *pContext, const char *utf8Text, char *buf) {
    
    const char *nextpos, *curpos = utf8Text;
    char *destbuf = buf;
    
    if (!pContext || pContext->utf8_mode)
        return utf8Text;
    do {
        nextpos = strchr(curpos, -61 /* =x3 */);
        if (nextpos) {
            memcpy (destbuf, curpos, nextpos - curpos);
            destbuf += (nextpos - curpos);
            *destbuf++ = *++nextpos + 0x40;
            curpos = nextpos + 1;
        }
    } while (nextpos);
    
    if (*curpos) {
        strcpy (destbuf, curpos);
    }
    return buf;
}

static void lkf_free_context_datfile (LKF_CONTEXT *pContext, LKF_CONTEXT_DATFILE *pDatFile)
{
    LKF_FREE (pContext, "lkf_free_context_datfile", pDatFile->lineOffsets);
    LKF_FREE (pContext, "lkf_free_context_datfile", pDatFile->buf);
    LKF_FREE (pContext, "lkf_free_context_datfile", pDatFile);
}


_SCORING_EXPORT unsigned int lkf_context_read_dat (LKF_CONTEXT *pContext, const char *fileName)
{ /* V21.2 */
    STAMM_FILE *fp;
    LKF_CONTEXT_DATFILE *pDatFile;
    char *buf;
    unsigned int *lineOffsets;
    unsigned int buf_alloc, buf_pos;
    unsigned int line_alloc, line_count;
    
    char line[2048];
    unsigned int lineLen;
    
    
    if (pContext->pDatFile)
    {
        lkf_free_context_datfile(pContext, pContext->pDatFile);
        pContext->pDatFile = 0;
    }
    
    if (!pContext->pStamm2001)
        return 0;
    
    fp = lkf_stamm_open (pContext->pStamm2001, fileName, 0);
    if (!fp->fp && !fp->fileContent) {
        lkf_stamm_close(fp);
        return 0;
    }
    
    buf_alloc = 100000;
    line_alloc = 1000;
    buf = (char *) LKF_MALLOC (pContext, "lkf_context_read_dat", buf_alloc);
    if (!buf) return LKF_OUTOFMEMORY_UINTERROR;
    
    lineOffsets = (unsigned int *) LKF_CALLOC(pContext, "lkf_context_read_dat.lines", line_alloc, sizeof (unsigned int));
    if (!lineOffsets) {
        LKF_FREE(pContext, "lkf_context_read_dat", buf);
        return LKF_OUTOFMEMORY_UINTERROR;
    }
    buf_pos = 0;
    line_count = 0;
    
    while (lkf_stamm_line(line, sizeof(line), fp))
    {
        if (line_alloc == line_count)
        {
            unsigned int *oldOffsets = lineOffsets;
            line_alloc += 1000;
            lineOffsets = (unsigned int *) LKF_CALLOC(pContext, "lkf_context_read_dat.lines", line_alloc, sizeof (unsigned int));
            if (!lineOffsets) {
                LKF_FREE(pContext, "lkf_context_read_dat", buf);
                LKF_FREE (pContext, "lkf_context_read_dat", oldOffsets);
                return LKF_OUTOFMEMORY_UINTERROR;
            }
            memcpy (lineOffsets, oldOffsets, sizeof (unsigned int) * line_count);
            LKF_FREE (pContext, "lkf_context_read_dat", oldOffsets);
        }
        
        lineLen = (unsigned int) strlen (line);
        
        if (buf_pos + lineLen + 1 > buf_alloc) {
            char *oldBuf = buf;
            buf_alloc += 100000;
            buf = (char *) LKF_MALLOC (pContext, "lkf_context_read_dat", buf_alloc);
            if (!buf) {
                LKF_FREE (pContext, "lkf_context_read_dat", oldBuf);
                LKF_FREE (pContext, "lkf_context_read_dat", lineOffsets);
                return LKF_OUTOFMEMORY_UINTERROR;
            }
            memcpy (buf, oldBuf, buf_pos);
            LKF_FREE (pContext, "lkf_context_read_dat", oldBuf);
        }
        
        lineOffsets[line_count++] = buf_pos;
        strcpy (buf + buf_pos, line);
        buf_pos += lineLen + 1;
    }
    
    pDatFile = (LKF_CONTEXT_DATFILE *) LKF_MALLOC (pContext, "lkf_context_read_dat", sizeof (LKF_CONTEXT_DATFILE));
    if (!pDatFile) {
        LKF_FREE (pContext, "lkf_context_read_dat", buf);
        LKF_FREE (pContext, "lkf_context_read_dat", lineOffsets);
        return LKF_OUTOFMEMORY_UINTERROR;
    }
    pDatFile->buf = buf;
    pDatFile->lineCount = line_count;
    pDatFile->lineOffsets = lineOffsets;
    strcpy (pDatFile->fileName, fileName);
    pContext->pDatFile = pDatFile;
    
	lkf_stamm_close(fp);
    return line_count;
}

_SCORING_EXPORT const char *lkf_context_dat_line (LKF_CONTEXT *pContext, unsigned int lineIndex)
{ /* V21.2 */
    if (!pContext->pDatFile || lineIndex >= pContext->pDatFile->lineCount)
        return 0;
    return pContext->pDatFile->buf + pContext->pDatFile->lineOffsets[lineIndex];
}

_SCORING_EXPORT void lkf_context_free_dat (LKF_CONTEXT *pContext)
{ /* V21.2 */
    if (pContext->pDatFile)
    {
        lkf_free_context_datfile(pContext, pContext->pDatFile);
        pContext->pDatFile = 0;
    }
}


_SCORING_EXPORT LKF_CONTEXT * lkf_alloc_context2 (unsigned int modelljahr, const char *input_path, STAMM_ADD_LINE_FUNC func, char *error)
{
    LKF_CONTEXT *pContext = lkf_alloc_context(0, 0, error);
    if (!pContext) {
        return 0;
    }
    pContext->stammAddLineFunc = func;
    lkf_set_modelljahr(pContext, modelljahr, input_path, error);
    return pContext;
}

_SCORING_EXPORT LKF_CONTEXT * lkf_alloc_context3 (unsigned int modelljahr, const char *input_path, STAMM_FILE_PATH_FUNC pathFunc, STAMM_ADD_LINE_FUNC addLineFunc, char *error) {
    LKF_CONTEXT *pContext = lkf_alloc_context(0, 0, error);
    if (!pContext) {
        return 0;
    }
    pContext->stammFilePathFunc = pathFunc;
    pContext->stammAddLineFunc = addLineFunc;
    pContext->privateStamm = 1;
    lkf_set_modelljahr(pContext, modelljahr, input_path, error);
    return pContext;
}

_SCORING_EXPORT LKF_CONTEXT * lkf_alloc_context_stamm (LKF_METADATA *pStamm, STAMM_FILE_PATH_FUNC pathFunc, STAMM_ADD_LINE_FUNC addLineFunc, char *error) {
    LKF_CONTEXT *pContext = lkf_alloc_context(0, 0, error);
    if (!pContext) {
        return 0;
    }
    pContext->stammFilePathFunc = pathFunc;
    pContext->stammAddLineFunc = addLineFunc;
    pContext->privateStamm = 2;
    lkf_set_modelljahr_stamm (pContext, pStamm);
    *error = 0;
    return pContext;
}


int lkf_has_k01 (LKF_CONTEXT *pContext, const char *abtfc)
{ /* V2019.1 */
    if (!pContext->pAbt)
        return 2;
    return lkf_context_find_abteilung(pContext, abtfc) ? 1 : 0;
}

_SCORING_EXPORT unsigned int lkf_get_contextvalue(LKF_CONTEXT *pContext, int nr) {
	switch (nr) {
	case 0:
		return pContext->importedILines;
	case 1:
		return pContext->failedILines;
	case 2:
		return pContext->zuordnungILine;
	default:
		return 0;
	}
}

_SCORING_EXPORT int lkf_context_set_modelparameter (LKF_CONTEXT *pContext, int parameterId, const char *value) {
    switch (parameterId) {
        case LKF_CONTEXT_MODELPARAMETER_TKLFACTOR:
            return 1;
        default:
            return 2;
    }
}

_SCORING_EXPORT long long lkf_get_melLongKey (LKF_CONTEXT *pContext, const char *mel)
{ /* V2022.1 */
    char buf[8];
    long long *longValue = (long long *) buf;
    *longValue = 0;
    strncpy (buf, mel, 5);
    return *longValue;
}

_SCORING_EXPORT long long lkf_get_diagLongKey (LKF_CONTEXT *pContext, const char *diag)
{ /* V2022.1 */
    char buf[8];
    long long *longValue = (long long *) buf;
    *longValue = 0;
    strncpy (buf, diag, 4);
    if (diag[3] && diag[4] && diag[4] != ' ') {
        buf[4] = diag[4];
        if (diag[5] && diag[5] != ' ') {
            buf[5] = diag[5];
        }
    }
    return *longValue;
}

_SCORING_EXPORT LKF_ANONYMISATION_CONTEXT *lkf_create_anonymisation_context (LKF_CONTEXT *pTargetContext, const char *parameters) {
    LKF_ANONYMISATION_CONTEXT *pAContext;
    LKF_COMMANDS *pCommands;
    LKF_COMMAND *pCommand;
    
    pCommands = lkfcommand_alloc(pTargetContext, parameters);
    if (!pCommands) return 0;
    
    pAContext = (LKF_ANONYMISATION_CONTEXT *) LKF_MALLOC (pTargetContext, "lkf_create_anonymisation_context", sizeof (LKF_ANONYMISATION_CONTEXT));
    if (!pAContext) {
        lkfcommand_free(pCommands);
        return 0;
    }
    
    memchr(pAContext, 0, sizeof (LKF_ANONYMISATION_CONTEXT));
    pAContext->targetContext = pTargetContext;
    
    if ((pCommand = lkfcommand_get(pCommands, "keepkey"))) {
        pAContext->nextKey = 0;
    }
    else if ((pCommand = lkfcommand_get(pCommands, "nextkey"))) {
        pTargetContext->flags &= ~1;
        pTargetContext->isBM = 0;
        if (pCommand->value[0]) {
            pAContext->nextKey = atoi(pCommand->value);
        }
        else {
            pAContext->nextKey = 100000;
        }
    }
    else {
        pTargetContext->flags &= ~1;
        pTargetContext->isBM = 0;
        pAContext->nextKey = 100000;
    }
    
    if ((pCommand = lkfcommand_get(pCommands, "addyears"))) {
        pAContext->aufaddyears = atoi(pCommand->value);
    }
    
    if ((pCommand = lkfcommand_get(pCommands, "dates"))) {
        if (!strcmp (pCommand->value, "off")) {
            pAContext->dates = 0;
        }
        else {
            pAContext->dates = atoi (pCommand->value);
        }
    }
    else {
        pAContext->dates = 1;
    }
    
    if ((pCommand = lkfcommand_get(pCommands, "statToAmb"))) {
        pAContext->statToAmb = atoi (pCommand->value);
    }
    if ((pCommand = lkfcommand_get(pCommands, "ambToStat"))) {
        pAContext->ambToStat = atoi (pCommand->value);
    }
    
    srand((unsigned int)time(0));

    if ((pCommand = lkfcommand_get(pCommands, "kanr"))) {
        strncpy (pAContext->KANR, pCommand->value, 6);
        pAContext->KANR[6] = 0;
        strncpy (pAContext->targetContext->KANR, pCommand->value, 6);
        pAContext->targetContext->KANR[6] = 0;
    }
    else {
        pAContext->KANR[0] = 0;
        pAContext->targetContext->KANR[0] = 0;
    }
    
    if ((pCommand = lkfcommand_get(pCommands, "allKK")) && !strcmp (pCommand->value, "false")) {
        pAContext->k01only = 0;
    }
    else {
        pAContext->k01only = 1;
    }
    
    if (!(pCommand = lkfcommand_get(pCommands, "stamm")) || strcmp (pCommand->value, "off")) {
        strcpy (pAContext->STAATB, "AT");
        strcpy (pAContext->STAATW, "AT");
        strcpy (pAContext->GEMCODE, "90201");
        strcpy (pAContext->PLZW, "1020");
    }
    lkfcommand_free(pCommands);
    return pAContext;
}

static void lkf_replace_kanr (char *line, const char *source, const char *target) {
    char *nextpos;
    unsigned int l;
    l = (unsigned int) strlen (source);
    if (l == 0) {
        return;
    }
    nextpos = line;
    while ((nextpos = strstr(nextpos, source))) {
        memcpy (nextpos, target, l);
        nextpos = nextpos + 4;
    }
}

static void lkf_replace_year (char *line, const char *source, const char *target) {
    char *nextpos;
    unsigned int l;
    l = (unsigned int) strlen (source);
    if (l == 0) {
        return;
    }
    nextpos = line;
    while ((nextpos = strstr(nextpos, source))) {
        memcpy (nextpos, target, l);
        nextpos = nextpos + 6;
    }
}
#define LKF_COPYADDLINE_K01      1
#define LKF_COPYADDLINE_K        2
#define LKF_COPYADDLINE_L        4
#define LKF_COPYADDLINE_B        8
#define LKF_COPYADDLINE_ADDL01  16
#define LKF_COPYADDLINE_ADDL02  32
#define LKF_COPYADDLINE_ADDL03  64
#define LKF_COPYADDLINE_ADDL04 128
#define LKF_COPYADDLINE_ALL    255

_SCORING_EXPORT void lkf_copy_addlines (LKF_CONTEXT *pTargetContext, LKF_CONTEXT *pContext, int flags)
{
    char line[1024];
    unsigned int i, sl, addlineanz;
    const char *kanr, *year;
    char sourceYear[8], targetYear[8];
    
    if (pTargetContext->KANR[0] && memcmp (pContext->KANR, pTargetContext->KANR, 4)) {
        kanr = pTargetContext->KANR;
    }
    else {
        kanr = 0;
    }
    
    if (pTargetContext->cmb_jahr != pContext->cmb_jahr) {
        sprintf (sourceYear, "|%04.4d|", pContext->cmb_jahr);
        sprintf(targetYear, "|%04.4d|", pTargetContext->cmb_jahr);
        year = targetYear;
    }
    else {
        year = 0;
    }
    
    addlineanz = lkf_getaddlineanz(pContext);
    for (i = 0; i < addlineanz; i++) {
        lkf_getaddline(pContext, i, line);
        
        if (line[0] == 'K') {
            if (!memcmp (line + 1, "01", 2)) {
                if (flags & (LKF_COPYADDLINE_K01+LKF_COPYADDLINE_K)) {
                    if (kanr) {
                        lkf_replace_kanr(line, pContext->KANR, kanr);
                    }
                    if (year) {
                        lkf_replace_year(line, sourceYear, targetYear);
                    }
                    lkf_add_line(pTargetContext, line);
                }
            }
            else if (flags & LKF_COPYADDLINE_K) {
                if (kanr) {
                    lkf_replace_kanr(line, pContext->KANR, kanr);
                }
                if (year) {
                    lkf_replace_year(line, sourceYear, targetYear);
                }
                lkf_add_line(pTargetContext, line);
            }
        }
        else if (line[0] == 'L') {
            if (flags & LKF_COPYADDLINE_L) {
                if (kanr) {
                    lkf_replace_kanr(line, pContext->KANR, kanr);
                }
                if (year) {
                    lkf_replace_year(line, sourceYear, targetYear);
                }
                lkf_add_line(pTargetContext, line);
            }
        }
        else if (line[0] == 'B') {
            if (flags & LKF_COPYADDLINE_B) {
                if (kanr) {
                    lkf_replace_kanr(line, pContext->KANR, kanr);
                }
                if (year) {
                    lkf_replace_year(line, sourceYear, targetYear);
                }
                lkf_add_line(pTargetContext, line);
            }
        }
    }
    for (sl = 1; sl <= 4; sl++) {
        unsigned int count = lkf_get_context_l_count (pContext, sl, flags);
        for (i = 0; i < count; i++) {
            if (lkf_get_context_l (pContext, sl, i, line, 1024) > 0) {
                if (memcmp (line + 9, pContext->KANR, 4)) {
                    continue;
                }
                if (kanr) {
                    lkf_replace_kanr(line, pContext->KANR, kanr);
                }
                if (year) {
                    lkf_replace_year(line, sourceYear, targetYear);
                }
                lkf_add_line(pTargetContext, line);
            }
        }
    }
}

_SCORING_EXPORT void lkf_free_anonymisation_context (LKF_ANONYMISATION_CONTEXT *pAContext) {
    LKF_FREE (0, "lkf_free_anonymisation_context", pAContext);
}
_SCORING_EXPORT LKF_AUFENTHALT *lkf_anonymisation_add_aufenthalt (LKF_ANONYMISATION_CONTEXT *pAContext, LKF_AUFENTHALT *pAufenthalt) {
    LKF_CONTEXT *pTargetContext;
    LKF_AUFENTHALT *pCopy;
    long dayDiff;
    
    pTargetContext = pAContext->targetContext;
    
    if (!pTargetContext) {
        return 0;
    }
    
    pCopy = lkf_copy_aufenthalt2 (pAufenthalt, pTargetContext, 1);
    if (!pCopy) {
        return 0;
    }
    if (pCopy->BEHANDLUNGSART == 'I' && pAContext->ambToStat) {
        pCopy->AUFART = 'A';
        pCopy->ENTART = 'E';
        memcpy (pCopy->ENTDAT, pCopy->AUFDAT, 8);
        pCopy->BEHANDLUNGSART = 'S';
        pCopy->isAmb = 0;
    }
    else if (pCopy->BEHANDLUNGSART == 'S' && pAContext->statToAmb && strchr ("AW", pAufenthalt->AUFART) && pAufenthalt->ENTART == 'E' && !memcmp (pAufenthalt->AUFDAT, pAufenthalt->ENTDAT, 8)) {
        
        unsigned int i;
        
        pCopy->BEHANDLUNGSART = 'I';
        pCopy->AUFART = '1';
        pCopy->ENTART = '1';
        pCopy->isAmb = 1;
        
        for (i = 0; i < pCopy->abt_anz; i++) {
            if (strchr ("12345", pCopy->abt[i].ABTFC[1])) {
                pCopy->abt[i].ABTFC[1] = '6';
            }
            pCopy->abt[i].PHYS_ANW = 'J';
        }
    }
    
    if (pAContext->KANR[0]) {
        strncpy (pCopy->KANR, pAContext->KANR, 6);
    }
    
    if (pAContext->nextKey > 0) {
        char buf[32];
        int buflen;
        buflen = (int) sprintf (buf, "%d", pAContext->nextKey++);
        if (buflen < 12) {
            memset (buf + buflen, ' ', 12 - buflen);
        }
        memcpy (pCopy->PATID, buf, 12);
        pCopy->UCASE_PATID[0] = 0;
    }
    
    if (IsEmpty(pCopy->GEBDAT, 8) && !pTargetContext->isBM) {
        long aufDat;
        int altersgruppe;
        altersgruppe = atoi(pAufenthalt->ALTERSGRUPPE);
        aufDat = lkf_dat2intStrict (pCopy->AUFDAT);
        
        if (aufDat > 0) {
            aufDat -= 90;
            aufDat -= 365 * altersgruppe;
            lkf_int2dat8(aufDat, pCopy->GEBDAT);
        }
    }
    
    if (pAContext->dates || pAContext->aufaddyears) {
        unsigned int i;
        long aufDat, gebDat, entDat, randDat;
        char adjustedDat[10];
        char entyear[5];
        aufDat = lkf_dat2intStrict (pCopy->AUFDAT);
        entDat = lkf_dat2intStrict (pCopy->ENTDAT);
        gebDat = lkf_dat2intStrict (pCopy->GEBDAT);
        if (entDat) {
            randDat = entDat;
            sprintf (entyear, "%4.4s", pCopy->ENTDAT);
        }
        else {
            randDat = aufDat;
            sprintf (entyear, "%4.4s", pCopy->AUFDAT);
        }
        if (pAContext->dates == 1) {
            long lFirstDay, lLastDay;
            sprintf (adjustedDat, "%s0101", entyear);
            lFirstDay = (int) lkf_dat2intStrict (adjustedDat);
            sprintf (adjustedDat, "%s1231", entyear);
            lLastDay = (int) lkf_dat2intStrict (adjustedDat);

            if (lLastDay - randDat < randDat - lFirstDay) {
                dayDiff = rand() / (RAND_MAX / (lLastDay - randDat));
            }
            else {
                dayDiff = rand() / (RAND_MAX / (lFirstDay - randDat));
            }
        }
        else if (pAContext->dates >= 2) {
            long firstOfMonth;
            if (pCopy->ENTDAT[0] >= '0') {
                sprintf (adjustedDat, "%6.6s01", pCopy->ENTDAT);
                firstOfMonth = lkf_dat2intStrict (adjustedDat);
                dayDiff = firstOfMonth - entDat;
            }
            else if (pCopy->AUFDAT[0] >= 2) {
                sprintf (adjustedDat, "%6.6s01", pCopy->AUFDAT);
                firstOfMonth = lkf_dat2intStrict (adjustedDat);
                dayDiff = firstOfMonth - aufDat;
            }
            else {
                dayDiff = -1;
            }
        }
        else {
            dayDiff = 0;
        }

        
        if (pAContext->aufaddyears) {
            int y;
            y = atoi (entyear);
            if (entDat) {
                sprintf (adjustedDat, "%04d%4.4s", y + pAContext->aufaddyears, pCopy->ENTDAT + 4);
                dayDiff += lkf_dat2intStrict (adjustedDat) - entDat;
            }
            else {
                sprintf (adjustedDat, "%04d%4.4s", y + pAContext->aufaddyears, pCopy->AUFDAT + 4);
                dayDiff += lkf_dat2intStrict (adjustedDat) - aufDat;
            }
        }
                
        if (aufDat) {
            lkf_int2dat8(aufDat + dayDiff, pCopy->AUFDAT);
        }
        if (entDat) {
            lkf_int2dat8(entDat + dayDiff, pCopy->ENTDAT);
        }
        if (gebDat) {
            lkf_int2dat8(gebDat + dayDiff, pCopy->GEBDAT);
        }
        for (i = 0; i < pAufenthalt->abt_anz; i++) {
            LKF_AUFENTHALT_ABT *pAbt;
            long dat;
            
            pAbt = pCopy->abt + i;
            dat = lkf_dat2intStrict (pAbt->ABTDAT);
            if (dat > 0) {
                lkf_int2dat8(dat + dayDiff, pAbt->ABTDAT);
                memcpy (pAbt->ABTZEIT, "0000", 4);
            }
            dat = lkf_dat2intStrict (pAbt->ENTDAT);
            if (dat > 0) {
                lkf_int2dat8(dat + dayDiff, pAbt->ENTDAT);
                memcpy (pAbt->ENTZEIT, "0000", 4);
            }
        }
        
        for (i = 0; i < pAufenthalt->mel_anz; i++) {
            LKF_AUFENTHALT_MEL *pMel;
            long dat;
            
            pMel = pCopy->mel + i;
            
            dat = lkf_dat2intStrict (pMel->MELDAT);
            if (dat > 0) {
                lkf_int2dat8(dat + dayDiff, pMel->MELDAT);
                memcpy (pMel->MELZEIT, "0000", 4);
            }
        }
    }
    else {
        dayDiff = 0;
    }
    
    if (pAContext->STAATB[0]) {
        memcpy(pAufenthalt->STAATB, pAContext->STAATB, 3);
    }
        
    if (pAContext->STAATW[0]) {
        memcpy(pAufenthalt->STAATW, pAContext->STAATW, 3);
    }
    
    if (pAContext->PLZW[0]) {
        memcpy(pAufenthalt->PLZW, pAContext->PLZW, 6);
    }

    if (pAContext->GEMCODE[0]) {
        memcpy(pAufenthalt->GEMEINDEZIFFER, pAContext->GEMCODE, 5);
    }

    if (pCopy->pIntensiv) {
        unsigned int i;
        LKF_EXPANDED_LINE *pLine;
        char value[24];
        for (i = 0; i < pCopy->pIntensiv->lineCount; i++) {
            
            pLine = pCopy->pIntensiv->lines[i];
            
            if (pAContext->KANR[0]) {
                char *kanr = lkf_getXLine_FieldValue(pLine, GEN_KANR, value, 24);
                if (kanr) {
                    lkf_setXLine_FieldValue(pLine, GEN_KANR,  pAContext->KANR);
                }
            }
            if (dayDiff) {
                long lDate;
                char *date;
                
                date = lkf_getXLine_FieldValue(pLine, I11_AUFNAHMEDATUM, value, 24);
                if (date && (lDate = lkf_dat2intStrict (date))) {
                    lkf_int2dat8(lDate + dayDiff, value);
                    lkf_setXLine_FieldValue(pLine, I11_AUFNAHMEDATUM, value);
                }

                date = lkf_getXLine_FieldValue(pLine, GEN_ERHEBDAT, value, 24);
                if (date && (lDate = lkf_dat2intStrict (date))) {
                    lkf_int2dat8(lDate + dayDiff, value);
                    lkf_setXLine_FieldValue(pLine, GEN_ERHEBDAT, value);
                }
            }
        }
    }

    lkf_insert_aufenthalt(pTargetContext, pCopy);
    return pCopy;
}
