/****************************************************************************
** Leistungsorientierte Krankenanstaltenfinanzierung (LKF)                 **
** Scoring-C-Sourcen V2026.1                                               **
** (C) 2026 BMASGPK                                                        **
*****************************************************************************
** stat5.c - Statistik-Informationsmodul                                   **
**                                                                         **
**		 Alex.Holzer@chello.at                                             **
**       Bernhard.Pesec@dothealth.at                                       **
***************************************************************************/

#include "lkfint5.h"

/****************************************************************************
** Definition der konstanten Statistik-Strukturen                          **
****************************************************************************/

const LKF_STAT_FIELD
    StatAmb = {LKF_STAT_AMB, "Ambulant", "Anzahl Ambulante Frequenzen"},
	StatBelagstage   = {LKF_STAT_BELAGSTAGE, "Belagstage",		"Anzahl der im Berichtsjahr angefallenen Belagstage (Mitternachtsstände)"},
    StatBelagstage2017   = {LKF_STAT_BELAGSTAGE, "Belagstage",		"Anzahl der im Berichtsjahr angefallenen Belagstage (Mitternachtsstaende)"},
    StatPflegetage   = {LKF_STAT_PFLEGETAGE, "Pflegetage",      "Anzahl der im Berichtsjahr angefallenen Pflegetage"},
	StatAufnahmen    = {LKF_STAT_AUFNAHMEN,  "Aufnahmen",		"Anzahl im Berichtsjahr aufgenommener Patienten"},
	StatVerblieben   = {LKF_STAT_VERBLIEBEN, "Verblieben",		"Anzahl Verbliebene Patienten vom Vorjahr"},
	StatEntlassungen = {LKF_STAT_ENTLASSUNG, "Entlassungen",	"Anzahl Entlassungen"},
	StatVerstorben   = {LKF_STAT_VERSTORBEN, "Verstorbene",		"Anzahl Verstorbene im Berichtsjahr"},
	StatVerbleibende = {LKF_STAT_VERBLEIBEND,"Verbleibende",	"Anzahl am Jahresende verbleibende Patienten"},
	StatGanzPeriode  = {LKF_STAT_GANZJAHR,   "GanzJahr",		"Aufenthalte, die sich über das ganze Jahr erstrecken"},
	StatEintags      = {LKF_STAT_EINTAG,     "Eintag",			"Aufenthalte mit Gesamtbelagsdauer 0 Tage"},
	StatPatMaennlich = {LKF_STAT_MAENNLICH,	 "männlich",		"Anzahl männliche Patienten"},
    StatPatMaennlich2017 = {LKF_STAT_MAENNLICH,	 "maennlich",		"Anzahl maennliche Patienten"},
    StatPatWeiblich  = {LKF_STAT_WEIBLICH,	 "weiblich",		"Anzahl weibliche Patienten"},
    StatPatDivers  = {LKF_STAT_DIVERS,       "divers",          "Anzahl diverse Patienten"},
    StatPat			 = {LKF_STAT_AUFCOUNT,	 "Aufenthalte",		"Anzahl Aufenthalte"};

/* Definition der KA-Statistik */
const LKF_STAT_FIELDGROUP KADef =  {9, {&StatBelagstage, &StatPflegetage, &StatAufnahmen, &StatVerblieben, &StatEntlassungen,
									   &StatVerstorben, &StatVerbleibende, &StatGanzPeriode, &StatEintags}};

const LKF_STAT_FIELDGROUP KADef2017 =  {10, {&StatBelagstage2017, &StatPflegetage, &StatAufnahmen, &StatVerblieben, &StatEntlassungen,
    &StatVerstorben, &StatVerbleibende, &StatGanzPeriode, &StatEintags, &StatAmb}}; /* V21.0 */

/* Definition der Abteilungs-Statistik */
const LKF_STAT_FIELDGROUP AbtDef = {9, {&StatBelagstage, &StatPflegetage, &StatAufnahmen, &StatVerblieben, &StatEntlassungen,
										&StatVerstorben, &StatVerbleibende, &StatGanzPeriode, &StatEintags}};

const LKF_STAT_FIELDGROUP AbtDef2017 = {10, {&StatBelagstage, &StatPflegetage, &StatAufnahmen, &StatVerblieben, &StatEntlassungen,
    &StatVerstorben, &StatVerbleibende, &StatGanzPeriode, &StatEintags, &StatAmb}}; /* V21.0 */

/* Definition der Altersstatistik */
const LKF_STAT_FIELDGROUP AlterDef = {3, {&StatPatMaennlich, &StatPatWeiblich, &StatBelagstage}};
const LKF_STAT_FIELDGROUP AlterDef2017 = {4, {&StatPatMaennlich2017, &StatPatWeiblich, &StatBelagstage, &StatAmb}}; /* V21.0 */
const LKF_STAT_FIELDGROUP AlterDef2020 = {5, {&StatPatMaennlich2017, &StatPatWeiblich, &StatBelagstage, &StatAmb, &StatPatDivers}}; /* V2020.0 */

const char *sAlterDescription[] = {"Alter < 1", "1 <= Alter < 15", "15 <= Alter < 45", "45 <= Alter < 65", "65 <= Alter < 75", "Alter >= 75"};
const int AlterIntGrenzen[] = {1,15,45,65,75,-1};
const LKF_STAT_AGGREGATION_INFO AlterAggregationInfo = {6, 0, AlterIntGrenzen, 0, sAlterDescription};


/* Definition der Hauptwohnsitz-Statistik */
const LKF_STAT_FIELDGROUP HauptwohnsitzDef = {1, {&StatPat}};
const LKF_STAT_FIELDGROUP HauptwohnsitzDef2017 = {2, {&StatPat, &StatAmb}};
const char *HauptwohnsitzDescription[] = {"Burgenland", "Kärnten", "Niederösterreich", "Oberösterreich", "Salzburg", "Steiermark", "Tirol", "Vorarlberg", "Wien", "Ausland"};
const char *HauptwohnsitzDescription2017[] = {"Burgenland", "Kaernten", "Niederoesterr.", "Oberoesterreich", "Salzburg", "Steiermark", "Tirol", "Vorarlberg", "Wien", "Ausland"};
const char *HauptwohnsitzWerte[] = {"1", "2", "3", "4", "5", "6", "7", "8", "9", ""};
const LKF_STAT_AGGREGATION_INFO HauptWohnsitzAggregationInfo = {10, 1, 0, HauptwohnsitzWerte, HauptwohnsitzDescription};
const LKF_STAT_AGGREGATION_INFO HauptWohnsitzAggregationInfo2017 = {10, 1, 0, HauptwohnsitzWerte, HauptwohnsitzDescription2017};
/****************************************************************************
** Belegung und Freigabe der LKFStat-Struktur                              **
****************************************************************************/

typedef struct LKF_STAT_AUFENTHALT 
{
	LKF_AUFENTHALT *pAufenthalt;
	unsigned int lAufDat;
	unsigned int lEntDat;
	unsigned int lAbtAnz;
	unsigned int *plAbtDat;
	unsigned int lDatOk;
	unsigned int lModellJahr;
} LKF_STAT_AUFENTHALT; /* V11.0 */

static LKF_STAT_AUFENTHALT *lkf_stat_AllocStatInfo (LKF_STAT *pLKFStat, LKF_AUFENTHALT *pAufenthalt)
{ /* V11.0 */
	unsigned int bOk = 1, i;
    LKF_CONTEXT *pContext;
    LKF_STAT_AUFENTHALT *pStatAufenthalt;
    
    pContext = pAufenthalt->pScoringContext;
	pStatAufenthalt = LKF_CALLOC (pContext, "lkf_stat_AllocStatInfo", 1, sizeof (LKF_STAT_AUFENTHALT));
    if (!pStatAufenthalt) return 0;
    
	if (pAufenthalt->pScoringContext)
		pStatAufenthalt->lModellJahr = (unsigned int) pAufenthalt->pScoringContext->modelljahr;
	else
		pStatAufenthalt->lModellJahr = 2016;

	pStatAufenthalt->pAufenthalt = pAufenthalt;
	pStatAufenthalt->lAufDat =  (unsigned int) lkf_dat2int (pAufenthalt->AUFDAT);
    
    if (pAufenthalt->isAmb)
        pStatAufenthalt->lEntDat = pStatAufenthalt->lAufDat;
    else {
        pStatAufenthalt->lEntDat =  (unsigned int) lkf_dat2int (pAufenthalt->ENTDAT);
        
        if (!pStatAufenthalt->lEntDat && pAufenthalt->ENTART == 'V')
            pStatAufenthalt->lEntDat = pLKFStat->lLastDay + 1; /* V11.1 */
    }

	pStatAufenthalt->lAbtAnz = pAufenthalt->abt_anz;
	pStatAufenthalt->plAbtDat = LKF_CALLOC (pAufenthalt->pScoringContext, "lkf_stat_AllocStatInfo", pStatAufenthalt->lAbtAnz + 1, sizeof(unsigned int));
    if (!pStatAufenthalt->plAbtDat) {
        LKF_FREE(pContext, "lkf_stat_AllocStatInfo", pStatAufenthalt);
        return 0;
    }
    
    if (pAufenthalt->isAmb) {
        for (i = 0; i <= pStatAufenthalt->lAbtAnz; i++)
        {
            pStatAufenthalt->plAbtDat[i] = pStatAufenthalt->lAufDat;
        }
   
    }
    else {
        for (i = 0; i < pStatAufenthalt->lAbtAnz; i++)
        {
            pStatAufenthalt->plAbtDat[i] = (unsigned int) lkf_dat2int (pAufenthalt->abt[i].ABTDAT);
            if (!pStatAufenthalt->plAbtDat[i]) bOk = 0;
        }
        pStatAufenthalt->plAbtDat[pStatAufenthalt->lAbtAnz] = pStatAufenthalt->lEntDat;
    }

	if (pStatAufenthalt->lAufDat && pStatAufenthalt->lEntDat && pStatAufenthalt->lAufDat <= pStatAufenthalt->lEntDat)
	{
		if (pStatAufenthalt->lAufDat > pStatAufenthalt->lEntDat)
			bOk = 0;
		
		if (bOk)
		{
			if (pStatAufenthalt->plAbtDat[0] != pStatAufenthalt->lAufDat)
				bOk = 0;
			else
			{
				for (i = 0; i < pStatAufenthalt->lAbtAnz; i++)
				{
					if (pStatAufenthalt->plAbtDat[i] > pStatAufenthalt->plAbtDat[i+1])
					{
						if (pStatAufenthalt->pAufenthalt->ENTART != 'V' || i+1 < pStatAufenthalt->lAbtAnz) /* V11.1 */
							bOk = 0;
					}
				}
			}
		}
	}
	else
		bOk = 0;
	pStatAufenthalt->lDatOk = bOk;
	return pStatAufenthalt;
}

static void lkf_stat_FreeStatInfo (LKF_CONTEXT *pContext, LKF_STAT_AUFENTHALT *pStatAufenthalt)
{
	if (pStatAufenthalt->plAbtDat) 
		LKF_FREE (pContext, "lkf_stat_FreeStatInfo.abt", pStatAufenthalt->plAbtDat);
	LKF_FREE (pContext, "lkf_stat_FreeStatInfo", pStatAufenthalt);
}

static void lkf_stat_free_counter (LKF_CONTEXT *pContext, LKF_STAT_COUNTER *pCounter)
{
	if (pCounter)
	{
		LKF_FREE (pContext, "lkf_stat_free_counter.counter", pCounter->pCounter);
		LKF_FREE (pContext, "lkf_stat_free_counter", pCounter);
	}
}

static void lkf_stat_free_aggregation (LKF_CONTEXT *pContext, LKF_STAT_AGGREGATION *pAggregation)
{
	if (pAggregation)
	{
		unsigned int i;

		for (i = 0; i < pAggregation->nCount; i++)
		{
			lkf_stat_free_counter (pContext, pAggregation->ppCounter[i]);
		}
		LKF_FREE (pContext, "lkf_stat_free_aggregation.counter", pAggregation->ppCounter);
		LKF_FREE (pContext, "lkf_stat_free_aggregation", pAggregation);
	}
}

static void lkf_reset_lkfstat (LKF_STAT *pLKFStat)
{
	unsigned int i;

	if (pLKFStat) 
	{
		if (pLKFStat->pKACounter) 
		{
			lkf_stat_free_counter (pLKFStat->pContext, pLKFStat->pKACounter);
			pLKFStat->pKACounter = 0;
		}

		if (pLKFStat->ppAbtCounter)
		{
			for (i = 0; i < pLKFStat->nAbtCount; i++)
				lkf_stat_free_counter (pLKFStat->pContext, pLKFStat->ppAbtCounter[i]);
			LKF_FREE (pLKFStat->pContext, "lkf_reset_lkfstat", pLKFStat->ppAbtCounter);
			pLKFStat->ppAbtCounter = 0;
			pLKFStat->nAbtAlloc = 0;
			pLKFStat->nAbtCount = 0;
		}

		if (pLKFStat->pHauptWohnsitz)
		{
			lkf_stat_free_aggregation (pLKFStat->pContext, pLKFStat->pHauptWohnsitz);
			pLKFStat->pHauptWohnsitz = 0;
		}

		if (pLKFStat->pAlter)
		{
			lkf_stat_free_aggregation (pLKFStat->pContext, pLKFStat->pAlter);
			pLKFStat->pAlter = 0;
		}
	}
}

static LKF_STAT *lkf_alloc_lkfstat (LKF_CONTEXT *pContext)
{
	LKF_STAT *pLKFStat = (LKF_STAT *) LKF_CALLOC (pContext, "lkf_alloc_lkfstat", 1, sizeof (LKF_STAT));
	if (!pLKFStat) {
		return 0;
	}
    pLKFStat->pContext = pContext;
	pLKFStat->nIgnoreErrors = 1;
	pLKFStat->nIgnoreMark = 1;

	pLKFStat->pKADef = &KADef;
	pLKFStat->pAbtDef = &AbtDef;	
	pLKFStat->pAlterDef = &AlterDef;
	pLKFStat->pAlterAggr = &AlterAggregationInfo;
    if (pContext->modelljahr >= 2020)
    {
        pLKFStat->pKADef = &KADef2017;
        pLKFStat->pAbtDef = &AbtDef2017;
        pLKFStat->pAlterDef = &AlterDef2020;
        pLKFStat->pHauptWohnsitzAggr = &HauptWohnsitzAggregationInfo2017;
        pLKFStat->pHauptWohnsitzDef = &HauptwohnsitzDef2017;
    }
    else if (pContext->modelljahr >= 2017)
    {
        pLKFStat->pKADef = &KADef2017;
        pLKFStat->pAbtDef = &AbtDef2017;
        pLKFStat->pAlterDef = &AlterDef2017;
        pLKFStat->pHauptWohnsitzAggr = &HauptWohnsitzAggregationInfo2017;
        pLKFStat->pHauptWohnsitzDef = &HauptwohnsitzDef2017;
    }
    else
    {
        pLKFStat->pKADef = &KADef;
        pLKFStat->pAbtDef = &AbtDef;
        pLKFStat->pAlterDef = &AlterDef;
        pLKFStat->pHauptWohnsitzAggr = &HauptWohnsitzAggregationInfo;
        pLKFStat->pHauptWohnsitzDef = &HauptwohnsitzDef;
    }

	pLKFStat->pAlter = 0;
	pLKFStat->pHauptWohnsitz = 0;
	pLKFStat->pKACounter = 0;
	pLKFStat->nAbtAlloc = pLKFStat->nAbtCount = 0;
	pLKFStat->ppAbtCounter = 0;

	pLKFStat->nModelljahr = pContext->modelljahr;

	return pLKFStat;
}

static void lkf_free_lkfstat (LKF_STAT *pLKFStat)
{
    if (pLKFStat) {
        lkf_reset_lkfstat(pLKFStat);
        LKF_FREE (pLKFStat->pContext, "lkf_free_lkfstat", pLKFStat);
    }
}

int lkf_alloc_context_lkfstat (LKF_CONTEXT *pContext)
{
	if (pContext->pLKFStat) lkf_free_lkfstat (pContext->pLKFStat);
	pContext->pLKFStat = lkf_alloc_lkfstat (pContext);
	if (!pContext->pLKFStat) return LKF_OUTOFMEMORY_ERROR;
	return 0;
}

void lkf_free_context_lkfstat (LKF_CONTEXT *pContext)
{
	if (pContext->pLKFStat)
	{
		lkf_free_lkfstat (pContext->pLKFStat);
		pContext->pLKFStat = 0;
	}
}

static LKF_STAT_COUNTER *lkf_stat_alloc_counter (LKF_CONTEXT *pContext, const char *sInfo, const LKF_STAT_FIELDGROUP *pFieldGroup)
{
	LKF_STAT_COUNTER *pCounter = (LKF_STAT_COUNTER *) LKF_MALLOC (pContext, "lkf_stat_alloc_counter", sizeof (LKF_STAT_COUNTER));
    if (!pCounter) return 0;
    
	if (sInfo)
	{
		strncpy (pCounter->sInfo, sInfo, 20);
		pCounter->sInfo[19] = 0;
	}
	else pCounter->sInfo[0] = 0;
	
	pCounter->pFieldGroup = pFieldGroup;

	pCounter->pCounter = (unsigned int *) LKF_CALLOC (pContext, "lkf_stat_alloc_counter.counter", sizeof (unsigned int), pFieldGroup->nCount);
    if (!pCounter->pCounter) {
        LKF_FREE (pContext, "lkf_stat_alloc_counter", pCounter);
        return 0;
    }
    
	return pCounter;
}

static LKF_STAT_AGGREGATION *lkf_stat_alloc_aggregation (LKF_CONTEXT *pContext, const LKF_STAT_FIELDGROUP *pFieldGroup, const LKF_STAT_AGGREGATION_INFO *pAggregationInfo)
{
	unsigned int i;
	LKF_STAT_AGGREGATION *pAggregation = (LKF_STAT_AGGREGATION *) LKF_MALLOC (pContext, "lkf_stat_alloc_aggregation", sizeof (LKF_STAT_AGGREGATION));
    if (!pAggregation) return 0;
    
	pAggregation->pAggregationInfo = pAggregationInfo;
	pAggregation->pFieldGroup = pFieldGroup;
	pAggregation->nCount = pAggregationInfo->nCount;
	pAggregation->ppCounter = (LKF_STAT_COUNTER **) LKF_CALLOC (pContext, "lkf_stat_alloc_aggregation.counter", pAggregationInfo->nCount, sizeof (LKF_STAT_COUNTER *));
    
    if (!pAggregation->ppCounter) {
        LKF_FREE(pContext, "lkf_stat_alloc_aggregation", pAggregation);
        return 0;
    }

	for (i = 0; i < pAggregationInfo->nCount; i++)
	{
		pAggregation->ppCounter[i] = lkf_stat_alloc_counter (pContext, 0, pFieldGroup);
		if (!pAggregation->ppCounter[i]) {
			for (unsigned int j = 0; j < i; j++) {
				lkf_stat_free_counter(pContext, pAggregation->ppCounter[j]);
			}
			LKF_FREE(pContext, "lkf_stat_alloc_aggregation.counter", pAggregation->ppCounter);
			LKF_FREE(pContext, "lkf_stat_alloc_aggregation", pAggregation);
			return 0;
		}
	}

	return pAggregation;
}

/**************************************************************************************
** lkf_stat_abt_getindex:                                                            **
**     Liefert zu einem Funktionscode den Index in der LKFSTAT-Abteilungsstruktur.   **
**     Wenn die Abteilung noch nicht eingetragen ist, wird sie angelegt.             **
**************************************************************************************/

static unsigned int lkf_stat_abt_getindex (LKF_STAT *pLKFStat, const char *ABTFC)
{
	int lIsSmaller, lIsBigger, lCurrent, res;
	char sAbtFC[10];
	LKF_STAT_COUNTER* pNewCounter;
	lIsSmaller = -1;
	lIsBigger = (int) pLKFStat->nAbtCount;

	/* Suche nach existierendem ABTFC bzw. Position für die neue Abteilung im sortieren Array */
	while (lIsSmaller + 1 < lIsBigger)
	{
		lCurrent = (lIsSmaller + lIsBigger) >> 1;
		res = memcmp (pLKFStat->ppAbtCounter[lCurrent]->sInfo, ABTFC, 8);
		if (res > 0) lIsBigger = lCurrent;
		else if (res < 0) lIsSmaller = lCurrent;
		else return (unsigned int) lCurrent;
	}

	/* Erweiterung des Abteilungsarrays, wenn notwendig */
	if (pLKFStat->nAbtAlloc == pLKFStat->nAbtCount)
	{
		LKF_STAT_COUNTER **ppOld = pLKFStat->ppAbtCounter;
		pLKFStat->ppAbtCounter = (LKF_STAT_COUNTER **) LKF_MALLOC (pLKFStat->pContext, "lkf_stat_abt_getindex", sizeof(LKF_STAT_COUNTER *) * (pLKFStat->nAbtAlloc+=20));
        if (!pLKFStat->ppAbtCounter) {
			pLKFStat->nAbtAlloc = pLKFStat->nAbtCount = 0;
            LKF_FREE (pLKFStat->pContext, "lkf_stat_abt_getindex", ppOld);
            return LKF_OUTOFMEMORY_UINTERROR;
        }
		if (pLKFStat->nAbtCount)
		{
			memcpy (pLKFStat->ppAbtCounter, ppOld, sizeof (LKF_STAT_COUNTER *) * pLKFStat->nAbtCount);
            LKF_FREE (pLKFStat->pContext, "lkf_stat_abt_getindex", ppOld);
		}
	}

	/* Erzeugung der neuen Abteilungsstruktur */

	memcpy (sAbtFC, ABTFC, 8);
	sAbtFC[8] = 0;
	pNewCounter = lkf_stat_alloc_counter(pLKFStat->pContext, sAbtFC, pLKFStat->pAbtDef);
	if (!pNewCounter) {
		return LKF_OUTOFMEMORY_UINTERROR;
	}
	if (lIsBigger < (int)pLKFStat->nAbtCount)
		memmove(pLKFStat->ppAbtCounter + lIsBigger + 1, pLKFStat->ppAbtCounter + lIsBigger, sizeof(LKF_STAT_COUNTER*) * (pLKFStat->nAbtCount - (unsigned int)lIsBigger));
	pLKFStat->ppAbtCounter[lIsBigger] = pNewCounter;
	pLKFStat->nAbtCount++;
	return (unsigned int) lIsBigger;
}

/**************************************************************************************
** lkf_stat_aufabt_fill:                                                             **
**     Befüllt die statistichen Daten zu einer Abteilung eines Aufenthalts.          **
**************************************************************************************/

static void lkf_stat_aufabt_fill (LKF_STAT *pLKFStat, LKF_STAT_AUFENTHALT *pStatAufenthalt, unsigned int nAbtNr, LKF_STAT_COUNTER *pStatCounter)
{
	const LKF_STAT_FIELDGROUP *pFieldGroup;
	LKF_AUFENTHALT *pAufenthalt;
	unsigned int i;
	unsigned int lVal;
	unsigned int lAufDat, lEntDat;
	pAufenthalt = pStatAufenthalt->pAufenthalt;

	pFieldGroup = pStatCounter->pFieldGroup;

	if (pStatAufenthalt->lModellJahr > 2005 && !pStatAufenthalt->lDatOk)
		return;

	lAufDat = pStatAufenthalt->plAbtDat[nAbtNr];
	lEntDat = pStatAufenthalt->plAbtDat[nAbtNr+1];

	if (lEntDat > pLKFStat->lLastDay + 1) 
		lEntDat = pLKFStat->lLastDay + 1;

	if (!lAufDat || !lEntDat || lAufDat > pLKFStat->lLastDay || lEntDat < lAufDat || lEntDat < pLKFStat->lFirstDay) 
		return;

    if (pAufenthalt->isAmb) {
        for (i = 0; i < pFieldGroup->nCount; i++)
        {
            switch (pFieldGroup->pFields[i]->nFieldNr)
            {
                case LKF_STAT_AMB:
                    if (lAufDat && lEntDat && lAufDat >= pLKFStat->lFirstDay && lAufDat <= pLKFStat->lLastDay)
                    {
                        pStatCounter->pCounter[i]++;
                    }
                    break;
                default:
                    break;
            }
        }
        return;
    }
    
    
	for (i = 0; i < pFieldGroup->nCount; i++)
	{
		switch (pFieldGroup->pFields[i]->nFieldNr)
		{
			case LKF_STAT_BELAGSTAGE:
				if (lAufDat && lEntDat && lEntDat >= pLKFStat->lFirstDay && lAufDat <= pLKFStat->lLastDay)
				{
					lVal = (lEntDat > pLKFStat->lLastDay) ? pLKFStat->lLastDay : lEntDat;
					lVal -= (lAufDat < pLKFStat->lFirstDay) ? (pLKFStat->lFirstDay-1) : lAufDat;
					pStatCounter->pCounter[i] += lVal;
				}
				break;
			case LKF_STAT_PFLEGETAGE:
				if (pLKFStat->nModelljahr < 2010)
				{ /* V14.1: keine Pflegetageberechnung ab 2010 */
					if (lAufDat && lEntDat && lEntDat >= pLKFStat->lFirstDay && lAufDat <= pLKFStat->lLastDay)
					{
						lVal = (lEntDat > pLKFStat->lLastDay) ? pLKFStat->lLastDay : lEntDat;
						lVal -= (lAufDat < pLKFStat->lFirstDay) ? (pLKFStat->lFirstDay) : lAufDat;
						pStatCounter->pCounter[i] += lVal + 1;
					}
				}
				break;
			case LKF_STAT_AUFNAHMEN:
				if (lAufDat) 
				{
					if (lAufDat >= pLKFStat->lFirstDay && lAufDat <= pLKFStat->lLastDay)
					{
						pStatCounter->pCounter[i]++;
					}
				}
				break;
			case LKF_STAT_VERBLIEBEN:
				if (lAufDat && lAufDat < pLKFStat->lFirstDay && lEntDat && lEntDat >= pLKFStat->lFirstDay)
					pStatCounter->pCounter[i]++;
				break;
			case LKF_STAT_ENTLASSUNG:
				if (lEntDat && (nAbtNr + 1 < pAufenthalt->abt_anz || (pAufenthalt->ENTART != 'S' && pAufenthalt->ENTART != 'V')))
				{ /* nicht nur Aufenthalts-, sondern auch Abteilungsentlassungen im Jahr zählen */
					if (lEntDat >= pLKFStat->lFirstDay && lEntDat <= pLKFStat->lLastDay)
					{
						pStatCounter->pCounter[i]++;
					}						
				}
				break;
			case LKF_STAT_VERSTORBEN:
				if (pAufenthalt->ENTART == 'S' && nAbtNr + 1 == pAufenthalt->abt_anz && lEntDat && lEntDat >= pLKFStat->lFirstDay && lEntDat <= pLKFStat->lLastDay)
					pStatCounter->pCounter[i]++;
				break;
			case LKF_STAT_VERBLEIBEND:
				if (lAufDat && lEntDat && lAufDat <= pLKFStat->lLastDay && lEntDat > pLKFStat->lLastDay)
					pStatCounter->pCounter[i]++;
				break;
			case LKF_STAT_GANZJAHR:
				if (lAufDat && lAufDat <= pLKFStat->lFirstDay && lEntDat && lEntDat >= pLKFStat->lLastDay)
					pStatCounter->pCounter[i]++;
				break;
			case LKF_STAT_EINTAG:
				if (lAufDat && lAufDat == lEntDat && lAufDat >= pLKFStat->lFirstDay && lAufDat <= pLKFStat->lLastDay)
					pStatCounter->pCounter[i]++;
				break;
			case LKF_STAT_MAENNLICH:
				if (pAufenthalt->GESCHL == 'M') pStatCounter->pCounter[i]++;
				break;
			case LKF_STAT_WEIBLICH:	
				if (pAufenthalt->GESCHL == 'W') pStatCounter->pCounter[i]++;
				break;
            case LKF_STAT_DIVERS:
                if (pAufenthalt->GESCHL != 'M' && pAufenthalt->GESCHL != 'W') pStatCounter->pCounter[i]++;
                break;
			case LKF_STAT_AUFCOUNT:
				pStatCounter->pCounter[i]++;
				break;
			default:
				break;
		}
	}
}

/********************************************************************************
** lkf_stat_getLineCount:                                                      **
**      Liefert die Anzahl Ergebniszeilen zu einer Statistik-Kategorie zurück  **
********************************************************************************/

_SCORING_EXPORT unsigned int lkf_stat_getLineCount (LKF_CONTEXT *pContext, unsigned int nType)
{
	LKF_STAT *pLKFStat = pContext->pLKFStat;
	if (!pLKFStat) return 0;

	switch (nType)
	{
		case LKF_STATTYPE_KA:
			if (pLKFStat->pKADef) return 1;
			else return 0;
		case LKF_STATTYPE_ABT:
			return pLKFStat->nAbtCount;
		case LKF_STATTYPE_ALTER:
			if (pLKFStat->pAlter) return pLKFStat->pAlter->nCount;
			else return 0;
		case LKF_STATTYPE_HAUPTWOHNSITZ:
			if (pLKFStat->pHauptWohnsitz) return pLKFStat->pHauptWohnsitz->nCount;
			else return 0;
		default:
			return 0;
	}
}

/********************************************************************************
** lkf_stat_getHeadline:                                                       **
**      Liefert eine Überschriftszeile zur Statistik-Kategorie zurück.         **
********************************************************************************/

static void lkf_stat_getstaticheadline (LKF_CONTEXT *pContext, const char *sPrefix, const LKF_STAT_FIELDGROUP *pFieldGroup, char *sBuf)
{
	unsigned int i;

	if (!pFieldGroup) 
	{
		sBuf[0] = 0;
		return;
	}

	strcpy (sBuf, sPrefix);
	sBuf += strlen (sBuf);

	for (i = 0; i < pFieldGroup->nCount; i++)
	{
		sBuf += sprintf (sBuf, "%-12.12s; ", pFieldGroup->pFields[i]->sShort);
	}
}

_SCORING_EXPORT unsigned int lkf_stat_getHeadline (LKF_CONTEXT *pContext, unsigned int nType, char *sBuf, unsigned int nBufLen)
{
	unsigned int lLen;
	char sLocalBuf[1024];
	LKF_STAT *pLKFStat = pContext->pLKFStat;
	if (!pLKFStat) return 0;

	switch (nType)
	{
		case LKF_STATTYPE_KA:
			lkf_stat_getstaticheadline (pContext, "KANR     ; ", pLKFStat->pKADef, sLocalBuf);
			break;
		case LKF_STATTYPE_ABT:
			lkf_stat_getstaticheadline (pContext, "ABTFC    ; ", pLKFStat->pAbtDef, sLocalBuf);
			break;
		case LKF_STATTYPE_ALTER:
			lkf_stat_getstaticheadline (pContext, "Alter           ; ", pLKFStat->pAlterDef, sLocalBuf);
			break;
		case LKF_STATTYPE_HAUPTWOHNSITZ:
			lkf_stat_getstaticheadline (pContext, "Bundesland      ; ", pLKFStat->pHauptWohnsitzDef, sLocalBuf);
			break;
		default:
			return 0;
	}

	strncpy (sBuf, sLocalBuf, nBufLen);
	lLen = (unsigned int) strlen (sLocalBuf);
	if (lLen >= nBufLen) sBuf[nBufLen-1] = 0;
	return lLen;
}

/********************************************************************************
** lkf_stat_getLine:                                                           **
**      Liefert eine Statistik-Zeile zurück.                                   **
********************************************************************************/

static void lkf_stat_getstaticline (LKF_CONTEXT *pContext, const char *sPrefix, const LKF_STAT_COUNTER *pCounter, char *sBuf)
{
	unsigned int i;

	if (!pCounter)
	{
		sBuf[0] = 0;
		return;
	}

	strcpy (sBuf, sPrefix);
	sBuf += strlen (sBuf);
	for (i = 0; i < pCounter->pFieldGroup->nCount; i++)
	{
		sBuf += sprintf (sBuf, "%12d; ", pCounter->pCounter[i]);
	}
}

_SCORING_EXPORT unsigned int lkf_stat_getLine (LKF_CONTEXT *pContext, unsigned int nType, unsigned int nLine, char *sBuf, unsigned int nBufLen)
{
	unsigned int lLen;
	char sLocalBuf[1024];
	char sPrefixBuf[20];
	LKF_STAT *pLKFStat = pContext->pLKFStat;
	if (!pLKFStat) return 0;

	sLocalBuf[0] = 0;

	switch (nType)
	{
		case LKF_STATTYPE_KA:
			if (nLine == 0) 
			{
				sprintf (sPrefixBuf, "%4.4s     ; ", pContext->KANR);			
				lkf_stat_getstaticline (pContext, sPrefixBuf, pLKFStat->pKACounter, sLocalBuf);
			}
			break;

		case LKF_STATTYPE_ABT:
			if (nLine < pLKFStat->nAbtCount) 
			{
				sprintf (sPrefixBuf, "%8.8s ; ", pLKFStat->ppAbtCounter[nLine]->sInfo);
				lkf_stat_getstaticline (pContext, sPrefixBuf, pLKFStat->ppAbtCounter[nLine], sLocalBuf);
			}
			break;

		case LKF_STATTYPE_ALTER:
			if (pLKFStat->pAlter && nLine < pLKFStat->pAlter->nCount) 
			{
				sprintf (sPrefixBuf, "%-16.16s; ", pLKFStat->pAlter->pAggregationInfo->sDescription[nLine]);
				lkf_stat_getstaticline (pContext, sPrefixBuf, pLKFStat->pAlter->ppCounter[nLine], sLocalBuf);
			}
			break;

		case LKF_STATTYPE_HAUPTWOHNSITZ:

			if (pLKFStat->pHauptWohnsitz && nLine < pLKFStat->pHauptWohnsitz->nCount)
			{
				sprintf (sPrefixBuf, "%-16.16s; ", pLKFStat->pHauptWohnsitz->pAggregationInfo->sDescription[nLine]);
				lkf_stat_getstaticline (pContext, sPrefixBuf, pLKFStat->pHauptWohnsitz->ppCounter[nLine], sLocalBuf);
			}	
			break;

		default:
			return 0;
	}

	strncpy (sBuf, sLocalBuf, nBufLen);
	lLen = (unsigned int) strlen (sLocalBuf);
	if (lLen >= nBufLen) sBuf[nBufLen-1] = 0;
	return lLen;
}

/**************************************************************************************
** lkf_stat_aufenthalt_fill:                                                         **
**     Befüllt die statistischen Daten zu einem Aufenthalt.                          **
**************************************************************************************/

static void lkf_stat_aufenthalt_fill (LKF_STAT *pLKFStat, const LKF_STAT_AUFENTHALT *pStatAufenthalt, LKF_STAT_COUNTER *pStatCounter)
{
	const LKF_STAT_FIELDGROUP *pFieldGroup;
	LKF_AUFENTHALT *pAufenthalt;
	unsigned int i, j;

	unsigned int lVal;

	pAufenthalt = pStatAufenthalt->pAufenthalt;

	pFieldGroup = pStatCounter->pFieldGroup;

    
    if (pAufenthalt->isAmb) {
        for (i = 0; i < pFieldGroup->nCount; i++)
        {
            switch (pFieldGroup->pFields[i]->nFieldNr)
            {
                case LKF_STAT_AMB:
                    if (pStatAufenthalt->lAufDat && pStatAufenthalt->lEntDat && pStatAufenthalt->lAufDat >= pLKFStat->lFirstDay && pStatAufenthalt->lAufDat <= pLKFStat->lLastDay)
                    {
                        pStatCounter->pCounter[i]++;
                    }
                    break;
                default:
                    break;
            }
        }
        return;
    }

    
	for (i = 0; i < pFieldGroup->nCount; i++)
	{
		switch (pFieldGroup->pFields[i]->nFieldNr)
		{
			case LKF_STAT_BELAGSTAGE:
				if (pStatAufenthalt->lAufDat && pStatAufenthalt->lEntDat && pStatAufenthalt->lEntDat >= pLKFStat->lFirstDay && pStatAufenthalt->lAufDat <= pLKFStat->lLastDay)
				{
					lVal = (pStatAufenthalt->lEntDat > pLKFStat->lLastDay) ? pLKFStat->lLastDay : pStatAufenthalt->lEntDat;
					lVal -= (pStatAufenthalt->lAufDat < pLKFStat->lFirstDay) ? (pLKFStat->lFirstDay-1) : pStatAufenthalt->lAufDat; 
					
					if (pLKFStat->nModelljahr >= 2010)
					{ /* V14.0 */
						for (j = 0; j < pAufenthalt->abt_anz; j++)
						{
							if (!memcmp (pAufenthalt->abt[j].ABTFC, UNTERBRECHUNG_ABTFC, UNTERBRECHUNG_LEN) && pStatAufenthalt->plAbtDat[j]<=pLKFStat->lLastDay && (j+1==pAufenthalt->abt_anz || pStatAufenthalt->plAbtDat[j+1]>=pLKFStat->lFirstDay))
							{
								if (j + 1 < pAufenthalt->abt_anz)
									lVal -=  (pStatAufenthalt->plAbtDat[j+1] > pLKFStat->lLastDay ? pLKFStat->lLastDay : pStatAufenthalt->plAbtDat[j+1])
									- (pStatAufenthalt->plAbtDat[j] < pLKFStat->lFirstDay ? pLKFStat->lFirstDay-1 : pStatAufenthalt->plAbtDat[j]); /* V16.0 */
								else
									lVal -=  (pStatAufenthalt->lEntDat > pLKFStat->lLastDay ? pLKFStat->lLastDay : pStatAufenthalt->lEntDat)
									- (pStatAufenthalt->plAbtDat[j] < pLKFStat->lFirstDay ? pLKFStat->lFirstDay-1 : pStatAufenthalt->plAbtDat[j]); /* V16.0 */

							}
						}
					}
					
					pStatCounter->pCounter[i] += lVal;
				}
				break;
			case LKF_STAT_PFLEGETAGE:
				if (pLKFStat->nModelljahr < 2010)
				{ /* V14.1: keine Pflegetageberechnung ab 2010 */
					if (pStatAufenthalt->lAufDat && pStatAufenthalt->lEntDat && pStatAufenthalt->lEntDat >= pLKFStat->lFirstDay && pStatAufenthalt->lAufDat <= pLKFStat->lLastDay)
					{
						lVal = (pStatAufenthalt->lEntDat > pLKFStat->lLastDay) ? pLKFStat->lLastDay : pStatAufenthalt->lEntDat;
						lVal -= (pStatAufenthalt->lAufDat < pLKFStat->lFirstDay) ? (pLKFStat->lFirstDay) : pStatAufenthalt->lAufDat;
						pStatCounter->pCounter[i] += lVal + 1;
					}
				}
				break;
			case LKF_STAT_AUFNAHMEN:
				if (pStatAufenthalt->lAufDat >= pLKFStat->lFirstDay && pStatAufenthalt->lAufDat <= pLKFStat->lLastDay)
					pStatCounter->pCounter[i]++;
				break;
			case LKF_STAT_VERBLIEBEN:
				if (pStatAufenthalt->lAufDat && pStatAufenthalt->lAufDat < pLKFStat->lFirstDay && pStatAufenthalt->lEntDat >= pLKFStat->lFirstDay)
					pStatCounter->pCounter[i]++;
				break;
			case LKF_STAT_ENTLASSUNG:
				if (pAufenthalt->ENTART != 'S' && pStatAufenthalt->lEntDat)
				{
					if (pStatAufenthalt->lEntDat >= pLKFStat->lFirstDay && pStatAufenthalt->lEntDat <= pLKFStat->lLastDay)
						pStatCounter->pCounter[i]++;
				}
				break;
			case LKF_STAT_VERSTORBEN:
				if (pAufenthalt->ENTART == 'S' && pStatAufenthalt->lEntDat >= pLKFStat->lFirstDay && pStatAufenthalt->lEntDat <= pLKFStat->lLastDay)
					pStatCounter->pCounter[i]++;
				break;
			case LKF_STAT_VERBLEIBEND:
				if (pStatAufenthalt->lAufDat && pStatAufenthalt->lAufDat <= pLKFStat->lLastDay && pStatAufenthalt->lEntDat > pLKFStat->lLastDay)
					pStatCounter->pCounter[i]++;
				break;
			case LKF_STAT_GANZJAHR:
				if (pStatAufenthalt->lAufDat && pStatAufenthalt->lAufDat <= pLKFStat->lFirstDay && pStatAufenthalt->lEntDat >= pLKFStat->lLastDay)
					pStatCounter->pCounter[i]++;
				break;
			case LKF_STAT_EINTAG:
				if (pStatAufenthalt->lAufDat && pStatAufenthalt->lAufDat == pStatAufenthalt->lEntDat && pStatAufenthalt->lAufDat >= pLKFStat->lFirstDay && pStatAufenthalt->lAufDat <= pLKFStat->lLastDay)
					pStatCounter->pCounter[i]++;
				break;
			case LKF_STAT_MAENNLICH:
				if (pAufenthalt->GESCHL == 'M') pStatCounter->pCounter[i]++;
				break;
			case LKF_STAT_WEIBLICH:	
				if (pAufenthalt->GESCHL == 'W') pStatCounter->pCounter[i]++;
				break;
            case LKF_STAT_DIVERS:
                if (pAufenthalt->GESCHL == 'X') pStatCounter->pCounter[i]++;
                break;
			case LKF_STAT_AUFCOUNT:
				pStatCounter->pCounter[i]++;
				break;
			default:
				break;
		}
	}
}

/****************************************************************************************
** lkf_stat_getBundesland:                                                             **
**       Liefert zu einem Aufenthalt das Wohnsitz-Bundesland.                          **
****************************************************************************************/

static void lkf_stat_getBundesland (LKF_AUFENTHALT *pAufenthalt, char *sBundesland)
{

	char traceBuf[1024];
	char trimmed_string[8];
	sBundesland[0] = 0;
	simLTrim (trimmed_string, pAufenthalt->STAATW, 3);

	if (!memcmp (trimmed_string, "AT ", 3))
	{
		PLZ_LIST_STRING *pPlz;
		simTrim (trimmed_string, pAufenthalt->PLZW, 6);
		pPlz = PLZInArray (pAufenthalt->pScoringContext, trimmed_string);
		if (pPlz) sprintf (sBundesland, "%c", ((const char*)pPlz)[34]);
		if (!*sBundesland || !strchr("123456789", *sBundesland)) {
			sprintf(traceBuf, "PATID=%10.10s: AT %6.6s -> %s / Bundesland-ASCII %d", pAufenthalt->PATID, trimmed_string, pPlz ? "FOUND" : "NOT FOUND", *sBundesland);
			lkf_addTraceLineContext(pAufenthalt->pScoringContext, traceBuf, LKF_FAC_MBDS, LKF_SEV_INFO);
		}
	}
	else {
		sprintf(traceBuf, "PATID=%10.10s: %4.4s -> %3.3s -> NOT IN AT", pAufenthalt->PATID, pAufenthalt->STAATW, trimmed_string);
		lkf_addTraceLineContext(pAufenthalt->pScoringContext, traceBuf, LKF_FAC_MBDS, LKF_SEV_INFO);
	}
}

static void lkf_stat_getGEMCOBundesland (LKF_AUFENTHALT *pAufenthalt, char *sBundesland)
{ /* V2019.2 - Bundesland aus Gemeindecode ermitteln */
    char trimmed_string[8];
    sBundesland[0] = 0;
    simLTrim (trimmed_string, pAufenthalt->STAATW, 3);
    
    if (!memcmp (trimmed_string, "AT ", 3))
    {
        char bl = pAufenthalt->GEMEINDEZIFFER[0];
        if (bl >= '1' && bl <= '9') {
            sprintf (sBundesland, "%c", bl);
        }
    }
}




/**************************************************************************************
** lkf_stat_aufenthalt (V8.1):                                                       **
**     Berechnet die Statistiken für einen Aufenthalt.                               **
**************************************************************************************/

static int lkf_stat_aufenthalt (LKF_STAT *pLKFStat, LKF_AUFENTHALT *pAufenthalt)
{
	unsigned int i, j, nAbtIndex;
	LKF_STAT_AUFENTHALT *pStatAufenthalt; /* V11.0 */
	LKF_STAT_COUNTER *pStatCounter;
	const LKF_STAT_AGGREGATION_INFO *pInfo;

	pStatAufenthalt = lkf_stat_AllocStatInfo (pLKFStat, pAufenthalt);
	if (!pStatAufenthalt) {
		return LKF_OUTOFMEMORY_ERROR;
	}
    if (pStatAufenthalt->lModellJahr > 2005 && !pStatAufenthalt->lDatOk) {
        lkf_stat_FreeStatInfo(pLKFStat->pContext, pStatAufenthalt);
        return -1;
    }

	if (pLKFStat->pKADef) 
		lkf_stat_aufenthalt_fill (pLKFStat, pStatAufenthalt, pLKFStat->pKACounter);



	if (pLKFStat->pAlter)
	{
        int nAlter = 0;
        
        if (pAufenthalt->pScoringContext->isBM)
        { /* V19.0 */
            nAlter = atoi (pAufenthalt->ALTERSGRUPPE);
        } else {
        
            int nGebYear, nEntYear;
            char sYearBuf[6];
            memcpy (sYearBuf, pAufenthalt->GEBDAT, 4);
            sYearBuf[4] = 0;
            nGebYear = atoi (sYearBuf);

            if (nGebYear)
            {

                if (pAufenthalt->ENTART == 'V')
                    nAlter = pAufenthalt->pScoringContext->cmb_jahr - nGebYear;
                else
                {
                    memcpy (sYearBuf, pAufenthalt->ENTDAT, 4);
                    sYearBuf[4] = 0;
                    nEntYear = atoi (sYearBuf);
                    if (!nEntYear) nAlter = pAufenthalt->pScoringContext->cmb_jahr - nGebYear;
                    else
                    {
                        nAlter = nEntYear - nGebYear;
                        if (memcmp (pAufenthalt->ENTDAT + 4, pAufenthalt->GEBDAT + 4, 4) < 0)
                            nAlter--;
                    }
                }
            }
        }
        pInfo = pLKFStat->pAlter->pAggregationInfo;
        pStatCounter = 0;
        for (i = 0; !pStatCounter && i < pLKFStat->pAlter->nCount; i++)
        {
            if (pInfo->pIntGrenzen[i] == -1 || nAlter < pInfo->pIntGrenzen[i])
                pStatCounter = pLKFStat->pAlter->ppCounter[i];
        }

        if (pStatCounter)
            lkf_stat_aufenthalt_fill (pLKFStat, pStatAufenthalt, pStatCounter);
	}

	if (pLKFStat->pHauptWohnsitz)
	{
		char sValue[10];
        
        if (pLKFStat->nModelljahr >= 2019)
        { /* V2019.2 */
            lkf_stat_getGEMCOBundesland (pAufenthalt, sValue);
        }
        else {
            lkf_stat_getBundesland (pAufenthalt, sValue);
        }
        
		
		pInfo = pLKFStat->pHauptWohnsitz->pAggregationInfo;
		
		pStatCounter = 0;

		for (i = 0; !pStatCounter && i < pLKFStat->pHauptWohnsitz->nCount; i++)
		{
			if (!strcmp (sValue, pInfo->sCharWerte[i])) pStatCounter = pLKFStat->pHauptWohnsitz->ppCounter[i];
		}

		if (pStatCounter)
			lkf_stat_aufenthalt_fill (pLKFStat, pStatAufenthalt, pStatCounter);
	}

	if (pLKFStat->pAbtDef)
	{
		for (j = 0; j < pAufenthalt->abt_anz; j++)
		{

			if (pAufenthalt->pScoringContext->modelljahr >= 2010 && !memcmp (pAufenthalt->abt[j].ABTFC, UNTERBRECHUNG_ABTFC, UNTERBRECHUNG_LEN))
				continue; /* V14.0 */

			nAbtIndex = lkf_stat_abt_getindex (pLKFStat, pAufenthalt->abt[j].ABTFC);
			if (nAbtIndex == LKF_OUTOFMEMORY_UINTERROR) {
				return LKF_OUTOFMEMORY_ERROR;
			}
			lkf_stat_aufabt_fill (pLKFStat, pStatAufenthalt, j, pLKFStat->ppAbtCounter[nAbtIndex]);
		}
	}

	lkf_stat_FreeStatInfo (pLKFStat->pContext, pStatAufenthalt);
	return 0;
}


/***********************************************************************
** lkf_stat_init_fieldidarray:                                        **
**     Initialisiert das Field-Array der Statistik-Felder             **
***********************************************************************/

static void lkf_stat_init_fieldidarray (const LKF_STAT_FIELDGROUP *pFieldGroup, int *pIndexes)
{
    int i;
	for (i = 0; i < LKF_STAT_MAXSTATFIELD; i++) pIndexes[i] = -1;
	
	if (pFieldGroup)
	{
		for (i = 0; i < (int) pFieldGroup->nCount; i++) pIndexes[pFieldGroup->pFields[i]->nFieldNr] = i;
	}
}

/***********************************************************************
** Durchfuehrung der Statistik                                         **
***********************************************************************/

_SCORING_EXPORT unsigned int lkf_stat_package (LKF_CONTEXT *pContext)
{ /* V21.0 */
    LKF_STAT *pLKFStat = pContext->pLKFStat;
    unsigned int i;
	int ret;
    LKF_AUFENTHALT *pAufenthalt;
    
    if (!pLKFStat) return lkf_stat(pContext);
    /* Aufenthalts-Orientierte Durchfuehrung der Statistik */
    for (i = 0; i < pContext->patient_anz; i++)
    {
        pAufenthalt = pContext->ppAufenthalt[i];
        
        if ((pLKFStat->nIgnoreErrors || strchr ("0123", pAufenthalt->FLAG)) &&
            (pLKFStat->nIgnoreMark || (pAufenthalt->mark & 1)))
        {
            ret = lkf_stat_aufenthalt (pLKFStat, pAufenthalt);
			if (ret == LKF_OUTOFMEMORY_ERROR) return LKF_OUTOFMEMORY_UINTERROR;
        }
    }
    return 0;
}

_SCORING_EXPORT unsigned int lkf_stat (LKF_CONTEXT *pContext)
{
	int ret;
	unsigned int i;
	char datbuf[10];
	LKF_STAT *pLKFStat;
	LKF_AUFENTHALT *pAufenthalt;

	if (!pContext->pLKFStat) {
		if (lkf_alloc_context_lkfstat(pContext) == LKF_OUTOFMEMORY_ERROR) {
			return LKF_OUTOFMEMORY_UINTERROR;
		}
	}
	else lkf_reset_lkfstat (pContext->pLKFStat);

	pLKFStat = pContext->pLKFStat;
	
	/* Allokierung der Speicherstrukturen für die Statistik */
	if (pLKFStat->pKADef) pLKFStat->pKACounter = lkf_stat_alloc_counter (pContext, 0, pLKFStat->pKADef);
	lkf_stat_init_fieldidarray (pLKFStat->pKADef, pLKFStat->KAFieldId);

	lkf_stat_init_fieldidarray (pLKFStat->pAbtDef, pLKFStat->AbtFieldId);

	if (pLKFStat->pHauptWohnsitzAggr && pLKFStat->pHauptWohnsitzDef)
	{
		pLKFStat->pHauptWohnsitz = lkf_stat_alloc_aggregation (pContext, pLKFStat->pHauptWohnsitzDef, pLKFStat->pHauptWohnsitzAggr);
	}
	else
	{
		pLKFStat->pHauptWohnsitz = 0;
		pLKFStat->pHauptWohnsitzAggr = 0;
		pLKFStat->pHauptWohnsitzDef = 0;
	}
	lkf_stat_init_fieldidarray (pLKFStat->pHauptWohnsitzDef, pLKFStat->HauptWohnsitzFieldId);

	if (pLKFStat->pAlterAggr && pLKFStat->pAlterDef)
	{
		pLKFStat->pAlter = lkf_stat_alloc_aggregation (pContext, pLKFStat->pAlterDef, pLKFStat->pAlterAggr);
	}
	else 
	{
		pLKFStat->pAlter = 0;
		pLKFStat->pAlterAggr = 0;
		pLKFStat->pAbtDef = 0;
	}
	lkf_stat_init_fieldidarray (pLKFStat->pAlterDef, pLKFStat->AlterFieldId);

	/* Initialisierung von Daten */
	sprintf (datbuf, "%4.4d0101", pContext->cmb_jahr);
	pLKFStat->lFirstDay = (unsigned int) lkf_dat2int (datbuf);
	sprintf (datbuf, "%4.4d1231", pContext->cmb_jahr);
	pLKFStat->lLastDay = (unsigned int) lkf_dat2int (datbuf);

	/* Aufenthalts-Orientierte Durchfuehrung der Statistik */
	for (i = 0; i < pContext->patient_anz; i++)
	{
		pAufenthalt = pContext->ppAufenthalt[i];

		if ((pLKFStat->nIgnoreErrors || strchr ("0123", pAufenthalt->FLAG)) &&
			(pLKFStat->nIgnoreMark || (pAufenthalt->mark & 1)))
		{
			ret = lkf_stat_aufenthalt (pLKFStat, pAufenthalt);
			if (ret == LKF_OUTOFMEMORY_ERROR) {
				return LKF_OUTOFMEMORY_UINTERROR;
			}
		}
	}

	return 0;
}

/***********************************************************************************************
** lkf_stat_getFieldByPosition:                                                               **
**     Liefert einen einzelnen statistischen Wert zurück; als nNr ist die Position anzugeben. **
***********************************************************************************************/

_SCORING_EXPORT unsigned int lkf_stat_getFieldByPosition (LKF_CONTEXT *pContext, unsigned int nType, unsigned int nLine, int nNr, char *sBuf, unsigned int nBufLen)
{
	unsigned int len;
	char sLocalBuf[48];
	LKF_STAT *pLKFStat;
	sLocalBuf[0] = 0;

	pLKFStat = pContext->pLKFStat;
	
	if (pLKFStat)
	{
		if (nNr == LKF_STAT_AGGREGATE_VALUE)
		{
			switch (nType)
			{
				case LKF_STATTYPE_KA:
					if (nLine == 0) sprintf (sLocalBuf, "%4.4s", pContext->KANR);
					break;

				case LKF_STATTYPE_ABT:
					if (nLine < pLKFStat->nAbtCount) strcpy (sLocalBuf, pLKFStat->ppAbtCounter[nLine]->sInfo);
					break;

				case LKF_STATTYPE_ALTER:
					if (pLKFStat->pAlter && nLine < pLKFStat->pAlter->nCount)
						strcpy (sLocalBuf, pLKFStat->pAlter->pAggregationInfo->sDescription[nLine]);
					break;

				case LKF_STATTYPE_HAUPTWOHNSITZ:
					if (pLKFStat->pHauptWohnsitz && nLine < pLKFStat->pHauptWohnsitz->nCount)
						strcpy (sLocalBuf, pLKFStat->pHauptWohnsitz->pAggregationInfo->sDescription[nLine]);
					break;

				default:
					break;
			}
		}
		else if (nNr >= 0) 
		{
			LKF_STAT_COUNTER *pStatCounter = 0;
			switch (nType)
			{
				case LKF_STATTYPE_KA:
					if (nLine == 0) pStatCounter = pLKFStat->pKACounter;
					break;
				case LKF_STATTYPE_ABT:
					if (nLine < pLKFStat->nAbtCount) pStatCounter = pLKFStat->ppAbtCounter[nLine];
					break;
				case LKF_STATTYPE_ALTER:
					if (pLKFStat->pAlter && nLine < pLKFStat->pAlter->nCount)
						pStatCounter = pLKFStat->pAlter->ppCounter[nLine];
					break;
				case LKF_STATTYPE_HAUPTWOHNSITZ:
					if (pLKFStat->pHauptWohnsitz && nLine < pLKFStat->pHauptWohnsitz->nCount)
						pStatCounter = pLKFStat->pHauptWohnsitz->ppCounter[nLine];
					break;
				default:
					break;
			}

			if (pStatCounter && nNr < (int) pStatCounter->pFieldGroup->nCount)
			{
				sprintf (sLocalBuf, "%d", pStatCounter->pCounter[nNr]);
			}
		}
	}	
	strncpy (sBuf, sLocalBuf, nBufLen);
	len = (unsigned int) strlen(sLocalBuf);
	if (len >= nBufLen) sBuf[nBufLen-1] = 0;
	return len;
}

/************************************************************************
** getFieldPosition:                                                   **
**          Retourniert die Position eines Statistik-Felds in der      **
**          Feldgruppe oder -1, wenn das Feld nicht ausgewertet wurde. **
************************************************************************/

_SCORING_EXPORT int lkf_stat_getFieldPosition (LKF_CONTEXT *pContext, unsigned int nType, int nField)
{
    
    LKF_STAT *pLKFStat = pContext->pLKFStat;
    if (pLKFStat == 0) {
        return -1;
    }
    
	switch (nType)
	{
		case LKF_STATTYPE_KA:
			return pLKFStat->KAFieldId[nField];

		case LKF_STATTYPE_ABT:
			return pLKFStat->AbtFieldId[nField];

		case LKF_STATTYPE_ALTER:
			return pLKFStat->AlterFieldId[nField];

		case LKF_STATTYPE_HAUPTWOHNSITZ:
			return pLKFStat->HauptWohnsitzFieldId[nField];

		default:
			return -1;
	}
}

_SCORING_EXPORT unsigned int lkf_stat_getField (LKF_CONTEXT *pContext, unsigned int nType, unsigned int nLine, int nField, char *sBuf, unsigned int nBufLen)
{
	if (nField >= 0) 
	{
		if (!pContext->pLKFStat || nField > LKF_STAT_MAXSTATFIELD) nField = -1;
		else nField = lkf_stat_getFieldPosition (pContext, nType, nField);
			
		if (nField == -1)
		{
			if (nBufLen > 0) sBuf[0] = 0;
			return 0;
		}
	}

	return lkf_stat_getFieldByPosition (pContext, nType, nLine, nField, sBuf, nBufLen);
}

/***************************************************************************************
** lkf_stat_getColumnCount:                                                           **
**     Retourniert die Anzahl Spalten einer Statistik.                                **
***************************************************************************************/

_SCORING_EXPORT unsigned int lkf_stat_getFieldCount (LKF_CONTEXT *pContext, unsigned int nType)
{
	LKF_STAT *pLKFStat;
	pLKFStat = pContext->pLKFStat;
	if (!pLKFStat) return 0;

	switch (nType)
	{
		case LKF_STATTYPE_KA:
			if (pLKFStat->pKADef) return pLKFStat->pKADef->nCount;
			else return 0;

		case LKF_STATTYPE_ABT:
			if (pLKFStat->pAbtDef) return pLKFStat->pAbtDef->nCount;
			else return 0;

		case LKF_STATTYPE_ALTER:
			if (pLKFStat->pAlterDef) return pLKFStat->pAlterDef->nCount;
			else return 0;

		case LKF_STATTYPE_HAUPTWOHNSITZ:
			if (pLKFStat->pHauptWohnsitzDef) return pLKFStat->pHauptWohnsitzDef->nCount;
			else return 0;

		default:
			return 0;
	}
}


_SCORING_EXPORT unsigned int lkf_stat_getFieldAtIndex (LKF_CONTEXT *pContext, unsigned int nType, unsigned int index)
{
    LKF_STAT *pLKFStat;
    pLKFStat = pContext->pLKFStat;
    if (!pLKFStat) return 0;

    switch (nType)
    {
        case LKF_STATTYPE_KA:
            if (pLKFStat->pKADef && pLKFStat->pKADef->nCount > index) return pLKFStat->pKADef->pFields[index]->nFieldNr;
            else return 0;

        case LKF_STATTYPE_ABT:
            if (pLKFStat->pAbtDef && pLKFStat->pAbtDef->nCount > index) return pLKFStat->pAbtDef->pFields[index]->nFieldNr;
            else return 0;

        case LKF_STATTYPE_ALTER:
            if (pLKFStat->pAlterDef && pLKFStat->pAlterDef->nCount > index) return pLKFStat->pAlterDef->pFields[index]->nFieldNr;
            else return 0;

        case LKF_STATTYPE_HAUPTWOHNSITZ:
            if (pLKFStat->pHauptWohnsitzDef && pLKFStat->pHauptWohnsitzDef->nCount > index) return pLKFStat->pHauptWohnsitzDef->pFields[index]->nFieldNr;
            else return 0;

        default:
            return 0;
    }
}


_SCORING_EXPORT unsigned int lkf_stat_getFieldHeadlineByPosition (LKF_CONTEXT *pContext, unsigned int nType, int nNr, char *sBuf, unsigned int nBufLen)
{
	unsigned int len;
	char sLocalBuf[48];
	LKF_STAT *pLKFStat;
	sLocalBuf[0] = 0;

	pLKFStat = pContext->pLKFStat;

	if (pLKFStat)
	{
		if (nNr == LKF_STAT_AGGREGATE_VALUE)
		{
			switch (nType)
			{
				case LKF_STATTYPE_KA:
					strcpy (sLocalBuf, "KA");
					break;
				case LKF_STATTYPE_ABT:
					strcpy (sLocalBuf, "ABTFC");
					break;
				case LKF_STATTYPE_ALTER:
					strcpy (sLocalBuf, "ALTER");
					break;
				case LKF_STATTYPE_HAUPTWOHNSITZ:
					strcpy (sLocalBuf, "BUNDESLAND");
					break;
				default:
					break;
			}
		}
		else if (nNr >= 0) 
		{
			const LKF_STAT_FIELDGROUP *pFieldGroup = 0;
			switch (nType)
			{
				case LKF_STATTYPE_KA:
					pFieldGroup = pLKFStat->pKADef;
					break;
				case LKF_STATTYPE_ABT:
					pFieldGroup = pLKFStat->pAbtDef;
					break;
				case LKF_STATTYPE_ALTER:
					pFieldGroup = pLKFStat->pAlterDef;
					break;
				case LKF_STATTYPE_HAUPTWOHNSITZ:
					pFieldGroup = pLKFStat->pHauptWohnsitzDef;
					break;
			}

			if (pFieldGroup && nNr < (int)pFieldGroup->nCount) strcpy (sLocalBuf, pFieldGroup->pFields[nNr]->sShort);
		}
	}
	strncpy (sBuf, sLocalBuf, nBufLen);
	len = (unsigned int) strlen(sLocalBuf);
	if (len >= nBufLen) sBuf[nBufLen-1] = 0;
	return len;
}

_SCORING_EXPORT unsigned int lkf_stat_getFieldHeadline (LKF_CONTEXT *pContext, unsigned int nType, int nField, char *sBuf, unsigned int nBufLen)
{
	if (nField >= 0) 
	{
		if (!pContext->pLKFStat || nField > LKF_STAT_MAXSTATFIELD) nField = -1;
		else nField = lkf_stat_getFieldPosition (pContext, nType, nField);
			
		if (nField == -1)
		{
			if (nBufLen > 0) sBuf[0] = 0;
			return 0;
		}
	}

	return lkf_stat_getFieldHeadlineByPosition (pContext, nType, nField, sBuf, nBufLen);
}

_SCORING_EXPORT int lkf_stat_getLineByLineInfo (LKF_CONTEXT *pContext, unsigned int nType, const char *sInfo)
{
	unsigned int i;
	LKF_STAT *pLKFStat = pContext->pLKFStat;
	if (!pLKFStat) return 0;

	switch (nType)
	{
		case LKF_STATTYPE_KA:
			if (pLKFStat->pKADef && strcmp (pContext->KANR, sInfo)) return 0;
			else return -1;
		case LKF_STATTYPE_ABT:
			if (pLKFStat->pAbtDef) 
			{
				for (i = 0; i < pLKFStat->nAbtCount; i++)
				{
					if (strcmp (pLKFStat->ppAbtCounter[i]->sInfo, sInfo)) return (int) i;
				}
			}
			return -1;
		case LKF_STATTYPE_ALTER:
			return -1;
		case LKF_STATTYPE_HAUPTWOHNSITZ:
			return -1;
		default:
			return 0;
	}
}

LKF_CASESTAT *lkf_alloc_context_casestat (LKF_CONTEXT *pContext)
{ /* V21.0 */
    if (pContext->pCaseStats != 0) {
        lkf_free_context_casestat(pContext);
    }
    pContext->pCaseStats = (LKF_CASESTAT *) LKF_CALLOC (pContext, "lkf_alloc_context_casestat", 1, sizeof(LKF_CASESTAT));
    if (!pContext->pCaseStats) return 0;

    pContext->pCaseStats->category_alloc = 10;
    pContext->pCaseStats->pCategories =(LKF_CASESTAT_CATEGORY *) LKF_CALLOC(pContext, "lkf_alloc_context_casestat", pContext->pCaseStats->category_alloc, sizeof(LKF_CASESTAT_CATEGORY));
    if (!pContext->pCaseStats->pCategories) {
        LKF_FREE(pContext, "lkf_alloc_context_casestat", pContext->pCaseStats);
    }
    return pContext->pCaseStats;
}

LKF_CASESTAT *lkf_free_context_casestat (LKF_CONTEXT *pContext)
{
    if (pContext->pCaseStats) {
        LKF_FREE (pContext, "lkf_free_context_casestat.category", pContext->pCaseStats->pCategories);
        LKF_FREE (pContext, "lkf_free_context_casestat", pContext->pCaseStats);
        pContext->pCaseStats = 0;
    }
    return pContext->pCaseStats;
}

#ifdef ENABLE_CASESTAT
static int compare_stat_category (const void *pattern, const void *candidate) {
    LKF_CASESTAT_CATEGORY *pCat = (LKF_CASESTAT_CATEGORY *) candidate;
    return strcmp (pattern, pCat->key);
}

static const char *CreateCaseStatKey (const char *category, const char *ident, char *buffer) {
    sprintf(buffer, "%s.%s", category, ident);
    return buffer;
}

static LKF_CASESTAT_CATEGORY *GetCategory (const char *category, const char *ident, LKF_CONTEXT *pContext, int bCreate)
{
    int minindex, maxindex, curindex;
    
    char keybuffer[CASESTAT_KEY_MAX];
    LKF_CASESTAT *pCaseStats;
    LKF_CASESTAT_CATEGORY *pCategory = 0;
    LKF_CASESTAT_CATEGORY *pAll;
    
    pCaseStats = pContext->pCaseStats;
    if (pCaseStats == 0) {
        if (!bCreate) return 0;
        pCaseStats = lkf_alloc_context_casestat(pContext);
        CreateCaseStatKey(category, ident, keybuffer);
    }
    else {
        pCategory = (LKF_CASESTAT_CATEGORY *) bsearch(CreateCaseStatKey(category, ident, keybuffer), pCaseStats->pCategories, pCaseStats->category_anz, sizeof(LKF_CASESTAT_CATEGORY), compare_stat_category);
    }
    
    if (pCategory || !bCreate)
        return pCategory;
    
    if (pCaseStats->category_anz == pCaseStats->category_alloc) {
        LKF_CASESTAT_CATEGORY *pOld = pCaseStats->pCategories;
        pCaseStats->category_alloc += 10;
        pCaseStats->pCategories = (LKF_CASESTAT_CATEGORY *) LKF_CALLOC(sizeof(LKF_CASESTAT_CATEGORY), pCaseStats->category_alloc);
        memcpy (pCaseStats->pCategories, pOld, sizeof(LKF_CASESTAT_CATEGORY) * pCaseStats->category_alloc);
        LKF_FREE (pOld);
    }
    
    minindex = -1;
    maxindex = (int) pCaseStats->category_anz;
    pAll = pCaseStats->pCategories;
    
    while (minindex + 1 < maxindex) {
        curindex = (minindex + maxindex) / 2;
        if (strcmp(keybuffer, pAll[curindex].key) < 0) {
            maxindex = curindex;
        }
        else {
            minindex = curindex;
        }
    }
    
    if (maxindex < (int) pCaseStats->category_anz) {
        memmove(pAll + maxindex + 1, pAll + maxindex, sizeof(LKF_CASESTAT_CATEGORY) * (pCaseStats->category_anz - (unsigned int) maxindex));
    }
    
    pCategory = pAll + maxindex;
    pCaseStats->category_anz++;
    memset(pCategory, 0, sizeof(LKF_CASESTAT_CATEGORY));
    strcpy(pCategory->category, category);
    strcpy(pCategory->ident, ident);
    strcpy(pCategory->key, keybuffer);
    return pCategory;
}
#endif

int lkf_stat_register_case (LKF_AUFENTHALT *pAufenthalt, const char *category, const char *ident)
{
#ifdef ENABLE_CASESTAT
    LKF_CASESTAT_CATEGORY *pCat;
    if (pAufenthalt->pScoringContext == 0) return -1;
    
    pCat = GetCategory(category, ident, pAufenthalt->pScoringContext, 1);
    if (pCat) {
        switch (pAufenthalt->isAmb) {
            case 0:
                pCat->stat++;
                break;
            case 1:
                pCat->amb++;
                break;
            case 2:
                pCat->ambstat++;
                break;
            default:
                break;
        }
    }
    return 0;
#else
    return -2;
#endif
}

_SCORING_EXPORT unsigned int lkf_casestat_get_category_count (LKF_CONTEXT *pContext) {
    if (pContext->pCaseStats)
        return pContext->pCaseStats->category_anz;
    return 0;
}

_SCORING_EXPORT LKF_CASESTAT_CATEGORY *lkf_casestat_get_category(LKF_CONTEXT *pContext, unsigned int index) {
    if (pContext->pCaseStats && pContext->pCaseStats->category_anz > index)
        return pContext->pCaseStats->pCategories + index;
    return 0;
}

