#include "Fenster.h"
#include "Punkt.h"
#include "Text.h"
#include "MausEreignis.h"
#include "TastaturEreignis.h"
#include "Bildschirm.h"
#include "Bild.h"
#include "Farbe.h"
#include "Rahmen.h"
#include "TextFeld.h"
#include "Maus.h"
#include "Globals.h"

using namespace Framework;

// Fensterklasse erzeugen
WNDCLASS Framework::F_Normal( HINSTANCE hInst )// Erzeugen einer normalen Fensterklasse
{
	WNDCLASS ret;
	ret.cbClsExtra = 0;
	ret.cbWndExtra = 0;
	ret.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	ret.hCursor = LoadCursor(NULL,IDC_ARROW);
	ret.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	ret.hInstance = hInst;
	ret.lpszMenuName = "";
	ret.lpfnWndProc = WindowProc;
	ret.style = CS_HREDRAW | CS_VREDRAW;
	return ret;
}

WNDCLASSEX Framework::F_NormalEx( HINSTANCE hInst )
{
	WNDCLASSEX ret;
	ret.cbSize = sizeof( WNDCLASSEX );
	ret.cbClsExtra = 0;
	ret.cbWndExtra = 0;
	ret.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	ret.hCursor = LoadCursor(NULL,IDC_ARROW);
	ret.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	ret.hInstance = hInst;
	ret.lpszMenuName = "";
	ret.lpfnWndProc = WindowProc;
	ret.style = CS_HREDRAW | CS_VREDRAW;
	ret.hIconSm = 0;
	return ret;
}

// WinAPI
LRESULT CALLBACK Framework::WindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
	switch( message )
	{
	// Device 
	case WM_SETCURSOR:
		return 0;
	// Fenster 
	case WM_SIZE:
		if( wparam == SIZE_RESTORED )
			WFensterA.sendRestoreMessage( hwnd );
		break;
	// Schließen 
	case WM_CLOSE:
		if( WFensterA.sendVSchließMessage( hwnd ) )
			return 0;
		else
			break;
	case WM_DESTROY:
		if( WFensterA.sendNSchließMessage( hwnd ) )
			return 0;
		else
			break;
	// Maus 
	case WM_LBUTTONDOWN: // Linksklick
		{
			MausStand[ M_Links ] = 1;
			MausEreignis me;
			me.id = ME_PLinks;
			me.mx = (int)(short)LOWORD( lparam );
			me.my = (int)(short)HIWORD( lparam );
			me.verarbeitet = 0;
			WFensterA.sendMausMessage( hwnd, &me );
			break;
		}
	case WM_RBUTTONDOWN: // Rechtsklick
		{
			MausStand[ M_Rechts ] = 1;
			MausEreignis me;
			me.id = ME_PRechts;
			me.mx = (int)(short)LOWORD( lparam );
			me.my = (int)(short)HIWORD( lparam );
			me.verarbeitet = 0;
			WFensterA.sendMausMessage( hwnd, &me );
			break;
		}
	case WM_MBUTTONDOWN: // Mittelklick
		{
			MausStand[ M_Mitte ] = 1;
			MausEreignis me;
			me.id = ME_PMitte;
			me.mx = (int)(short)LOWORD( lparam );
			me.my = (int)(short)HIWORD( lparam );
			me.verarbeitet = 0;
			WFensterA.sendMausMessage( hwnd, &me );
			break;
		}
	case WM_LBUTTONUP: // Linksrelease
		{
			MausStand[ M_Links ] = 0;
			MausEreignis me;
			me.id = ME_RLinks;
			me.mx = (int)(short)LOWORD( lparam );
			me.my = (int)(short)HIWORD( lparam );
			me.verarbeitet = 0;
			WFensterA.sendMausMessage( hwnd, &me );
			break;
		}
	case WM_RBUTTONUP: // Rechtsrelease
		{
			MausStand[ M_Rechts ] = 0;
			MausEreignis me;
			me.id = ME_RRechts;
			me.mx = (int)(short)LOWORD( lparam );
			me.my = (int)(short)HIWORD( lparam );
			me.verarbeitet = 0;
			WFensterA.sendMausMessage( hwnd, &me );
			break;
		}
	case WM_MBUTTONUP: // Mittelrelease
		{
			MausStand[ M_Mitte ] = 0;
			MausEreignis me;
			me.id = ME_RMitte;
			me.mx = (int)(short)LOWORD( lparam );
			me.my = (int)(short)HIWORD( lparam );
			me.verarbeitet = 0;
			WFensterA.sendMausMessage( hwnd, &me );
			break;
		}
	case WM_LBUTTONDBLCLK: // Linksdoppelklick
		{
			MausEreignis me;
			me.id = ME_DKLinks;
			me.mx = (int)(short)LOWORD( lparam );
			me.my = (int)(short)HIWORD( lparam );
			me.verarbeitet = 0;
			WFensterA.sendMausMessage( hwnd, &me );
			break;
		}
	case WM_RBUTTONDBLCLK: // Rechtsdoppelklick
		{
			MausEreignis me;
			me.id = ME_DKRechts;
			me.mx = (int)(short)LOWORD( lparam );
			me.my = (int)(short)HIWORD( lparam );
			me.verarbeitet = 0;
			WFensterA.sendMausMessage( hwnd, &me );
			break;
		}
	case WM_MBUTTONDBLCLK: // Mitteldoppelklick
		{
			MausEreignis me;
			me.id = ME_DKMitte;
			me.mx = (int)(short)LOWORD( lparam );
			me.my = (int)(short)HIWORD( lparam );
			me.verarbeitet = 0;
			WFensterA.sendMausMessage( hwnd, &me );
			break;
		}
	case WM_MOUSEHOVER: // Maus betritt Fenster
		{
			MausTrack = 1;
			MausEreignis me;
			me.id = ME_Betritt;
			me.mx = (int)(short)LOWORD( lparam );
			me.my = (int)(short)HIWORD( lparam );
			me.verarbeitet = 0;
			WFensterA.sendMausMessage( hwnd, &me );
			break;
		}
	case WM_MOUSELEAVE: // Maus verlässt Fenster
		{
			MausTrack = 1;
			MausEreignis me;
			me.id = ME_Verlässt;
			me.mx = (int)(short)LOWORD( lparam );
			me.my = (int)(short)HIWORD( lparam );
			me.verarbeitet = 0;
			WFensterA.sendMausMessage( hwnd, &me );
			break;
		}
	case WM_MOUSEMOVE: // Maus wird bewegt
		{
			if( MausTrack )
			{
				TRACKMOUSEEVENT lptme;
				lptme.cbSize = sizeof(TRACKMOUSEEVENT);
				lptme.dwFlags = TME_HOVER | TME_LEAVE;
				lptme.dwHoverTime = 0;
				lptme.hwndTrack = hwnd;
				TrackMouseEvent( &lptme );
				MausTrack = 0;
			}
			MausEreignis me;
			me.id = ME_Bewegung;
			me.mx = (int)(short)LOWORD( lparam );
			me.my = (int)(short)HIWORD( lparam );
			me.verarbeitet = 0;
			WFensterA.sendMausMessage( hwnd, &me );
			break;
		}
	case WM_MOUSEWHEEL: // Maus scroll
		{
			MausEreignis me;
			if( (int)(short)HIWORD( wparam ) < 0 )
				me.id = ME_DScroll;
			else
				me.id = ME_UScroll;
			RECT r;
			GetWindowRect( hwnd, &r );
			me.mx = (int)(short)LOWORD( lparam ) - r.left;
			me.my = (int)(short)HIWORD( lparam ) - r.top;
			me.verarbeitet = 0;
			WFensterA.sendMausMessage( hwnd, &me );
			break;
		}
	// Tastatur 
	case WM_KEYDOWN:
		{
			TastaturEreignis te;
			te.id = TE_Press;
			te.taste = VirtualZuChar( (int)wparam );
			te.verarbeitet = 0;
			TastenStand[ te.taste ] = 1;
			WFensterA.sendTastaturMessage( hwnd, &te );
			break;
		} // Taste wird gedrückt
	case WM_KEYUP:
		{
			TastaturEreignis te;
			te.id = TE_Release;
			te.taste = VirtualZuChar( (int)wparam );
			TastenStand[ te.taste ] = 0;
			te.verarbeitet = 0;
			WFensterA.sendTastaturMessage( hwnd, &te );
			break;
		} // Taste wird losgelassen
	}
	return (DefWindowProc(hwnd, message, wparam, lparam));
}

void Framework::StartNachrichtenSchleife()
{
	MSG msg;
	while( GetMessage( &msg, NULL, 0, 0 ) > 0 && !msgExit )
	{
		if( !msgExit )
		{
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}
	}
	msgExit = 0;
}

void Framework::StopNachrichtenSchleife( HWND hwnd )
{
	msgExit = 1;
	PostMessage( hwnd, WM_MOUSELEAVE, 0, 0 );
}

unsigned char Framework::VirtualZuChar( int Virtual )
{
	UINT vk = MapVirtualKey( Virtual, 2 );
	if( !vk )
	{
		switch( Virtual )
		{
		case VK_CAPITAL:
			return T_Caps_Lock;
		case VK_SHIFT:
			return T_Shift;
		case VK_CONTROL:
			return T_Strg;
		case VK_F1:
			return T_F1;
		case VK_F2:
			return T_F2;
		case VK_F3:
			return T_F3;
		case VK_F4:
			return T_F4;
		case VK_F5:
			return T_F5;
		case VK_F6:
			return T_F6;
		case VK_F7:
			return T_F7;
		case VK_F8:
			return T_F8;
		case VK_F9:
			return T_F9;
		case VK_F10:
			return T_F10;
		case VK_F11:
			return T_F11;
		case VK_F12:
			return T_F12;
		case VK_PAUSE:
			return T_Pause;
		case VK_SNAPSHOT:
			return T_Druck;
		case VK_INSERT:
			return T_Einfg;
		case VK_DELETE:
			return T_Entf;
		case VK_LEFT:
			return T_Links;
		case VK_UP:
			return T_Oben;
		case VK_RIGHT:
			return T_Rechts;
		case VK_DOWN:
			return T_Unten;
		case VK_MENU:
			return T_Alt_Gr;
		case VK_NUMLOCK:
			return T_Num;
		case VK_HOME:
			return T_Pos1;
		case VK_PRIOR:
			return T_BildO;
		case VK_NEXT:
			return T_BildU;
		case VK_END:
			return T_Ende;
		}
	}
	char ret = (char)(short)LOWORD( vk );
	short SHIFT = GetKeyState( VK_SHIFT );
	short CAPSLOCK = GetKeyState( VK_CAPITAL );
	short ALTGR = TastenStand[ T_Alt_Gr ];
	if( ALTGR )
	{
		switch( ret )
		{
		case 'q':
			return '@';
		case 'Q':
			return '@';
		case '<':
			return '|';
		case '>':
			return '|';
		case '7':
			return '{';
		case '/':
			return '{';
		case '8':
			return '[';
		case '(':
			return '[';
		case '9':
			return ']';
		case ')':
			return ']';
		case '0':
			return '}';
		case '=':
			return '}';
		case 'ß':
			return '\\';
		case '?':
			return '\\';
		case '+':
			return '~';
		case '*':
			return '~';
		case 'e':
			return '€';
		case 'E':
			return '€';
		case 'm':
			return 'µ';
		case 'M':
			return 'µ';
		case '2':
			return '²';
		case '"':
			return '²';
		case '3':
			return '³';
		case '§':
			return '³';
		}
	}
	SHIFT = HIWORD( SHIFT );
	CAPSLOCK = LOWORD( CAPSLOCK );
	bool up = 0;
	if( SHIFT && !CAPSLOCK )
		up = 1;
	if( CAPSLOCK && !SHIFT )
		up = 1;
	ret = KleinOrGroß( ret, up );
	return ret;
}

// Inhalt der WFenster Klasse aus Fenster.h
// Konstruktor 
WFenster::WFenster()
{
	hWnd = 0;
	WFensterA.addFenster( this );
	MausAktion = 0;
	VSchließAktion = 0;
	NSchließAktion = 0;
	TastaturAktion = 0;
	screen = 0;
	ref = 1;
	mx = -1, my = -1;
	verschiebbar = 0;
	rahmen = 0;
	bitmap = 0;
	hdc = 0;
}

WFenster::WFenster( HWND hwnd )
{
	hWnd = hwnd;
	WFensterA.addFenster( this );
	MausAktion = 0;
	VSchließAktion = 0;
	NSchließAktion = 0;
	TastaturAktion = 0;
	screen = 0;
	ref = 1;
}

// Destruktor 
WFenster::~WFenster()
{
	if( WFensterA.removeFenster( this ) )
	{
		WFensterA.del();
	}
	if( hWnd )
		DestroyWindow( hWnd );
	if( screen )
		screen->release();
}

// nicht constant 
void WFenster::erstellen( int style, WNDCLASS wc ) // Erstellt ein Fenster in Windows
{
	if( !GetClassInfo( wc.hInstance, wc.lpszClassName, &wc ) )
	{
		if( !RegisterClass( &wc ) ) // Register Fensterklasse
		{
			MessageBox( hWnd, "Fehler beim Registrieren der Fensterklasse!", "Error", MB_ICONERROR ); // Fehlermeldung bei Fehler
			return;
		}
	}
	
	hWnd = CreateWindow( wc.lpszClassName, wc.lpszClassName, style, 0, 0, 0, 0, 0, 0, wc.hInstance, 0 ); // Fenster Erstellen
	
	if( hWnd == 0 )
	{
		MessageBox( hWnd, "Fehler beim erstellen des Fensters!", "Error", MB_ICONERROR ); // Fehlermeldung bei Fehler
		return;
	}
	this->style = style;
}

void WFenster::erstellenEx( int exStyle, int style, WNDCLASSEX wc ) // Das Fenster Erstellen
{
	if( !GetClassInfoEx( wc.hInstance, wc.lpszClassName, &wc ) )
	{
		if( !RegisterClassEx( &wc ) ) // Register Fensterklasse
		{
			MessageBox( hWnd, "Fehler beim Registrieren der Fensterklasse!", "Error", MB_ICONERROR ); // Fehlermeldung bei Fehler
			return;
		}
	}
	
	hWnd = CreateWindowEx( exStyle, wc.lpszClassName, wc.lpszClassName, style, 0, 0, 0, 0, 0, 0, wc.hInstance, 0 ); // Fenster Erstellen
	
	if( hWnd == 0 )
	{
		MessageBox( hWnd, "Fehler beim erstellen des Fensters!", "Error", MB_ICONERROR ); // Fehlermeldung bei Fehler
		return;
	}
	this->style = style;
}

void WFenster::setAnzeigeModus( int mod )// Fenster Anzeigen
{
	if( rahmen )
	{
		if( mod == 2 )
			ShowWindow( rahmen, 0 );
		else
			ShowWindow( rahmen, mod );
	}
	ShowWindow( hWnd, mod );
}

void WFenster::setPosition( Punkt *p )// Fenster Position
{
	RECT r;
	GetWindowRect( hWnd, &r ); // Vorherige Position herausfinden
	RECT res;
	res.left = p->getX(), res.top = p->getY(), res.right = r.right - r.left, res.bottom = r.bottom - r.top;
	AdjustWindowRect( &res, style, 0 );
	SetWindowPos( hWnd, 0, res.left, res.top, res.right, res.bottom, 0 ); // Position ändern
	p->release();
}

void WFenster::setPosition( int x, int y )
{
	RECT r;
	GetWindowRect( hWnd, &r ); // Vorherige Position herausfinden
	RECT res;
	res.left = x, res.top = y, res.right = r.right - r.left, res.bottom = r.bottom - r.top;
	AdjustWindowRect( &res, style, 0 );
	SetWindowPos( hWnd, 0, res.left, res.top, res.right, res.bottom, 0 ); // Position ändern
}

void WFenster::setGröße( Punkt *g )// Fenster Größe
{
	RECT r;
	GetWindowRect( hWnd, &r ); // vorherige Größe herausfinden
	RECT res;
	res.left = r.left, res.top = r.top, res.right = g->getX(), res.bottom = g->getY();
	AdjustWindowRect( &res, style, 0 );
	SetWindowPos( hWnd, 0, res.left, res.top, res.right, res.bottom, 0 ); // Größe ändern
	g->release();
}

void WFenster::setGröße( int breite, int höhe )
{
	RECT r;
	GetWindowRect( hWnd, &r ); // vorherige Größe herausfinden
	RECT res;
	res.left = r.left, res.top = r.top, res.right = breite, res.bottom = höhe;
	AdjustWindowRect( &res, style, 0 );
	SetWindowPos( hWnd, 0, res.left, res.top, res.right - res.left, res.bottom - res.top, 0 ); // Größe ändern
}

void WFenster::setBounds( Punkt *p, Punkt *g ) // setzt größe und Position
{
	SetWindowPos( hWnd, 0, p->getX(), p->getY(), g->getX(), g->getY(), 0 ); // Größe und Position ändern
	p->release();
	g->release();
}

void WFenster::setBildschirm( Bildschirm *screen )
{
	if( this->screen )
		this->screen->release();
	this->screen = screen;
}

void WFenster::zerstören()
{
	DestroyWindow( hWnd );
	if( rahmen )
		DestroyWindow( rahmen );
	if( bitmap )
		DeleteObject( bitmap );
	if( hdc )
		DeleteDC( hdc );
}

void WFenster::doMausAktion( MausEreignis *me )
{
	if( !MausAktion )
		return;
	if( !MausAktion( this, *me ) )
		return;
	if( screen )
	{
		if( screen->getMembers() )
		{
			screen->getMembers()->sendMausAll( me );
			if( !me->verarbeitet && verschiebbar )
			{
				if( mx != -1 && my != -1 ) // verschieben
				{
					RECT r;
					if( rahmen )
					{
						GetWindowRect( rahmen, &r );
						r.right -= r.left, r.bottom -= r.top;
						r.left += me->mx - mx;
						r.top += me->my - my;
						SetWindowPos( rahmen, 0, r.left, r.top, r.right, r.bottom, 0 ); // Position setzen
					}
					GetWindowRect( hWnd, &r ); // Vorherige Position herausfinden
					r.right -= r.left, r.bottom -= r.top; // Position updaten
					r.left += me->mx - mx;
					r.top += me->my - my;
					SetWindowPos( hWnd, 0, r.left, r.top, r.right, r.bottom, 0 ); // Position setzen

				}
				else if( me->id == ME_PLinks ) // verschieben starten
					mx = me->mx, my = me->my;
				if( me->id == ME_RLinks ) // verschieben beenden
					mx = -1, my = -1;
				me->verarbeitet = 1;
			}
		}
	}
}

void WFenster::doVSchließAktion()
{
	if( !VSchließAktion )
		return;
	VSchließAktion( this );
}

void WFenster::doNSchließAktion()
{
	if( !NSchließAktion )
		return;
	NSchließAktion( this );
}

void WFenster::doTastaturAktion( TastaturEreignis *te )
{
	if( !TastaturAktion )
		return;
	if( !TastaturAktion( this, *te ) )
		return;
	if( screen )
		if( screen->getMembers() )
			screen->getMembers()->sendTastaturAll( te );
}

void WFenster::doRestoreMessage() // macht den Rahmen sichtbar
{
	if( rahmen )
		ShowWindow( rahmen, 1 );
	ShowWindow( hWnd, 1 );
}

void WFenster::setMausAktion( bool (*MausAk)( WFenster *, MausEreignis ) )
{
	MausAktion = MausAk;
}

void WFenster::setVSchließAktion( void (*vSchließAk)( WFenster *) )
{
	VSchließAktion = vSchließAk;
}

void WFenster::setNSchließAktion( void (*nSchließAk)( WFenster *) )
{
	NSchließAktion = nSchließAk;
}

void WFenster::setTastaturAktion( bool (*TastaturAk)( WFenster *, TastaturEreignis ) )
{
	TastaturAktion = TastaturAk;
}

void WFenster::setFensterHandle( HWND hWnd ) // setzt das operationsfenster
{
	this->hWnd = hWnd;
}

void WFenster::setVerschiebbar( bool verschiebbar ) // legt fest, ob das Fenster durch ziehen mit Maus verschoben werden kann
{
	this->verschiebbar = verschiebbar;
}

void WFenster::ladeRahmenFenster( Bild *zBild, HINSTANCE hinst ) // setzt einen Transpatenten Rahmen um das Fenster
{
	if( !zBild )
		return;
	// Fenster erstellen
	WNDCLASSEX wcl = { 0 };
    wcl.cbSize = sizeof( wcl );
    wcl.style = CS_HREDRAW | CS_VREDRAW;
    wcl.lpfnWndProc = WindowProc;
    wcl.cbClsExtra = 0;
    wcl.cbWndExtra = 0;
    wcl.hInstance = hinst;
    wcl.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcl.hbrBackground = NULL;
    wcl.lpszMenuName = NULL;
    wcl.lpszClassName = TEXT("LayeredWindowClass");
    wcl.hIconSm = NULL;

	// Bitmap erstellen
	hdc = CreateCompatibleDC(NULL);
	if( !hdc )
		return;
	BITMAPINFO info;
	info.bmiHeader.biSize = sizeof( info.bmiHeader );
	info.bmiHeader.biBitCount = 32;
	info.bmiHeader.biWidth = zBild->getBreite();
	info.bmiHeader.biHeight = -zBild->getHöhe();
	info.bmiHeader.biCompression = BI_RGB;
	info.bmiHeader.biPlanes = 1;
	unsigned char *pPixels = 0;
	bitmap = CreateDIBSection( hdc, &info, DIB_RGB_COLORS, (void**)&pPixels, 0, 0 );
	if( !bitmap )
	{
		DeleteObject( bitmap );
		DeleteDC( hdc );
	}
	GdiFlush();
	// bitmap füllen
	int pitch = ( ( zBild->getBreite() * 32 + 31 ) & ~31 ) >> 3;
	unsigned char *pRow = 0;
	int *buffer = zBild->getBuffer();
	for( int i = 0; i < zBild->getHöhe(); i++ )
	{
		pRow = &pPixels[ i * pitch ];
		for( int i2 = 0; i2 < zBild->getBreite(); i2++ )
		{
			pRow[ i2 * 4 ] = (unsigned char)( ( buffer[ i2 + i * zBild->getBreite() ] >> 16 ) & 0xFF );
			pRow[ i2 * 4 + 1 ] = (unsigned char)( ( buffer[ i2 + i * zBild->getBreite() ] >> 8 ) & 0xFF );
			pRow[ i2 * 4 + 2] = (unsigned char)( ( buffer[ i2 + i * zBild->getBreite() ] ) & 0xFF );
			pRow[ i2 * 4 + 3] = (unsigned char)( ( buffer[ i2 + i * zBild->getBreite() ] >> 24 ) & 0xFF );
		}
	}
	// alpha berechnen
	unsigned char *pPixel  = 0;
	if( zBild->getBreite() * 4 == pitch )
	{
		int i = 0;
		int totalBytes = zBild->getBreite() * zBild->getHöhe() * 4;
		
		for( i = 0; i < totalBytes; i += 4 )
		{
			pPixel = &pPixels[ i ];
			pPixel[0] *= (unsigned char)( (float)pPixel[ 3 ] / 255.0f );
			pPixel[1] *= (unsigned char)( (float)pPixel[ 3 ] / 255.0f );
			pPixel[2] *= (unsigned char)( (float)pPixel[ 3 ] / 255.0f );
		}
	}
	else
	{
		int x = 0;
		int y = 0;
		
		for( y = 0; y < zBild->getHöhe(); ++y )
		{
			for( x = 0; x < zBild->getBreite(); ++x )
			{
				pPixel = &pPixels[ ( y * pitch ) + ( x * 4 ) ];
				pPixel[0] *= (unsigned char)( (float)pPixel[ 3 ] / 255.0f );
				pPixel[1] *= (unsigned char)( (float)pPixel[ 3 ] / 255.0f );
				pPixel[2] *= (unsigned char)( (float)pPixel[ 3 ] / 255.0f );
			}
		}
	}
	// Fenster erstellen fortsetzen
	if( RegisterClassEx( &wcl ) )
	{
		rahmen = CreateWindowEx( WS_EX_TOOLWINDOW | WS_EX_LAYERED,
								 wcl.lpszClassName,
								 TEXT( "Transparentes Fenster" ),
								 WS_POPUP,
								 0,
								 0,
								 zBild->getBreite(),
								 zBild->getHöhe(),
								 0,
								 0,
								 wcl.hInstance,
								 0
							   );
		if( rahmen )
		{
			// zeichnen
			HDC h = 0;
			if( h = GetDC( rahmen ) )
			{
				HGDIOBJ hPrevObj = NULL;
				POINT ptDest = { 0, 0 };
				POINT ptSrc = { 0, 0 };
				SIZE client = { zBild->getBreite(), zBild->getHöhe() };
				BLENDFUNCTION blendFunc = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };

				hPrevObj = SelectObject( hdc, bitmap );
				ClientToScreen( rahmen, &ptDest );

				UpdateLayeredWindow( rahmen, h, &ptDest, &client, hdc, &ptSrc, 0, &blendFunc, ULW_ALPHA );

				SelectObject( hdc, hPrevObj );
				ReleaseDC( rahmen, h );
			}
			UpdateWindow( rahmen );
			Punkt *pos = getPosition();
			Punkt *gr = getGröße();
			pos->x += ( gr->x - zBild->getBreite() ) / 2;
			pos->y += ( gr->y - zBild->getHöhe() ) / 2;
			SetWindowPos( rahmen, 0, pos->x, pos->y, zBild->getBreite(), zBild->getHöhe(), 0 );
			pos->release();
			gr->release();
		}
	}
}

// constant 
Punkt *WFenster::getPosition() const // gibt die Position zurück
{
	RECT r;
	GetWindowRect( hWnd, &r ); // Position herausfinden
	return new Punkt( r.left, r.top );
}

Punkt *WFenster::getGröße() const // gibt die Größe zurück
{
	RECT r;
	GetWindowRect( hWnd, &r ); // Größe herausfinden
	return new Punkt( r.right - r.left, r.bottom - r.top );
}

HWND WFenster::getFensterHandle() const // gibt ein Handle zum Fenster zurück
{
	return hWnd;
}

bool WFenster::hatMausAktion() const
{
	return MausAktion != 0;
}

bool WFenster::hatVSchließAktion() const
{
	return VSchließAktion != 0;
}

bool WFenster::hatNSchließAktion() const
{
	return NSchließAktion != 0;
}

bool WFenster::hatTastaturAktion() const
{
	return TastaturAktion != 0;
}

Bildschirm *WFenster::getBildschirm() const
{
	if( !screen )
		return 0;
	return screen->getThis();
}

Bildschirm *WFenster::zBildschirm() const
{
	return screen;
}

bool WFenster::istVerschiebbar() const // prüft, ob das Fenster durch ziehen mit Maus verschoben werden kann
{
	return verschiebbar;
}

// Reference Counting
WFenster *WFenster::getThis()
{
	ref++;
	return this;
}

WFenster *WFenster::release()
{
	ref--;
	if( ref < 1 )
		delete this;
	return 0;
}

// Inhalt der WFensterArray Klasse aus Fenster.h
// Konstruktor 
WFensterArray::WFensterArray()
{
	next = 0;
	This = 0;
}

// Destruktor 
WFensterArray::~WFensterArray()
{
	if( next )
		delete next;
}

// add und remove 
bool WFensterArray::addFenster( WFenster *fenster )
{
	if( fenster == This )
		return 0;
	if( !This )
	{
		This = fenster;
		return 1;
	}
	if( !next )
		next = new WFensterArray();
	return next->addFenster( fenster );
}

bool WFensterArray::removeFenster( WFenster *fenster )
{
	if( fenster == This )
		return 1;
	if( !next )
		return 0;
	if( next->removeFenster( fenster ) )
	{
		WFensterArray *tmp = next->getNext();
		next->setNext0();
		delete next;
		next = tmp;
	}
	return 0;
}

WFensterArray *WFensterArray::getNext()
{
	return next;
}

void WFensterArray::setNext0()
{
	next = 0;
}

void WFensterArray::del()
{
	if( next )
	{
		This = next->getThis();
		WFensterArray *tmp = next->getNext();
		next->setNext0();
		delete next;
		next = tmp;
	}
	else
		This = 0;
}

// Messages
bool WFensterArray::sendVSchließMessage( HWND hwnd )
{
	if( !This )
		return 0;
	bool ret = 0;
	if( This->getFensterHandle() == hwnd && This->hatVSchließAktion() )
	{
		This->doVSchließAktion();
		ret = 1;
	}
	if( !next )
		return ret;
	if( ret )
		next->sendVSchließMessage( hwnd );
	else
		ret = next->sendVSchließMessage( hwnd );
	return ret;
}

bool WFensterArray::sendNSchließMessage( HWND hwnd )
{
	if( !This )
		return 0;
	bool ret = 0;
	if( This->getFensterHandle() == hwnd && This->hatNSchließAktion() )
	{
		This->doNSchließAktion();
		ret = 1;
	}
	if( !next )
		return ret;
	if( ret )
		next->sendNSchließMessage( hwnd );
	else
		ret = next->sendNSchließMessage( hwnd );
	return ret;
}

bool WFensterArray::sendMausMessage( HWND hwnd, MausEreignis *me )
{
	if( !This )
		return 0;
	bool ret = 0;
	if( This->getFensterHandle() == hwnd && This->hatMausAktion() )
	{
		This->doMausAktion( me );
		ret = 1;
	}
	if( !next )
		return ret;
	if( ret )
		next->sendMausMessage( hwnd, me );
	else
		ret = next->sendMausMessage( hwnd, me );
	return ret;
}

bool WFensterArray::sendTastaturMessage( HWND hwnd, TastaturEreignis *te )
{
	if( !This )
		return 0;
	bool ret = 0;
	if( This->getFensterHandle() == hwnd && This->hatMausAktion() )
	{
		This->doTastaturAktion( te );
		ret = 1;
	}
	if( !next )
		return ret;
	if( ret )
		next->sendTastaturMessage( hwnd, te );
	else
		ret = next->sendTastaturMessage( hwnd, te );
	return ret;
}

bool WFensterArray::sendRestoreMessage( HWND hwnd )
{
	if( !This )
		return 0;
	bool ret = 0;
	if( This->getFensterHandle() == hwnd && This->hatMausAktion() )
	{
		This->doRestoreMessage();
		ret = 1;
	}
	if( !next )
		return ret;
	if( ret )
		next->sendRestoreMessage( hwnd );
	else
		ret = next->sendRestoreMessage( hwnd );
	return ret;
}

WFenster *WFensterArray::getThis()
{
	return This;
}

// WMessageBox
void Framework::WMessageBox( HWND hWnd, Text *titel, Text *meldung, UINT style )
{
	MessageBox( hWnd, meldung->getText(), titel->getText(), style ); // Message Box
	titel->release();
	meldung->release();
}