//
// 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.
//
// 
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;

namespace Managed
{
	public class Native 
	{
		[StructLayout(LayoutKind.Sequential)]
		public struct TestStruct
		{
			public byte a;
			public short b;
			public int c;
			public byte d;
			public short e;
			public int f;
		}
		[StructLayout(LayoutKind.Sequential)]
		public struct Complex
		{
			public Complex(float re, float im)
			{
				this.re = re;
				this.im = im;
			}
			public float Real
			{
				get
				{
					return re;
				}
				set
				{
					re = value;
				}
			}
			public float Imaginary
			{
				get
				{
					return im;
				}
				set
				{
					im = value;
				}
			}
			float re;
			float im;
		}
		[StructLayout(LayoutKind.Sequential)]
		public struct StructStringRef
		{
			public StructStringRef(string a, string b)
			{
				this.a = a;
				this.b = b;
			}
			[MarshalAs(UnmanagedType.LPWStr)]
			public string a;
			[MarshalAs(UnmanagedType.LPStr)]
			public string b;
		}
		[DllImport("unmanaged.dll")]
		public static extern int AddInteger(int a, int b);

		[DllImport("unmanaged.dll")]
		public static extern int StringLength(string str);

//		[DllImport("unmanaged.dll")]
//		public static extern int UnicodeStringLength(
//			[MarshalAs(UnmanagedType.LPWStr)] string str);
		[DllImport("unmanaged.dll", CharSet=CharSet.Unicode)]
		public static extern int UnicodeStringLength(string str);

		[DllImport("unmanaged.dll")]
		public static extern byte ByteFunc(byte a);
		[DllImport("unmanaged.dll")]
		public static extern short ShortFunc(short a);
		[DllImport("unmanaged.dll")]
		public static extern ushort WordFunc(short a);
		[DllImport("unmanaged.dll")]
		public static extern uint UintFunc(uint a);
		[DllImport("unmanaged.dll")]
		public static extern int LongFunc(int a);
		[DllImport("unmanaged.dll")]
		public static extern uint UnsignedLongFunc(uint a);
		[DllImport("unmanaged.dll")]
		public static extern char CharFunc(char a);
		[DllImport("unmanaged.dll")]
		public static extern float FloatFunc(float a);
		[DllImport("unmanaged.dll")]
		public static extern double DoubleFunc(double a);

		[DllImport("unmanaged.dll")]
		public static extern void ByteOutOutFunc(byte a, out byte o);
		[DllImport("unmanaged.dll")]
		public static extern void ShortOutFunc(short a, out short o);
		[DllImport("unmanaged.dll")]
		public static extern void WordOutFunc(ushort a, out ushort o);
		[DllImport("unmanaged.dll")]
		public static extern void IntOutFunc(int a, out int o);
		[DllImport("unmanaged.dll")]
		public static extern void UintOutFunc(uint a, out uint o);
		[DllImport("unmanaged.dll")]
		public static extern void LongOutFunc(int a, out int o);
		[DllImport("unmanaged.dll")]
		public static extern void UnsignedLongOutFunc(uint a, out uint o);
		[DllImport("unmanaged.dll")]
		public static extern void CharOutFunc(char a, out char o);
		[DllImport("unmanaged.dll")]
		public static extern void FloatOutFunc(float a, out float o);
		[DllImport("unmanaged.dll")]
		public static extern void DoubleOutFunc(double a, out double o);

		[DllImport("unmanaged.dll")]
		public static extern string ConcatString(string a, string b);

		[DllImport("unmanaged.dll", CharSet=CharSet.Unicode)]
		public static extern string ConcatUnicodeString(string a, string b);

		[DllImport("unmanaged.dll")]
		public static extern void ConcatOutString(string a, string b, StringBuilder o);

		[DllImport("unmanaged.dll")]
		public static extern void TestStructFunction(ref TestStruct s);

		[DllImport("unmanaged.dll")]
		public static extern Complex ComplexAdd(Complex a, Complex b);

		[DllImport("unmanaged.dll")]
		public static extern void TestStructStringRef(StructStringRef a);

		[DllImport("unmanaged.dll")]
		public static extern int IntArrayFunction(int [] ia, int length);

		[DllImport("unmanaged.dll")]
		public static extern float FloatArrayFunction(float [] fa, int length);

		[DllImport("unmanaged.dll")]
		public static extern int StringArrayFunction(string [] sa, int length);

		[DllImport("unmanaged.dll")]
		public static extern void MatrixMultiplyFunction(int [,] a,
			                                             int [,] b,
			                                             [Out] int [,] c,
			                                             int x, int y, int z);

		[DllImport("unmanaged.dll")]
		public static extern Complex ComplexAverage(Complex [] a, int length);

		[DllImport("unmanaged.dll", CharSet=CharSet.Unicode)]
		public static extern void DateFunction(DateTime date,
			[Out, MarshalAs(UnmanagedType.LPWStr)]
			StringBuilder fmtString,
			int bufferLength);

	}

	/// <summary>
	/// Podsumowanie dla Class1.
	/// </summary>
	class ManagedMain
	{
		static void Main(string[] args)
		{
			int retInt = Native.AddInteger(1, 2);
			Console.WriteLine("Wynik AddInteger: {0}", retInt);

			string str = "To jest test";
			int retLength = Native.StringLength(str);
			Console.WriteLine("Długość ciągu: {0}", retLength);

			retLength = Native.UnicodeStringLength(str);
			Console.WriteLine("Długość ciągu Unicode: {0}", retLength);

			byte byteRet = Native.ByteFunc(10);
			short shortRet = Native.ShortFunc(10);
			ushort ushortRet = Native.WordFunc(10);
			uint uintRet = Native.UintFunc(10);
			int longRet = Native.LongFunc(10);
			uint ulongRet = Native.UnsignedLongFunc(10);
			char charRet = Native.CharFunc((char)10);
			float floatRet = Native.FloatFunc(10);
			double doubleRet = Native.DoubleFunc(10);

			Native.ByteOutOutFunc(20, out byteRet);
			Native.ShortOutFunc(20, out shortRet);
			Native.WordOutFunc(20, out ushortRet);
			Native.IntOutFunc(20, out longRet);
			Native.UintOutFunc(20, out uintRet);
			Native.LongOutFunc(20, out longRet);
			Native.UnsignedLongOutFunc(20, out ulongRet);
			Native.CharOutFunc((char)20, out charRet);
			Native.FloatOutFunc(20, out floatRet);
			Native.DoubleOutFunc(20, out doubleRet);

			string a = "To jest ";
			string b = "test";
			string result = Native.ConcatString(a, b);
			Console.WriteLine("Wynik połączenia ciągów: {0}", result);

			result = Native.ConcatUnicodeString(a, b);
			Console.WriteLine("Wynik połączenia ciągów Unicode: {0}", result);

			StringBuilder sbr = new StringBuilder(128);
			Native.ConcatOutString(a, b, sbr);
			Console.WriteLine("Po usunięciu ciągu: {0}", sbr);

			int[] ia = {1, 2, 3, 4};
			Console.WriteLine("Tablica liczb całkowitych: {0}", ia.Length);
			retInt = Native.IntArrayFunction(ia, ia.Length);
			Console.WriteLine("Największa liczba całkowita: {0}", retInt);

			Native.TestStruct s = new Native.TestStruct();
			s.a = 0x11;
			s.b = 0x22;
			s.c = 0x33;
			s.d = 0x44;
			s.e = 0x55;
			s.f = 0x66;
			Native.TestStructFunction(ref s);

			Native.Complex ac = new Native.Complex(1.0F, 2.0F);
			Native.Complex bc = new Native.Complex(3.0F, 4.0F);
			Native.Complex cc = Native.ComplexAdd(ac, bc);

			Native.StructStringRef sr = new Native.StructStringRef("Test." , "Jeden, dwa, trzy.");
			Native.TestStructStringRef(sr);

			float[] fa = {1, 2, 3, 4};
			Console.WriteLine("Tablica liczb zmiennoprzecinkowych: {0}", fa.Length);
			float retFloat = Native.FloatArrayFunction(fa, fa.Length);
			Console.WriteLine("Największa liczba zmiennoprzecinkowa: {0}", retFloat);

			string[] sa = new string []{"pierwszy", "drugi", "trzeci", "czwarty", "piąty", "szósty" };
			Console.WriteLine("Tablica ciągów: {0}", sa.Length);
			retInt = Native.StringArrayFunction(sa, sa.Length);
			Console.WriteLine("Najdłuższy ciąg miał długość {0} znaków", retInt);

			int [,] am = new int [2,2] {{1,-2},{3,4}};
			int [,] bm = new int [2,3] {{5,4,-2},{-3,0,1}};
			int [,] cm = new int [2,3];
			Native.MatrixMultiplyFunction(am, bm, cm, 2, 2, 3);
			for(int i = 0; i < cm.GetLength(0); i++)
			{
				for(int j = 0; j < cm.GetLength(1); j++)
				{
					Console.Write("{0} ", cm[i,j]);
				}
				Console.WriteLine();
			}

			Native.Complex [] ca = new Native.Complex [] {new Native.Complex(1,2),
                                                          new Native.Complex(3,4),
                                                          new Native.Complex(5,6),
                                                          new Native.Complex(7,8)};
			Native.Complex cr = Native.ComplexAverage(ca, ca.Length);
			Console.WriteLine("Przeciętna wartość liczb zespolonych: {0} {1}", cr.Real, cr.Imaginary);

			DateTime now = DateTime.Now;
			Console.WriteLine("Data początkowa: {0}", now);
			StringBuilder retTime = new StringBuilder(256);
			Native.DateFunction(now, retTime, retTime.Capacity);
			Console.WriteLine("Data końcowa: {0}", retTime);

//			r = Native.Average(1, 2, 3, 4, 5, 6, 7);
//			Console.WriteLine("Średnia: {0}", r);
//
//			try
//			{
//
//			}
//			catch(Exception e)
//			{
//				Console.WriteLine(e);
//			}
			// IntPtr ump = Native.Add(a, b);
			// string result = Marshal.PtrToStringAuto(ump);
			// Marshal.FreeHGlobal(ump);
		}
	}
}
