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

#include "lkfint5.h"

_SCORING_EXPORT unsigned int lkf_trace_getLineCount (const LKF_CONTEXT *pContext)
{
	if (pContext && pContext->pTraceLineBuffer)
		return (unsigned int) pContext->pTraceLineBuffer->lLineCount;
	else
		return 0;
}

_SCORING_EXPORT const char *lkf_trace_getLine (const LKF_CONTEXT *pContext, unsigned int nLineNr)
{
	if (pContext && pContext->pTraceLineBuffer && nLineNr < pContext->pTraceLineBuffer->lLineCount)
		return pContext->pTraceLineBuffer->pBuf + pContext->pTraceLineBuffer->plOffsets[nLineNr];
	else
		return 0;
}

int lkf_isTraceInfo (const LKF_CONTEXT *pContext, int nFacility)
{
	int nTraceMode = lkf_getTraceMode (pContext, nFacility);
	return LKF_IS_TRACE_INFO(nTraceMode);
}

int lkf_isTraceInput (const LKF_CONTEXT *pContext, int nFacility)
{
	int nTraceMode = lkf_getTraceMode (pContext, nFacility);
	return LKF_IS_TRACE_INPUT (nTraceMode);
}

int lkf_isTraceDetail (const LKF_CONTEXT *pContext, int nFacility)
{
	int nTraceMode = lkf_getTraceMode (pContext, nFacility);
	return LKF_IS_TRACE_DETAIL (nTraceMode);
}

int lkf_trace_SetFacility (LKF_CONTEXT *pContext, const char *sLine)
{
	if (!sLine)
		pContext->nCurrentFacility = 0;
	else
	{
		switch (*sLine)
		{
			case 'M':
				pContext->nCurrentFacility = LKF_FAC_MBDS;
				break;
			case 'K':
				pContext->nCurrentFacility = LKF_FAC_KAS_KORE;
				break;
			case 'B':
				pContext->nCurrentFacility = LKF_FAC_BERICHT;
				break;
			case 'G':
				pContext->nCurrentFacility = LKF_FAC_GG;
				break;
			case 'I':
				pContext->nCurrentFacility = LKF_FAC_INTSCOR;
				break;
            case 'A':
                if (pContext->modelljahr >= SATZART_A_MODEL) {
                    pContext->nCurrentFacility = LKF_FAC_A;
                }
                else {
                    pContext->nCurrentFacility = 0;
                }
                break;
			default:
				pContext->nCurrentFacility = 0;
				break;
		}
	}
	return pContext->nCurrentFacility;
}

int lkf_getTraceMode (const LKF_CONTEXT *pContext, int nFacility)
{
	if (!nFacility)
		nFacility = pContext->nCurrentFacility;

	if (nFacility == LKF_FAC_MBDS)
		return pContext->nTraceAufenthalt;
	if (nFacility == LKF_FAC_INTSCOR)
		return pContext->nTraceAufenthaltIntScor;
	if (!pContext || !pContext->pTraceSettings)
		return LKF_TRACE_OFF;

	switch (nFacility)
	{
		case LKF_FAC_KAS_KORE:
			return pContext->pTraceSettings->nKasKoreSeverity;
		case LKF_FAC_MBDS:
			return pContext->pTraceSettings->nMBDSSeverity;
		case LKF_FAC_INTSCOR:
			return pContext->pTraceSettings->nIntSeverity;
		default:
			return 0;
	}
}

static void TraceAdd (LKF_CONTEXT *pContext, const char *sLine)
{
	if (!pContext->pTraceSettings)
		return;

    if (pContext->pTraceSettings->traceDelegate) {
        pContext->pTraceSettings->traceDelegate(pContext, sLine);
        if (!pContext->pTraceSettings->bSaveProtocol) {
            pContext->pTraceSettings->bFirst = 0;
            return;
        }
    }
    
	if (pContext->pTraceSettings->sFileName[0])
	{
		if (!pContext->pTraceSettings->fp)
		{
			pContext->pTraceSettings->fp = fopen (pContext->pTraceSettings->sFileName, pContext->pTraceSettings->bFirst ? "w" : "a");
			if (!pContext->pTraceSettings->fp)
				return;
		}
		fprintf (pContext->pTraceSettings->fp, "%s\n", sLine);

		if (pContext->pTraceSettings->bSafeFile)
		{
			fclose (pContext->pTraceSettings->fp);
			pContext->pTraceSettings->fp = 0;
		}
	}

	if (pContext->pTraceSettings->bSaveProtocol)
	{
		if (!pContext->pTraceLineBuffer)
		{
			pContext->pTraceLineBuffer = lkf_create_linebuffer (pContext);
			lkf_add_dynamic_line (pContext, pContext->pTraceLineBuffer, ";F;S; PATID      ; ABTFC    ; TEXT");
		}

		lkf_add_dynamic_line (pContext, pContext->pTraceLineBuffer, sLine);
	}
	pContext->pTraceSettings->bFirst = 0;
}

static char lkf_getFacilityCode (int nFacility)
{
	switch (nFacility)
	{
		case LKF_FAC_MBDS:
			return 'M';
		case LKF_FAC_KAS_KORE:
			return 'K';
		case LKF_FAC_BERICHT:
			return 'B';
		case LKF_FAC_GG:
			return 'G';
		case LKF_FAC_INTSCOR:
			return 'I';
        case LKF_FAC_A:
            return 'A';
		default:
			return ' ';
	}
}

static char lkf_getSeverityCode (int nSeverity)
{
	switch (nSeverity)
	{
		case LKF_TRACE_INFO:
			return 'I';
		case LKF_TRACE_DETAIL:
			return 'D';
		default:
			return ' ';
	}
}

void lkf_trace_mbds_aufenthalt (LKF_CONTEXT *pContext, LKF_AUFENTHALT *pAufenthalt)
{
	unsigned int i, nLineCount = lkf_auf_getlineanz (pAufenthalt);
	char sLine[1024];

	for (i = 0; i < nLineCount; i++)
	{
		lkf_auf_getline (pAufenthalt, i, sLine);
		lkf_addTraceInputLine (pContext, sLine);
	}

	if (pAufenthalt->pLineBuffer) {
	
		for (i = 0; i < pAufenthalt->pLineBuffer->lLineCount; i++) {
			lkf_addTraceInputLine (pContext, pAufenthalt->pLineBuffer->pBuf + pAufenthalt->pLineBuffer->plOffsets[i]);
		}
	
	}
}


void lkf_addTraceLineContext (LKF_CONTEXT *pContext, const char *sLine, int nFacility, int nSeverity)
{

	char sBuf[1024];
	if (!nFacility) nFacility = pContext->nCurrentFacility;
	sprintf (sBuf, ";%c;%c;            ;          ; ", lkf_getFacilityCode (nFacility), lkf_getSeverityCode (nSeverity));
	strncpy (sBuf + 30, sLine, 994);
	sBuf[1023] = 0;
	TraceAdd (pContext, sBuf);
}

void lkf_addTraceAbteilungLine (LKF_CONTEXT *pContext, const char *sAbtFC, const char *sLine, int nFacility, int nSeverity)
{
	char sBuf[1024];
	if (!nFacility) nFacility = pContext->nCurrentFacility;
	sprintf (sBuf, ";%c;%c;            ; %8.8s ; ",  lkf_getFacilityCode (nFacility), lkf_getSeverityCode (nSeverity), sAbtFC ? sAbtFC : "");
	strncpy (sBuf + 30, sLine, 994);
	sBuf[1023] = 0;
	TraceAdd (pContext, sBuf);	
}

void lkf_addTraceAufenthaltAbteilungLine (LKF_CONTEXT *pContext, LKF_AUFENTHALT *pAufenthalt, const char *sAbtFC, const char *sLine, int nFacility, int nSeverity)
{
	char sBuf[1024];
	if (!nFacility) nFacility = pContext->nCurrentFacility;
	sprintf (sBuf, ";%c;%c; %10.10s ; %8.8s ; ",  lkf_getFacilityCode (nFacility), lkf_getSeverityCode (nSeverity), pAufenthalt ? pAufenthalt->PATID : "", sAbtFC ? sAbtFC : "");
	strncpy (sBuf + 30, sLine, 994);
	sBuf[1023] = 0;
	TraceAdd (pContext, sBuf);	
}

void lkf_addTraceLine (LKF_CHECK_CONTEXT *pContext, const char *sLine, int nFacility, int nSeverity)
{
	const char *sAbtFC;

	if (pContext->nAbtIndex >= 0 && pContext->pAufenthalt && (unsigned int) pContext->nAbtIndex < pContext->pAufenthalt->abt_anz)
		sAbtFC = pContext->pAufenthalt->abt[pContext->nAbtIndex].ABTFC;
	else
		sAbtFC = "";

	lkf_addTraceAufenthaltAbteilungLine (pContext->pContext, pContext->pAufenthalt, sAbtFC, sLine, nFacility, nSeverity);
}

void lkf_addTraceAufenthaltLine (LKF_CONTEXT *pContext, LKF_AUFENTHALT *pAufenthalt, int nAbt, const char *sLine, int nFacility, int nSeverity)
{
	const char *sAbtFC = 0;

	if (pAufenthalt && pContext && pContext->pTraceSettings && pContext->pTraceSettings->sPATID[0])
    {
        if (pContext->isBM) {
            if (memcmp (pContext->pTraceSettings->sPATID, pAufenthalt->UCASE_PATID, LKF_AUFENTHALT_LONGID_LEN))
                return;
        }
        else if (memcmp (pContext->pTraceSettings->sPATID, pAufenthalt->PATID, LKF_AUFENTHALT_PATID_LEN)) {
            return;
        }
	}

	if (pAufenthalt && nAbt >= 0 && pAufenthalt->abt_anz > (unsigned int) nAbt)
	{
		sAbtFC = pAufenthalt->abt[nAbt].ABTFC;
	}
	lkf_addTraceAufenthaltAbteilungLine (pContext, pAufenthalt, sAbtFC, sLine, nFacility, nSeverity);

}

void lkf_addTraceInputLine (LKF_CONTEXT *pContext, const char *sLine)
{
	TraceAdd (pContext, sLine);
}

static LKF_TRACE_SETTINGS *ContextTraceParameters (LKF_CONTEXT *pContext)
{
	if (!pContext->pTraceSettings)
	{
		pContext->pTraceSettings = (LKF_TRACE_SETTINGS *) LKF_MALLOC (pContext, "ContextTraceParameters", sizeof(LKF_TRACE_SETTINGS));
        if (!pContext->pTraceSettings) return 0;
		pContext->pTraceSettings->nIntSeverity = 0;
		pContext->pTraceSettings->nKasKoreSeverity = 0;
		pContext->pTraceSettings->nMBDSSeverity = 0;
		pContext->pTraceSettings->sPATID[0] = 0;
		pContext->pTraceSettings->sFileName[0] = 0;
		pContext->pTraceSettings->bFirst = 1;
		pContext->pTraceSettings->bSafeFile = 0;
		pContext->pTraceSettings->bSaveProtocol = 1;
		pContext->pTraceSettings->fp = 0;
        pContext->pTraceSettings->traceDelegate = 0;
	}
	return pContext->pTraceSettings;
}

_SCORING_EXPORT void lkf_set_debug_tracefile (LKF_CONTEXT *pContext, const char *sFile, int bSafeFile, int bFileOnly)
{
	LKF_TRACE_SETTINGS *pTraceSettings = ContextTraceParameters (pContext);

	if (pTraceSettings->fp)
	{
		fclose (pTraceSettings->fp);
		pTraceSettings->fp = 0;
	}
	
	pTraceSettings->bFirst = 1;

	if (sFile)
	{
		strncpy (pTraceSettings->sFileName, sFile, LKF_TRACE_FILENAME_LEN);
		pTraceSettings->sFileName[LKF_TRACE_FILENAME_LEN-1] = 0;
		pTraceSettings->bSafeFile = bSafeFile;
		pTraceSettings->bSaveProtocol = !bFileOnly;
	}
	else
	{
		pTraceSettings->bSaveProtocol = 1;
		pTraceSettings->sFileName[0] = 0;
	}
}

_SCORING_EXPORT void lkf_set_debug_tracecb (LKF_CONTEXT *pContext, LKFTRACE_DELEGATE traceDelegate, int bSave) {
    LKF_TRACE_SETTINGS *pTraceSettings = ContextTraceParameters (pContext);

    if (pTraceSettings->fp)
    {
        fclose (pTraceSettings->fp);
        pTraceSettings->fp = 0;
    }
    
    pTraceSettings->traceDelegate = traceDelegate;
    pTraceSettings->bFirst = 1;
    pTraceSettings->bSaveProtocol = bSave;
    pTraceSettings->sFileName[0] = 0;
}

_SCORING_EXPORT void lkf_finish_debug_tracecb (LKF_CONTEXT *pContext) {
    
    if (pContext && pContext->pTraceSettings) {
        pContext->pTraceSettings->traceDelegate = 0;
    }
}

_SCORING_EXPORT void lkf_set_debug_trace (LKF_CONTEXT *pContext)
{
	LKF_TRACE_SETTINGS *pTraceSettings = ContextTraceParameters (pContext);
	pTraceSettings->nIntSeverity = LKFTRACE_DEBUG_INTSCOR;
	pTraceSettings->nKasKoreSeverity = LKFTRACE_DEBUG_KASKORE;
	pTraceSettings->nMBDSSeverity = LKFTRACE_DEBUG_MBDS;
	sprintf (pTraceSettings->sPATID, LKFTRACE_DEBUG_PATID);
	sprintf (pTraceSettings->sFileName, LKFTRACE_DEBUG_FILENAME);
	pTraceSettings->bFirst = 1;
	pTraceSettings->bSafeFile = LKFTRACE_DEBUG_SAFE_FILE;
	pTraceSettings->bSaveProtocol = LKFTRACE_DEBUG_SAVEPROTOCOL;
}

_SCORING_EXPORT void lkf_trace_setAufenthalt (LKF_CONTEXT *pContext, const char *sPATID)
{
    LKF_TRACE_SETTINGS *pSettings;
    pSettings = ContextTraceParameters (pContext);
    strncpy (pSettings->sPATID, sPATID, LKF_AUFENTHALT_LONGID_LEN_AB2017);
	pSettings->sPATID[LKF_AUFENTHALT_LONGID_LEN_AB2017] = 0;
}

_SCORING_EXPORT void lkf_trace_setLevel (LKF_CONTEXT *pContext, int nFacility, int nLevel)
{
	LKF_TRACE_SETTINGS *pSettings = ContextTraceParameters (pContext);
	switch (nFacility)
	{
	case LKF_FAC_MBDS:
		pSettings->nMBDSSeverity = nLevel;
		break;
	case LKF_FAC_INTSCOR:
		pSettings->nIntSeverity = nLevel;
		break;
	case LKF_FAC_KAS_KORE:
	case LKF_FAC_GG:
		pSettings->nKasKoreSeverity = nLevel;
		break;
	default:
		pSettings->nMBDSSeverity = nLevel;
		pSettings->nIntSeverity = nLevel;
		pSettings->nKasKoreSeverity = nLevel;
		break;
	}
}

_SCORING_EXPORT const char *lkf_trace_getAufenthalt (const LKF_CONTEXT *pContext)
{
	if (pContext && pContext->pTraceSettings && pContext->pTraceSettings->sPATID[0])
		return pContext->pTraceSettings->sPATID;
	return 0;
}

_SCORING_EXPORT int lkf_trace_getLevel (const LKF_CONTEXT *pContext, unsigned int nFacility)
{
	if (pContext && pContext->pTraceSettings)
	{
		switch (nFacility)
		{
			case LKF_FAC_MBDS:
				return pContext->pTraceSettings->nMBDSSeverity;
			case LKF_FAC_INTSCOR:
				return pContext->pTraceSettings->nIntSeverity;
			case LKF_FAC_GG:
			case LKF_FAC_KAS_KORE:
				return pContext->pTraceSettings->nKasKoreSeverity;
			default:
				return 0;
		}
	}
	return 0;
}

_SCORING_EXPORT void lkf_trace_finished (LKF_CONTEXT *pContext)
{
    if (pContext && pContext->pTraceSettings) {
        if (pContext->pTraceSettings->fp)
        {
            fclose (pContext->pTraceSettings->fp);
            pContext->pTraceSettings->fp = 0;
        }
    }
}
