//
// Copyright (c) 2002
// Ronald Kevin Burton
//
// Z poniższym kodem nie jest związana żadna gwarancja poprawności działania.
// Program został dołączony do książki ".NET CLR. Księga eksperta" w celu
// ilustracji koncepcji i zasad przedstawionych w tej książce. Program może być 
// używany na własne ryzyko.
//
// Przyznaje się prawo do użycia lub kopiowania tego oprogramowania do dowolnego celu
// bez konieczności ponoszenia żadnych opłat pod warunkiem, że powyższe uwagi zostaną 
// zachowane we wszystkich kopiach. Przyznaje się także prawo do modyfikacji kodu
// i dystrybucji zmodyfikowanego kodu pod warunkiem zachowania powyższych uwag
// oraz dołączenia informacji mówiącej o modyfikacji kodu.
//
// 
// Unmanaged.cpp : Definiuje punkt wejścia dla aplikacji DLL.
//

#include "stdafx.h"
#include "Unmanaged.h"
#include "stdio.h"

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
    return TRUE;
}
UNMANAGED_API void DateFunction(DATE date, wchar_t *retBuffer, int bufferLength)
{
	SYSTEMTIME st;
	VariantTimeToSystemTime(date, &st);
	int retVal = GetDateFormat(LOCALE_USER_DEFAULT,
		                       DATE_LONGDATE,
							   &st,
							   NULL,
							   retBuffer,
							   bufferLength);
	return;
}
UNMANAGED_API int AddInteger(int a, int b)
{
	return a + b;
}
UNMANAGED_API int StringLength(char * str)
{
	return (int)strlen(str);
}
UNMANAGED_API int UnicodeStringLength(wchar_t * str)
{
	return (int)wcslen(str);
}

UNMANAGED_API unsigned char ByteFunc(unsigned char a)
{
	return a;
}
UNMANAGED_API short ShortFunc(short a)
{
	return a;
}
UNMANAGED_API unsigned short WordFunc(unsigned short a)
{
	return a;
}
UNMANAGED_API unsigned int UintFunc(unsigned int a)
{
	return a;
}
UNMANAGED_API long LongFunc(long a)
{
	return a;
}
UNMANAGED_API unsigned long UnsignedLongFunc(unsigned long a)
{
	return a;
}
UNMANAGED_API char CharFunc(char a)
{
	return a;
}
UNMANAGED_API float FloatFunc(float a)
{
	return a;
}
UNMANAGED_API double DoubleFunc(double a)
{
	return a;
}

UNMANAGED_API void ByteOutOutFunc(unsigned char a, unsigned char* o)
{
	*o = a;	
}
UNMANAGED_API void ShortOutFunc(short a, short *o)
{
	*o = a;	
}
UNMANAGED_API void WordOutFunc(unsigned short a, unsigned short *o)
{
	*o = a;	
}
UNMANAGED_API void IntOutFunc(int a, int *o)
{
	*o = a;
}
UNMANAGED_API void UintOutFunc(unsigned int a, unsigned int *o)
{
	*o = a;	
}
UNMANAGED_API void LongOutFunc(long a, long *o)
{
	*o = a;	
}
UNMANAGED_API void UnsignedLongOutFunc(unsigned long a, unsigned long *o)
{
	*o = a;	
}
UNMANAGED_API void CharOutFunc(char a, char *o)
{
	*o = a;	
}
UNMANAGED_API void FloatOutFunc(float a, float *o)
{
	*o = a;	
}
UNMANAGED_API void DoubleOutFunc(double a, double *o)
{
	*o = a;	
}

UNMANAGED_API char* ConcatString(char* a, char* b)
{
	size_t size = strlen(a) + strlen(b) + 1;

    // CoTaskMemAlloc musi być użyty zamiast nowego operatora,
    // ponieważ kod po stronie zarządzanej będzie wywoływał Marshal.FreeCoTaskMem 
    // w celu zwolnienia tej pamięci.
   
    char* buffer = (char*)CoTaskMemAlloc( size * sizeof(char) );

	strcpy(buffer, a);
	strcat(buffer, b);

	return buffer;
}
UNMANAGED_API wchar_t* ConcatUnicodeString(wchar_t* a, wchar_t* b)
{
	size_t size = wcslen(a) + wcslen(b) + 1;

    // CoTaskMemAlloc musi być użyty zamiast nowego operatora,
    // ponieważ kod po stronie zarządzanej będzie wywoływał Marshal.FreeCoTaskMem 
    // w celu zwolnienia tej pamięci.
   
    wchar_t* buffer = (wchar_t*)CoTaskMemAlloc( size * sizeof(wchar_t) );

	wcscpy(buffer, a);
	wcscat(buffer, b);

	return buffer;
}

UNMANAGED_API void ConcatOutString(char* a, char* b, char * o)
{
	size_t size = strlen(a) + strlen(b) + 1;

	strcpy(o, a);
	strcat(o, b);
}

UNMANAGED_API void TestStructFunction(TestStruct *s)
{
	s->a = s->a * 2;
	s->b = s->b * 2;
	s->c = s->c * 2;
	s->d = s->d * 2;
	s->e = s->e * 2;
	s->f = s->f * 2;
}

UNMANAGED_API void TestStructStringRef(StructStringRef a)
{
	wprintf(L"a: %ls", a.a);
	printf("b: %s", a.b);
}

UNMANAGED_API int IntArrayFunction(int *pia, int length)
{
	int max = pia[0];
	for(int i = 0;i < length; i++)
	{
		if(pia[i] > max)
			max = pia[i];
	}
	return max;
}

UNMANAGED_API float FloatArrayFunction(float *pfa, int length)
{
	float max = pfa[0];
	for(int i = 0;i < length; i++)
	{
		if(pfa[i] > max)
			max = pfa[i];
	}
	return max;
}

UNMANAGED_API int StringArrayFunction(char **psa, int length)
{
	size_t max = strlen(psa[0]);
	for(int i = 0;i < length; i++)
	{
		if(strlen(psa[i]) > max)
			max = strlen(psa[i]);
	}
	return (int)max;
}

UNMANAGED_API void MatrixMultiplyFunction(int *a, int *b, int *c, int x, int y, int z)
{
	// A X wierszy x Y kolumn
	// B Y wierszy x Z kolumn
	// C X wierszy x Z kolumn

	// Dla każdego wiersza w A
	for(int i = 0; i < x; i++)
	{
		// Dla każdej kolumny w B (wiersz w B)
		for(int j = 0; j < z; j++)
		{
			// c[i,j] = 0;
			*(c + i*z + j) = 0;
			for(int k = 0; k < y; k++)
			{
				// c[i,j] += a[i,k] * b[k,j]
				*(c + i*z + j) += *(a + i*y + k) * *(b + k*z + j);
			}
		}
	}
}

UNMANAGED_API complex ComplexAdd(complex a, complex b)
{
	complex c;
	c.re = a.re + b.re;
	c.im = a.im + b.im;
	return c;
}

UNMANAGED_API complex ComplexAverage(complex* a, int length)
{
	complex c;
	c.re = 0;
	c.im = 0;
	for(int i = 0; i < length; i++)
	{
		c.re += a[i].re;
		c.im += a[i].im;
	}
	c.re /= (float)length;
	c.im /= (float)length;
	return c;
}
