// Processor.cpp : Implementation of CProcessor

#include "stdafx.h"
#include "LKFStatic.h"
#include "Processor.h"
#include "Output.h"
#include "Buffer.h"
#include "Protocol.h"

#define MAX_ELEMENT_LEN 1024

#ifdef LKFSERVER_LOG_MODE
void log (const char *s)
{
	static int first = 1;
	FILE *fp = fopen (LKFSERVER_LOG_FILENAME, first ? "w" :"a");
	first = 0;
	if (fp) {

		fprintf (fp, "%s\n", s);
		fclose (fp);
	}
}
#endif

// CProcessor

CProcessor::CProcessor ()
{
	const char *importsep, *exportsep;
	pOutputBuffer = 0;
	ctx = lkf_alloc_context (0, "", 0);
	pLKFStatic = GetStaticObject ();
	pLKFStatic->GetCurrentLineSeparators (&importsep, &exportsep);
	strcpy (LineSepExport, exportsep);
	strcpy (LineSepImport, importsep);
	LineSepExportLen = (unsigned int) strlen (LineSepExport);
	LineSepImportLen = (unsigned int) strlen (LineSepImport);
	pOutputBuffer = 0;
	m_OutputFile = 0;
	m_InputFile = 0;
	ppFilter = 0;
	nFilterCount = 0;

	pProtocolObject = new ProtocolObject ();
	GetStaticProtocolObject()->SaveAddObject (pProtocolObject);

	m_LastUsedModelYear = 0;
	FixedModelYear = 0;

	*sLastError = 0;
	stammdaten_ok = 0;
	modelljahr_gesetzt = 0;
}

CProcessor::~CProcessor ()
{
	if (pOutputBuffer) delete pOutputBuffer;
	lkf_free_context (ctx);

	if (ppFilter) delete ppFilter;

	pProtocolObject->SaveClose ();
}

int getInt (const char *line, int len)
{
	char b[MAX_ELEMENT_LEN];
	strncpy (b, line, len);
	b[len] = 0;
	return atoi (b);
}

#define CPROCESSOR_MAX_LINE 2048

int CProcessor::ComputeLine (const char *line)
{
	const char *delimiter; /* V12.0: const */
	int offset = 0;
	int l;
	char buf[CPROCESSOR_MAX_LINE];

#ifdef LKFSERVER_LOG_MODE
	static int counter = 0;
	char lbuf[1024];


	sprintf (lbuf, "ComputeLine(%d) called.\n", counter++);
	log(lbuf);

#endif

	delimiter = strstr (line, LineSepImport);
	
	if (delimiter) l = (int) (delimiter - line);
	else l = (int)  strlen (line);

	if (l < CPROCESSOR_MAX_LINE) {
		memcpy (buf, line, l);
		buf[l] = 0;
		lkf_add_line (ctx, buf);

		if (delimiter) {
			while (line[++l] && strchr (LineSepImport, line[l]));
			return l;
		}
		else return l;
	}
	else
	{
		sprintf (sLastError, "Zeile zu lang (%d Zeichen)", l);
		return -1;
	}
	return 0;
}

STDMETHODIMP CProcessor::SetData(BSTR Buffer, LONG* ReturnCode)
{
	char *d = createChar (Buffer);
	char *c = d;
	int offset;
	int l = (int) strlen (d);

	*sLastError = 0;

	
#ifdef LKFSERVER_LOG_MODE
	char buf[1024];
	sprintf (buf, "SetData called with %d bytes", l);
	log (buf);
#endif

	while (*c) {
		offset = ComputeLine (c);
		if (offset < 0) 
		{
			if (ReturnCode) *ReturnCode = offset;		
			return S_OK;
		}
		c += offset;
	}
	delete d;
	if (ReturnCode) *ReturnCode = 0;
	return S_OK;
}

STDMETHODIMP CProcessor::Compute(LONG Model, LONG Flags, LONG MaxAuf)
{
	*sLastError = 0;
	if (!stammdaten_ok) 
	{
		strcpy (sLastError, "Fehler beim Scoring: Stammdaten nicht initialisiert.");
	}
	else 
	{
		lkf_context_scoring (ctx, 0);
	}
	return S_OK;
}

#define OUTPUTFILE_SCORING		 0
#define OUTPUTFILE_ERROR		 1
#define OUTPUTFILE_WARNING		 2
#define OUTPUTFILE_MELDEDIAG	 3
#define OUTPUTFILE_INTSCORING	 4
#define OUTPUTFILE_CHECK_ERROR	 5
#define OUTPUTFILE_CHECK_WARNING 6
#define OUTPUTFILE_DATA			 7
#define OUTPUTFILE_STAT			 8
#define OUTPUTFILE_OPTIMIZER	11
#define OUTPUTFILE_NPPLAUS		12
#define OUTPUTFILE_NPPLAUS_SUM  13 /* V10.0 */
#define OUTPUTFILE_CSV			21
#define OUTPUTFILE_STAMM		31
#define OUTPUTFILE_SATZART	    32
#define OUTPUTFILE_ERRORLIST	33
#define OUTPUTFILE_PROTOCOL	    41
#define OUTPUTFILE_TRACE        42
#define OUTPUTFILE_CHECK_INFO   9

int CProcessor::FinishPrepareOutput (Output *pOutput, LONG *buflen)
{
	if (pOutputBuffer) delete pOutputBuffer;
	pOutputBuffer = new BufferChar ();
	pOutputBuffer->SetLineSeparator (LineSepExport, LineSepExportLen);
	pOutput->FillBuffer (ctx, pOutputBuffer);
	if (buflen) *buflen = (LONG) pOutputBuffer->GetCharCount ();
	return 0;
}

STDMETHODIMP CProcessor::PrepareOutput(LONG type, LONG flags, LONG* buflen)
{
	Output *pOutput;
	const char *sType;
	char sParameter[128];

	*sLastError = 0;

	switch (type)
	{
		case OUTPUTFILE_SCORING:
			pOutput = new OutputScoringFile (flags);
			sType = "Scoring-File";
			break;

		case OUTPUTFILE_ERROR:
			pOutput = new OutputPlausErrorFile (flags);
			if (m_InputFile) pOutput->SetInputFileName (m_InputFile);
			if (m_OutputFile) pOutput->SetOutputFileName (m_OutputFile);
			sType = "Error-File";
			break;

		case OUTPUTFILE_WARNING:
			pOutput = new OutputPlausWarningFile (flags);
			if (m_InputFile) pOutput->SetInputFileName (m_InputFile);
			if (m_OutputFile) pOutput->SetOutputFileName (m_OutputFile);
			((OutputPlausWarningFile *) pOutput)->SetModelYear (m_LastUsedModelYear);
			sType = "Warning-File";
			break;

		case OUTPUTFILE_MELDEDIAG:
			pOutput = new OutputMeldeDiagFile (flags);
			((OutputMeldeDiagFile *) pOutput)->SetModelYear (m_LastUsedModelYear);
			sType = "MeldeDiag-File";
			break;

		case OUTPUTFILE_STAT:
			pOutput = new OutputStatFile (flags);
			sType = "Stat-File";
			break;

		case OUTPUTFILE_TRACE:
			pOutput = new OutputTraceFile (flags);
			sType = "Trace-File";
			break;

		case OUTPUTFILE_INTSCORING:
			pOutput = new OutputIntensivScoringFile (flags);
			sType = "Intensiv-Scoring";
			break;

		case OUTPUTFILE_CHECK_ERROR:
			pOutput = new OutputCheckFile (0, flags);
			sType = "Check-Errors";
			break;

		case OUTPUTFILE_CHECK_WARNING:
			pOutput = new OutputCheckFile (1, flags);
			sType = "Check-Warnings";
			break;

		case OUTPUTFILE_CHECK_INFO:
			pOutput = new OutputCheckFile (2, flags);
			sType = "Check-Infos";
			break;


		case OUTPUTFILE_DATA:
			pOutput = new OutputDataFile (flags);
			sType = "Data-File";
			break;

		case OUTPUTFILE_ERRORLIST:
			pOutput = new OutputErrorListFile (flags);
			sType = "Error List";
			break;

		case OUTPUTFILE_SATZART:
			pOutput = new OutputSatzartFile (m_LastUsedModelYear, flags);
			sType = "Satzart-Definitionen";
			break;

		case OUTPUTFILE_OPTIMIZER:
			pOutput = new OutputScoringOptimizerFile (flags);
			sType = "Optimizer";
			break;

		case OUTPUTFILE_NPPLAUS:
			pOutput = new OutputPlausNPFile (flags);
			sType = "NP-Plaus-Check";
			break;

		case OUTPUTFILE_NPPLAUS_SUM: /* V10.0 */
			pOutput = new OutputNPSumFile (flags);
			sType = "NP-Plaus-Summen";
			break;

		case OUTPUTFILE_PROTOCOL:
			pOutput = new OutputProtocolFile (flags);
			sType = "Protocol";
			break;

		default:
			sType = "undefiniert";
			pOutput = new Output (flags);
			break;

	}
	
	sprintf (sParameter, "Type = %s, Flags = %d", sType, flags);
	ProtocolCall *pCall = new ProtocolCall ("PrepareOutput", sParameter);

	FinishPrepareOutput (pOutput, buflen);
	
	sprintf (sParameter, "Buffer-Length = %d", *buflen);
	
	pCall->SetResult (sParameter);
	pProtocolObject->SaveAddCall (pCall);
	delete pOutput;
	return S_OK;
}

unsigned int CProcessor::CreateUIntArray (VARIANT var, unsigned int *&array)
{
	unsigned int *fieldnumbers;
	unsigned int i, count;

	array = 0;

	if (var.vt & VT_ARRAY) {
	
		SAFEARRAY *pArray;
		
		if (var.vt & VT_BYREF) pArray = *var.pparray;
		else pArray = var.parray;
	
		if ((pArray->fFeatures & FADF_HAVEVARTYPE) && pArray->cDims == 1) {
			
			unsigned int element_size;
			element_size = pArray->cbElements;

			/* int datatype = ((unsigned long *)pArray)[-1]; */
			count = pArray->rgsabound[0].cElements;
			if (count > 0 && (element_size == 4 || element_size == 2 || element_size == 16)) {
				fieldnumbers = new unsigned int [count];

				if (element_size == 4) 
				{
					unsigned long *p = (unsigned long *) pArray->pvData;
					for (i = 0; i < count; i++) fieldnumbers[i] = p[i];
				}
				else if (element_size == 16)
				{
					unsigned long *p = (unsigned long *) pArray->pvData;
					for (i = 0; i < count; i++) fieldnumbers[i] = p[i*4+2];
				}
				else 
				{
					unsigned short *p = (unsigned short *) pArray->pvData;
					for (i = 0; i < count; i++) fieldnumbers[i] = p[i];
				}
				array = fieldnumbers;
				return count;
				
			}
			else return 0;
		}
		else return 0;		
	}
	else if (var.vt & VT_BSTR)
	{ /* V10.1 - comma-separated strings werden auch akzeptiert */
		char *s = 0;	
		if (var.vt & VT_BYREF && var.pbstrVal && *var.pbstrVal)
			s = createChar (*var.pbstrVal);
		else
			s = createChar (var.bstrVal);
		
		if (s)
		{
			const char *pCurrent = s;

			count = 0;

			while (pCurrent)
			{
				if ((*pCurrent >= '0' && *pCurrent <= '9') || *pCurrent == ' ')
				{
					pCurrent = strchr (pCurrent, ',');
					if (pCurrent) ++pCurrent;
					count++;
				}
				else
					pCurrent = 0;
			}
			
			if (!count)
				return 0;

			fieldnumbers = new unsigned int [count];

			count = 0;
			pCurrent = s;
			while (pCurrent)
			{
				if ((*pCurrent >= '0' && *pCurrent <= '9')  || *pCurrent == ' ')
				{
					fieldnumbers[count] = atoi (pCurrent);
					pCurrent = strchr (pCurrent, ',');
					if (pCurrent) ++pCurrent;
					count++;
				}
				else
					pCurrent = 0;
			}
			delete s;
			array = fieldnumbers;
			return count;
		}
		else return 0;
	}
	else return 0;
}

void CProcessor::FreeUIntArray (unsigned int *&array)
{
	if (array) {
		delete array;
		array = 0;
	}
}


STDMETHODIMP CProcessor::PrepareOutputEx(LONG type, LONG flags, VARIANT parameters, LONG* buflen)
{
	Output *pOutput;
	unsigned int *fieldnumbers;
	unsigned int count;
	char *c;

	*sLastError = 0;

	switch (type)
	{
	case OUTPUTFILE_CSV:

		count = CreateUIntArray (parameters, fieldnumbers);
		if (count > 0) {
			pOutput = new OutputScoringCSVFile (count, fieldnumbers, flags);
			FreeUIntArray (fieldnumbers);
		}
		else {
			pOutput = new Output (flags);
		}

		break;
	case OUTPUTFILE_STAMM:
		c = createChar (parameters);
		if (c) {
			pOutput = new OutputStammFile (c, flags);
			delete c;
		}
		else pOutput = new Output (flags);
		break;
	default:
		return PrepareOutput (type, flags, buflen);
	}

	FinishPrepareOutput (pOutput, buflen);
	delete pOutput;
	return S_OK;
}


STDMETHODIMP CProcessor::GetOutput(LONG offset, LONG maxlen, BSTR* buffer)
{
	char *buf = 0;
	*sLastError = 0;

	if (pOutputBuffer) {
		unsigned int buflen = (unsigned int) maxlen;
		unsigned int returned_buflen;
		buf = new char[maxlen + 1];
		returned_buflen = pOutputBuffer->GetBuffer ((unsigned int) offset, buf, buflen);
		buf[returned_buflen] = 0;
	}
	else {
		buf = 0;
	}

	if (buf) 
	{
		*buffer = createBSTR(buf);
		delete buf;
	}
	else *buffer = createBSTR("");
	return S_OK;
}

STDMETHODIMP CProcessor::get_ImportSeparator(BSTR* pVal)
{
	*pVal = createBSTR (LineSepImport);
	return S_OK;
}

STDMETHODIMP CProcessor::put_ImportSeparator(BSTR newVal)
{
	char *c = createChar (newVal);

	strncpy (LineSepImport, c, MAX_LINESEP);
	LineSepImport[MAX_LINESEP-1] = 0;
	LineSepImportLen = (unsigned int) strlen (LineSepImport);
	delete c;
	return S_OK;
}

STDMETHODIMP CProcessor::get_ExportSeparator(BSTR* pVal)
{
	*pVal = createBSTR (LineSepExport);
	return S_OK;
}

STDMETHODIMP CProcessor::put_ExportSeparator(BSTR newVal)
{
	char *c = createChar (newVal);

	strncpy (LineSepExport, c, MAX_LINESEP);
	LineSepExport[MAX_LINESEP-1] = 0;
	LineSepExportLen = (unsigned int) strlen (LineSepExport);
	delete c;

	return S_OK;
}

STDMETHODIMP CProcessor::GetBufferLineCount(LONG* linecount)
{
	*sLastError = 0;
	if (pOutputBuffer) {
		*linecount = (LONG) pOutputBuffer->GetLineCount ();
	}
	else {
		*linecount = 0;
	}

	return S_OK;
}


STDMETHODIMP CProcessor::GetBufferLen(LONG* BufLen)
{
	*sLastError = 0;
	if (pOutputBuffer) {
		*BufLen = (LONG) pOutputBuffer->GetCharCount ();
	}
	else {
		*BufLen = 0;
	}

	return S_OK;
}

STDMETHODIMP CProcessor::GetDefaultFilename(BSTR* filename)
{
	if (pOutputBuffer) {
		*filename = createBSTR (pOutputBuffer->GetDefaultOutputFilename());
	}
	else {
		*filename = createBSTR("");
	}
	return S_OK;
}

STDMETHODIMP CProcessor::GetOutputLines(LONG startline, LONG linecount, BSTR * linebuf)
{
	return S_OK;
}

STDMETHODIMP CProcessor::get_FixedModel(LONG* pVal)
{
	*pVal = FixedModelYear;

	return S_OK;
}

STDMETHODIMP CProcessor::put_FixedModel(LONG newVal)
{
	FixedModelYear = newVal;

	return S_OK;
}

STDMETHODIMP CProcessor::get_InputFileName(BSTR* pVal)
{
	// TODO: Add your implementation code here

	return S_OK;
}

STDMETHODIMP CProcessor::put_InputFileName(BSTR newVal)
{
	// TODO: Add your implementation code here

	return S_OK;
}

STDMETHODIMP CProcessor::get_OutputFileName(BSTR* pVal)
{
	// TODO: Add your implementation code here

	return S_OK;
}

STDMETHODIMP CProcessor::put_OutputFileName(BSTR newVal)
{
	// TODO: Add your implementation code here

	return S_OK;
}

#define EXTEND_FILTER_SIZE 2

unsigned int CProcessor::GetFreeFilterIndex (void)
{
	LKF_FILTER **ppOld;
	unsigned int i;
	for (i = 1; i < nFilterCount; i++) {
		if (!ppFilter[i]) return i;
	}

	ppOld = ppFilter;

	ppFilter = new  LKF_FILTER * [nFilterCount + EXTEND_FILTER_SIZE];
	
	if (ppOld) {
		memcpy (ppFilter, ppOld, sizeof(LKF_FILTER *) * nFilterCount);
		delete ppOld;
	}

	for (i = 0; i < EXTEND_FILTER_SIZE; i++) ppFilter[nFilterCount+i] = 0;
	if (!nFilterCount) {
		nFilterCount = EXTEND_FILTER_SIZE;
		return 1;
	}
	else {
		nFilterCount += EXTEND_FILTER_SIZE;
		return nFilterCount - EXTEND_FILTER_SIZE;
	}
}

STDMETHODIMP CProcessor::CreateFilter(BSTR FilterText, LONG* Filter)
{
	LKF_FILTER *pFilter;
	char *f = createChar (FilterText);
	const char *endfilter = (const char *) f;
	*sLastError = 0;
	pFilter = lkf_filter_create (&endfilter);

	if (pFilter) {
		if (!*endfilter) {
			*Filter = this->GetFreeFilterIndex ();
			ppFilter[*Filter] = pFilter;
		}
		else {
			strcpy (sLastError, "Ungültiger Filter-Ausdruck!");
			lkf_filter_drop (pFilter);
			*Filter = 0;
		}
	}
	else *Filter = 0;
	return S_OK;
}

STDMETHODIMP CProcessor::DropFilter(LONG Filter, LONG* RetVal)
{
	LKF_FILTER **ppDeleteFilter = ppFilter + Filter;
	
	if (*ppFilter) {
		lkf_filter_drop (*ppDeleteFilter);
		*ppDeleteFilter = 0;
	}
	
	*RetVal = 0;
	return S_OK;
}

STDMETHODIMP CProcessor::ApplyFilter(LONG Filter, LONG Flags, LONG* Count)
{ 
	// flags = 1: set, flags = 2: delete, flags = 4: negate criteria

	LKF_FILTER *pFilter;
	if (Filter) pFilter = ppFilter[Filter];
	else pFilter = 0;

	*Count = lkf_context_filter (ctx, pFilter, Flags);
	return S_OK;
}

STDMETHODIMP CProcessor::GetFilterText(LONG Filter, BSTR* FilterText)
{
	char sFilterBuf[512];
	char *sFilterText;

	if (Filter == 0) sFilterText = "";
	else if (((unsigned long)Filter) >= nFilterCount) sFilterText = "";
	else if (ppFilter[Filter])
	{
		unsigned int len = lkf_filter_gettext (ppFilter[Filter], sFilterBuf, 512);
		
		if (len < 512) sFilterText = sFilterBuf;
		else sFilterText = "...";
	}
	else sFilterText = "-";
	*FilterText = createBSTR (sFilterText);
	return S_OK;
}

STDMETHODIMP CProcessor::GetMarkCount(LONG* MarkCount)
{
	unsigned int i, nAufenthaltCount;
	unsigned int nMarkCount = 0;
	LKF_AUFENTHALT *pAufenthalt;

	nAufenthaltCount = lkf_get_aufenthalt_anz (ctx);

	for (i = 0; i < nAufenthaltCount; i++) 
	{
		pAufenthalt = lkf_get_aufenthalt (ctx, i);
		if (lkf_auf_is_marked (pAufenthalt)) nMarkCount++;
	}

	*MarkCount = nMarkCount;
	
	return S_OK;
}

STDMETHODIMP CProcessor::GetAufenthaltCount(LONG* AufenthaltCount)
{
	*AufenthaltCount = lkf_get_aufenthalt_anz (ctx);
	return S_OK;
}

STDMETHODIMP CProcessor::MarkAufenthalte(VARIANT Ids, LONG Flags, LONG* Count)
{
	unsigned int i, count;
	unsigned int *aufenthalt_ids;
	unsigned int id_count;
	LKF_AUFENTHALT *pAufenthalt;
	int mark;

	count = 0;

	mark = (Flags & 1) ? 1 : 0;

	id_count = CreateUIntArray (Ids, aufenthalt_ids);

	for (i = 0; i < id_count; i++) {
		pAufenthalt = lkf_get_aufenthalt (ctx, aufenthalt_ids[i]);
		if (pAufenthalt) {
			count++;
			lkf_auf_mark (pAufenthalt, mark);
		}
	}

	FreeUIntArray (aufenthalt_ids);
	*Count = count;

	return S_OK;
}

STDMETHODIMP CProcessor::DoIntScoring(LONG flags, VARIANT Settings, LONG* Result)
{
	if (!stammdaten_ok)
	{
		strcpy (sLastError, "Die Stammdaten sind nicht erfolgreich initialisiert worden");
		if (Result) *Result = (LONG) 2;
	}
	else 
	{
		lkf_int_scoring (ctx);
		if (Result) *Result = 0;
	}
	return S_OK;
}

STDMETHODIMP CProcessor::BatchExecute(BSTR commands, LONG* returncode)
{
	return S_OK;
}

STDMETHODIMP CProcessor::CheckInput(LONG abrechnungsjahr, LONG modus, ULONG* returncode)
{
	unsigned int retcode;
	char ErrorBuffer[1024];
	unsigned long ret;
	*sLastError = 0;
	if (!modelljahr_gesetzt) {
		m_LastUsedModelYear = FixedModelYear != 0 ? FixedModelYear : abrechnungsjahr;
		retcode = lkf_set_modelljahr (ctx, m_LastUsedModelYear, 0, ErrorBuffer);
		modelljahr_gesetzt = 1;
		if (retcode) 
		{
			strcpy (sLastError, ErrorBuffer);
			if (returncode) *returncode = (LONG) retcode;
		}
		stammdaten_ok = 1;
	}
	else retcode = 0;

	if (abrechnungsjahr || modus) lkf_set_contextparameters (ctx, abrechnungsjahr, 1, 1, 'J', modus);

	ret = lkf_check (ctx, modus);
	if (ret) sprintf (sLastError, "Fehler %d beim Aufruf von lkf_check", ret);	
	if (returncode) *returncode = (LONG) ret;

	return S_OK;
}

STDMETHODIMP CProcessor::SetErrorFormat(LONG Facility, VARIANT ErrorFields, LONG* ReturnCode)
{
	unsigned int *fields; 
	unsigned int fieldcount;

	fields = 0;
	fieldcount = CreateUIntArray (ErrorFields, fields);

	if (fields && fieldcount) {
		::lkf_setErrorFormat ((LKF_CONTEXT *) ctx, (unsigned int) Facility, fieldcount, fields);
		if (ReturnCode) *ReturnCode = 0;
		FreeUIntArray (fields);
	}
	else if (ReturnCode) *ReturnCode = 1;

	return S_OK;
}

STDMETHODIMP CProcessor::SetErrorFilter(LONG ErrorFilter, LONG* ErrorCount)
{
	unsigned int errorcount = ::lkf_setErrorFilter ((LKF_CONTEXT *) ctx, ErrorFilter);
	if (ErrorCount) *ErrorCount = (LONG ) errorcount;
	return S_OK;
}

STDMETHODIMP CProcessor::SetCompatibilityMode(LONG Compatibility, LONG* ReturnCode)
{
	::lkf_set_compatibilitymode ((LKF_CONTEXT *) ctx, (unsigned int) Compatibility);
	if (ReturnCode) *ReturnCode = 0;
	return S_OK;
}

STDMETHODIMP CProcessor::SetIntAbtData(BSTR ABTFC, LONG Betten, LONG* Returncode)
{
	char *sAbtFC = createChar (ABTFC);
	int retcode;
	
	*sLastError = 0;

	retcode = ::lkf_setIntAbtData ((LKF_CONTEXT *) ctx, sAbtFC, (unsigned int) Betten);
	if (Returncode) *Returncode = retcode;
	if (retcode > 0) sprintf (sLastError, "Fehler %d beim Setzen der Intensiv-Abteilungsdaten", retcode); 
	delete sAbtFC;
	return S_OK;
}

STDMETHODIMP CProcessor::GetLastError(BSTR* Error)
{
	if (Error) *Error = createBSTR (sLastError);
	return S_OK;
}

STDMETHODIMP CProcessor::DoScoring(LONG Flags, LONG* Result)
{
	*sLastError = 0;
	if (!stammdaten_ok) 
	{
		strcpy (sLastError, "Fehler beim Scoring: Stammdaten nicht initialisiert.");
	}
	else 
	{
		int ret = lkf_context_scoring (ctx, 0);
		if (ret < 0)
		{
			strncpy (sLastError, lkf_get_context_error (ctx), 511);
			sLastError[511] = 0;
		}
		if (Result) *Result = ret;
	}
	return S_OK;

}

STDMETHODIMP CProcessor::SetFlags(LONG Flags)
{
	::lkf_set_contextflags (ctx, (int) Flags);
	return S_OK;
}

STDMETHODIMP CProcessor::SetContextParameters(LONG Abrechnungsjahr, LONG PeriodVal, LONG PeriodNr, LONG PeriodType, LONG Flags)
{
	::lkf_set_contextparameters (ctx, (int) Abrechnungsjahr, (int) PeriodVal, (int) PeriodNr, (char) PeriodType, (int) Flags);
	return S_OK;
}

STDMETHODIMP CProcessor::SetAbrechnungsjahr(LONG Abrechnungsjahr)
{
	::lkf_set_abrechnungsjahr (ctx, (int) Abrechnungsjahr);
	return S_OK;
}

STDMETHODIMP CProcessor::SetModelljahr(LONG Modelljahr, LONG* Result)
{
	int ret;
	char sError[1024];
	*sLastError = 0;

	if (Modelljahr) 
	{
		m_LastUsedModelYear = Modelljahr;
		ret = ::lkf_set_modelljahr (ctx, (unsigned int) Modelljahr, "", sError);
	}
	else 
	{
		m_LastUsedModelYear = FixedModelYear;
		ret = ::lkf_set_modelljahr (ctx, (unsigned int) FixedModelYear, "", sError);
	}
	modelljahr_gesetzt = 1;

	if (ret) strcpy (sLastError, sError);
	else stammdaten_ok = 1;

	if (Result) *Result = ret;
	return S_OK;
}

STDMETHODIMP CProcessor::SetIntContextParameters(BSTR VonDatum, BSTR BisDatum, LONG Flags, LONG MindestStd, LONG* Result)
{
	char *sVonDatum, *sBisDatum;
	int retcode;
	sVonDatum = createChar (VonDatum);
	sBisDatum = createChar (BisDatum);

	retcode = ::lkf_int_setintcontextparameters (ctx, sVonDatum, sBisDatum, (unsigned int) Flags, (unsigned int) MindestStd);

	if (Result) *Result = retcode;
	delete sVonDatum;
	delete sBisDatum;
	return S_OK;
}

STDMETHODIMP CProcessor::DoStat(LONG Flags, LONG* Result)
{
	int retcode = lkf_stat (ctx);
	if (Result) *Result = retcode;
	return S_OK;
}



STDMETHODIMP CProcessor::SendBuffer(VARIANT Buffer, LONG* ReturnCode)
{

	if (Buffer.vt & VT_BSTR)
	{
		if (Buffer.vt & VT_BYREF)
		{
			return SetData (*Buffer.pbstrVal, ReturnCode);
		}
		else
		{
			return SetData (Buffer.bstrVal, ReturnCode);
		}
	}
	else
	{
		if (ReturnCode) *ReturnCode = -4;
		sprintf (sLastError, "Ungültiger Übergabetyp %d", Buffer.vt);
		return S_OK;
	}
}

STDMETHODIMP CProcessor::TraceSetAufenthalt(BSTR AufNr)
{
	char *sVonDatum = createChar (AufNr);
	lkf_trace_setAufenthalt (ctx, sVonDatum);
	delete sVonDatum;
	return S_OK;
}

STDMETHODIMP CProcessor::TraceSetMode(LONG Facility, LONG Level)
{
	lkf_trace_setLevel (ctx, Facility, Level);
	return S_OK;
}

STDMETHODIMP CProcessor::TraceGetAufenthalt(BSTR* AufNr)
{
	const char *sAufenthalt = lkf_trace_getAufenthalt (ctx);

	if (AufNr)
	{
		if (sAufenthalt)
			*AufNr = createBSTR (sAufenthalt);
		else
			*AufNr = createBSTR ("");
	}

	return S_OK;
}

STDMETHODIMP CProcessor::TraceGetMode(LONG Facility, LONG* Level)
{
	if (Level)
	{
		*Level = lkf_trace_getLevel (ctx, Facility);
	}

	return S_OK;
}
