#include "Netzwerk.h"
#include <main.h>
#include <Datei.h>
#include <Fenster.h>
#include <Globals.h>
#include <InitDatei.h>
#include "Keys.h"

int KSGStart Framework::Start( Startparam p )
{
	Network::Start( 10 );
	char serverReturn = 0;

	HANDLE Mutex = OpenMutex( MUTEX_ALL_ACCESS, false, "KSG_Client" );
	if( Mutex == NULL )
	{
		Mutex = CreateMutex( NULL, true, "KSG_Client" );
		DateiRemove( new Text( "data/tmp/k.id" ) );
		DateiRemove( new Text( "data/tmp/keinabsturz" ) );
	}
	else
	{
		WMessageBox( 0, new Text( "Fehler" ), new Text( "Das Programm läuft bereits. Wenn dieß nicht der Fall ist,\nmusst du den Komputer neu starten." ), MB_ICONERROR );
		Network::Exit();
		return 0;
	}

	if( DateiExistiert( new Text( "data/update/unable/list.patch" ) ) )
	{
		PROCESS_INFORMATION prozessinfo3;
		STARTUPINFO startinfo3;
		ZeroMemory( &startinfo3, sizeof( STARTUPINFOW ) );
		startinfo3.cb = sizeof( STARTUPINFOW );

		if( CreateProcess( 0, "data/patch/bin/übernehmen.exe", 0, 0, 0, 0, 0, 0, &startinfo3, &prozessinfo3 ) == 1 )
		{
			Network::Exit();
			DateiRemove( new Text( "data/tmp" ) );
			exit( 0 );
		}
		else
		{
			WMessageBox( 0, new Text( "Fehler" ), new Text( "Bei dem Übernehen der Änderungen ist ein Fehler aufgetreten.\nBitte starte den Komputer neu. Sollte diese Meldung weiterhin\nerscheinen, so musst du das Spiel neu Installieren." ), MB_ICONERROR );
			exit( 0 );
		}
	}

	PROCESS_INFORMATION prozessinfo1;
	STARTUPINFO startinfo1;
	startinfo1.cb = sizeof( STARTUPINFOW );
	ZeroMemory( &startinfo1, sizeof( STARTUPINFOW ) );
	bool pe = 0;

	if( CreateProcess( 0, "data/start/icon.exe", 0, 0, 0, 0, 0, 0, &startinfo1, &prozessinfo1 ) == 1 )
	{
		CloseHandle( prozessinfo1.hThread );
		pe = 1;
	}

	InitDatei *iDat = new InitDatei( "data/optionen.ini" );
	iDat->laden();
	if( !iDat->zWert( "ServerIP" ) )
		iDat->addWert( "ServerIP", "127.0.0.1" );
	if( !iDat->zWert( "ServerPort" ) )
		iDat->addWert( "ServerPort", "4225" );
	iDat->speichern();
	Text *ipT = iDat->getWert( "ServerIP" );
	unsigned short port = (unsigned short)TextZuInt( iDat->zWert( "ServerPort" )->getText(), 10 );
	iDat->release();
    SSLKlient *klientSSL = new SSLKlient();
    int l = 0;
	if( !klientSSL->verbinde( port, ipT->getText() ) )
	{
		Text *message = new Text( "Der Server wurde nicht gefunden.\nServer Ip:" );
		message->append( ipT->getText() );
		message->append( "\nServer Port:" );
		message->append( (int)port );
		WMessageBox( 0, new Text( "Fehler" ), message, MB_ICONERROR );
		ipT->release();
        klientSSL->release();
		Network::Exit();
		return 0;
	}
    klientSSL->sende( "\1", 5 );
	char byte = 0;
    klientSSL->getNachricht( &byte, 1 );
	if( byte == 3 )
	{
        klientSSL->getNachricht( &byte, 1 );
		char *message = new char[ byte + 1 ];
		message[ byte ] = 0;
        klientSSL->getNachricht( message, byte );
		Text *nachricht = new Text( "Fehler während der Identifikation beim Server.\nServer Rückgabe:\n " );
		nachricht->append( message );
		WMessageBox( 0, new Text( "Server Fehler" ), nachricht, MB_ICONERROR );
		delete[]message;
		ipT->release();
        klientSSL->sende( "\3", 1 );
		klientSSL->getNachricht( &serverReturn, 1 );
		klientSSL->trenne();
		klientSSL->release();
		Network::Exit();
		return 0;
	}
	int klientNummer = 0;
	char *netwSchlüssel = 0;
	char netwSchlüsselLän = 0;
    int normPort = 0;
	if( byte == 1 )
	{
        klientSSL->getNachricht( (char*)&normPort, 4 );
		klientSSL->getNachricht( (char*)&klientNummer, 4 );
		klientSSL->getNachricht( &netwSchlüsselLän, 1 );
		if( netwSchlüsselLän )
		{
			netwSchlüssel = new char[ netwSchlüsselLän ];
            klientSSL->getNachricht( netwSchlüssel, netwSchlüsselLän );
			Datei *dat = new Datei();
			dat->setDatei( "data/tmp/schlüssel.netw" );
			dat->erstellen();
			dat->open( Datei::Style::schreiben );
			dat->schreibe( &netwSchlüsselLän, 1 );
			dat->schreibe( netwSchlüssel, netwSchlüsselLän );
			dat->close();
			dat->release();
		}
	}
	else
	{
		WMessageBox( 0, new Text( "Server Fehler" ), new Text( "Unbekannte Rückgabe vom Server.\nEventuell ist deine Version des Spiels veraltet." ), MB_ICONERROR );
		ipT->release();
		klientSSL->sende( "\3", 1 );
		klientSSL->getNachricht( &serverReturn, 1 );
		klientSSL->trenne();
		klientSSL->release();
		Network::Exit();
		delete[] netwSchlüssel;
		return 0;
	}
	Datei *dat = new Datei();
	dat->setDatei( "data/tmp/k.id" );
	dat->erstellen();
	dat->open( Datei::Style::schreiben );
	dat->schreibe( (char*)&klientNummer, 4 );
	dat->close();
    dat->setDatei( "data/tmp/m.port" );
    dat->erstellen();
    dat->open( Datei::Style::schreiben );
    dat->schreibe( (char*)&normPort, 4 );
    dat->close();
	dat->release();
	klientSSL->sende( "\3", 1 );
	klientSSL->getNachricht( &serverReturn, 1 );
	klientSSL->trenne();
	klientSSL->release();

	ErhaltungKlient *erhaltung = new ErhaltungKlient( klientNummer );
	erhaltung->verbinden( normPort, ipT, netwSchlüssel, netwSchlüsselLän );

	if( pe )
	{
		while( WaitForSingleObject( prozessinfo1.hProcess, 1000 ) == WAIT_TIMEOUT );
		CloseHandle( prozessinfo1.hProcess );
	}

	PROCESS_INFORMATION prozessinfo2;
	STARTUPINFO startinfo2;
	startinfo2.cb = sizeof( STARTUPINFOW );
	ZeroMemory( &startinfo2, sizeof( STARTUPINFOW ) );

	if( CreateProcess( 0, "data/patch/bin/patcher.exe", 0, 0, 0, 0, 0, 0, &startinfo2, &prozessinfo2 ) == 1 )
	{
		CloseHandle( prozessinfo2.hThread );
		while( WaitForSingleObject( prozessinfo2.hProcess, 5000 ) == WAIT_TIMEOUT );
		unsigned long erfolg = 0;
		GetExitCodeProcess( prozessinfo2.hProcess, &erfolg );
		if( erfolg != 0 && DateiExistiert( new Text( "data/tmp/keinabsturz" ) ) )
		{
			bool gamestart = erfolg == 2;
			if( erfolg == 1 )
			{
				PROCESS_INFORMATION prozessinfo3;
				STARTUPINFO startinfo3;
				startinfo3.cb = sizeof( STARTUPINFOW );
				ZeroMemory( &startinfo3, sizeof( STARTUPINFOW ) );

				if( CreateProcess( 0, "data/patch/bin/übernehmen.exe", 0, 0, 0, 0, 0, 0, &startinfo3, &prozessinfo3 ) == 1 )
				{
					if( DateiExistiert( new Text( "data/tmp/keinabsturz" ) ) )
						erhaltung->abmelden();
					erhaltung->trennen();
					erhaltung->warteAufThread( 5000 );
					erhaltung->release();
					Klient *klient = new Klient();
                    int l = 0;
                    char *key;
                    Keys::getServerKey( &key, l, Keys::MAIN, Keys::SENDEN );
                    klient->setSendeKey( key, l );
                    delete[] key;
                    Keys::getServerKey( &key, l, Keys::MAIN, Keys::EMPFANGEN );
                    klient->setEmpfangKey( key, l );
                    delete[] key;
					if( !klient->verbinde( normPort, ipT->getText() ) )
					{
						WMessageBox( 0, new Text( "Fehler" ), new Text( "Die Verbindung zum Server ist abgebrochen." ), MB_ICONERROR );
						ipT->release();
						klient->release();
						Network::Exit();
						delete[] netwSchlüssel;
						return 0;
					}
					klient->sende( "\0", 1 ); // Verschlüsselung aktivieren
					klient->sendeEncrypted( "\1", 1 );
					klient->sendeEncrypted( (char*)&klientNummer, 4 );
					klient->getNachrichtEncrypted( &serverReturn, 1 );
					if( serverReturn == 3 )
					{
						klient->getNachrichtEncrypted( &byte, 1 );
						char *message = new char[ byte + 1 ];
						message[ byte ] = 0;
						klient->getNachrichtEncrypted( message, byte );
						Text *nachricht = new Text( "Fehler während der Identifikation beim Server.\nServer Rückgabe:\n " );
						nachricht->append( message );
						WMessageBox( 0, new Text( "Server Fehler" ), nachricht, MB_ICONERROR );
						delete[] message;
					}
					else
					{
						klient->setSendeKey( netwSchlüssel, netwSchlüsselLän );
						klient->setEmpfangKey( netwSchlüssel, netwSchlüsselLän );
					}
					klient->sendeEncrypted( "\7", 1 );
					klient->getNachrichtEncrypted( &serverReturn, 1 );
					if( serverReturn == 3 )
					{
						klient->getNachrichtEncrypted( &byte, 1 );
						char *message = new char[ byte + 1 ];
						message[ byte ] = 0;
						klient->getNachrichtEncrypted( message, byte );
						Text *nachricht = new Text( "Fehler während der Abmeldung beim Server.\nServer Rückgabe:\n " );
						nachricht->append( message );
						WMessageBox( 0, new Text( "Server Fehler" ), nachricht, MB_ICONERROR );
						delete[]message;
					}
					klient->sendeEncrypted( "\3", 1 );
					klient->getNachrichtEncrypted( &serverReturn, 1 );
					klient->trenne();
					ipT->release();
					klient->release();
					Network::Exit();

					DateiRemove( new Text( "data/tmp" ) );

					exit( 0 );
				}
				else
					gamestart = 0;
				if( !gamestart )
					WMessageBox( 0, new Text( "Fehler" ), new Text( "Bei dem Übernehen der Änderungen ist ein Fehler aufgetreten." ), MB_ICONERROR );
			}
			if( gamestart )
			{
				PROCESS_INFORMATION prozessinfo3;
				STARTUPINFO startinfo3;
				startinfo3.cb = sizeof( STARTUPINFOW );
				ZeroMemory( &startinfo3, sizeof( STARTUPINFOW ) );
				DateiRemove( new Text( "data/tmp/keinabsturz" ) );

				if( CreateProcess( 0, "\"data/client/bin/game client.exe\"", 0, 0, 0, 0, 0, 0, &startinfo3, &prozessinfo3 ) == 1 )
				{
					CloseHandle( prozessinfo3.hThread );
					while( WaitForSingleObject( prozessinfo3.hProcess, 5000 ) == WAIT_TIMEOUT );
					CloseHandle( prozessinfo3.hProcess );
				}
				else
					WMessageBox( 0, new Text( "Fehler" ), new Text( "Das Spiel konnte nicht gestartet werden." ), MB_ICONERROR );
			}
		}
		CloseHandle( prozessinfo2.hProcess );
	}
	else
	{
		WMessageBox( 0, new Text( "Fehler" ), new Text( "Der Patcher konnte nicht gestartet werden." ), MB_ICONERROR );
	}
	if( DateiExistiert( new Text( "data/tmp/keinabsturz" ) ) )
		erhaltung->abmelden();
	erhaltung->trennen();
	erhaltung->warteAufThread( 5000 );
	erhaltung->release();

	Klient *klient = new Klient();
    char *key;
    Keys::getServerKey( &key, l, Keys::MAIN, Keys::SENDEN );
    klient->setSendeKey( key, l );
    delete[] key;
    Keys::getServerKey( &key, l, Keys::MAIN, Keys::EMPFANGEN );
    klient->setEmpfangKey( key, l );
    delete[] key;
	if( !klient->verbinde( normPort, ipT->getText() ) )
	{
		WMessageBox( 0, new Text( "Fehler" ), new Text( "Die Verbindung zum Server ist abgebrochen." ), MB_ICONERROR );
		ipT->release();
		klient->release();
		Network::Exit();
		delete[] netwSchlüssel;
		return 0;
	}
	klient->sende( "\0", 1 ); // Verschlüsselung aktivieren
	klient->sendeEncrypted( "\1", 1 );
	klient->sendeEncrypted( (char*)&klientNummer, 4 );
	klient->getNachrichtEncrypted( &serverReturn, 1 );
	if( serverReturn == 3 )
	{
		klient->getNachrichtEncrypted( &byte, 1 );
		char *message = new char[ byte + 1 ];
		message[ byte ] = 0;
		klient->getNachrichtEncrypted( message, byte );
		Text *nachricht = new Text( "Fehler während der Identifikation beim Server.\nServer Rückgabe:\n " );
		nachricht->append( message );
		WMessageBox( 0, new Text( "Server Fehler" ), nachricht, MB_ICONERROR );
		delete[]message;
	}
	else
	{
		klient->setSendeKey( netwSchlüssel, netwSchlüsselLän );
		klient->setEmpfangKey( netwSchlüssel, netwSchlüsselLän );
	}
	klient->sendeEncrypted( "\7", 1 );
	klient->getNachrichtEncrypted( &serverReturn, 1 );
	if( serverReturn == 3 )
	{
		klient->getNachrichtEncrypted( &byte, 1 );
		char *message = new char[ byte + 1 ];
		message[ byte ] = 0;
		klient->getNachrichtEncrypted( message, byte );
		Text *nachricht = new Text( "Fehler während der Abmeldung beim Server.\nServer Rückgabe:\n " );
		nachricht->append( message );
		WMessageBox( 0, new Text( "Server Fehler" ), nachricht, MB_ICONERROR );
		delete[]message;
	}
	klient->sendeEncrypted( "\3", 1 );
	klient->getNachrichtEncrypted( &serverReturn, 1 );
	klient->trenne();
	ipT->release();
	klient->release();
	Network::Exit();

	DateiRemove( new Text( "data/tmp" ) );

	delete[] netwSchlüssel;

	return 0;
}