#include <SDL/SDL.h>
#include <SDL/SDL_net.h>
#include "RSClient.h"

#include "RSConsts.h"

#ifdef _DEV_CPP_
#undef main
#endif

RSClient rsClients[RSConsts::MAX_CLIENT];

bool bIsQuit = false;

/** パケット情報から、接続済みのクライアントを探す。無かったら新しく接続する
  * @param[in]	lpPacket	パケット情報（中のアドレスホスト名を使用）
  * @retval		RSClient*	取得できたクライアントへのインデックス
  * @retval		NULL		取得できなかった場合
  */
RSClient* searchOrRegisterClient( UDPpacket* lpPacket ) {
	// search already registered
	for( int i = 0; i < RSConsts::MAX_CLIENT; i ++ ) {
		if( rsClients[i].m_IPAddress.host == lpPacket->address.host &&
			rsClients[i].m_IPAddress.port == lpPacket->address.port)
		{
			fprintf( stdout, "establish:hostname=%x, port=%x, id=%d\n", lpPacket->address.host, lpPacket->address.port, i);
			// already registered
			return &rsClients[i];
		}
	}

	// 見つからなかった
	// 新しく登録する
	for( int i = 0; i < RSConsts::MAX_CLIENT; i ++ ) {
		if( rsClients[i].m_nConnectState == RSConsts::ConnectState::WAIT ) {
			rsClients[i].m_PacketData.m_nID = i;
			fprintf( stdout, "connect:hostname=%x, port=%x, id=%d\n", lpPacket->address.host, lpPacket->address.port, i);
			return &rsClients[i];
		}
	}
	fprintf( stdout, "client full:hostname=%x, port=%x, id=%d\n", lpPacket->address.host, lpPacket->address.port, -1);
	// 空いていなかった
	return NULL;
}

int func( void* data ) {
	while( bIsQuit == false ) {
		Uint32 last = SDL_GetTicks();

/*		for( int i = 0; i < RSConsts::ConnectState; i ++ ) {
		}*/

		while( SDL_GetTicks() - last < RSConsts::PREFERRED_WAIT_FRAME_NUM ) {
			SDL_Delay(1);
		}
	}
	return 0;
}

int main( int argc, char** argv ) {

	UDPsocket sdServerSocket;		// socket descriptor
	UDPpacket *lpPacket;
	// 
	if( SDLNet_Init() < 0 ) {
		fprintf( stderr, "SDLNet_Init: %s\n", SDLNet_GetError() );
		return 1;
	}

	// 待ち受けソケットポート
	// open socket
	if( !( sdServerSocket = SDLNet_UDP_Open( 5000 ) ) ) {
		fprintf( stderr, "SDLNet_Init: %s\n", SDLNet_GetError() );
		return 2;
	}

	// create packet data
	if( !( lpPacket = SDLNet_AllocPacket( PACKET_DATA_LENGTH ) ) ) {
		exit(3 );
	}

	// create and start timeout counter
	SDL_Thread* lpTimeOutThread = SDL_CreateThread( func, NULL );

	// 送信ソケット
/*	UDPsocket sdClientSocket;
	UDPpacket* lpClientPacket;
	if( !( sdClientSocket = SDLNet_UDP_Open( 6000 ) ) ) {
		return 2;
	}*/
	
	while( bIsQuit == false ) {
		// wait a packet
		if( SDLNet_UDP_Recv( sdServerSocket, lpPacket ) ){

			RSClient* lpClient = searchOrRegisterClient( lpPacket );
			if( lpClient != NULL ) {
				// 取得できた

				// Connect
				lpClient->m_nConnectState = RSConsts::ConnectState::ESTABLISH;

				// ホスト名設定
				lpClient->m_IPAddress = lpPacket->address;

				// データ設定

				int nLength = lpPacket->len;
				if( nLength != PACKET_DATA_LENGTH ) {
					// データサイズが異なる

					// 無視
					continue;
				}

				// データを変換
				lpClient->m_PacketData = (*((PacketData*)( lpPacket->data )));
				fprintf( stdout, "[state:%d][x:%d,y:%d]\n",
					lpClient->m_PacketData.m_nState,
					lpClient->m_PacketData.m_nX,
					lpClient->m_PacketData.m_nY );

				// 他のクライアントに送付
				for( int i = 0; i < RSConsts::MAX_CLIENT; i ++ ) {
					int nUUID = -1;

					if( lpClient == &rsClients[i] ) {
						nUUID = i;
					}
					if( rsClients[i].m_nConnectState == RSConsts::ConnectState::ESTABLISH ) {
						rsClients[i].m_PacketData.m_nUUID = nUUID;
						lpPacket->data = (Uint8*)(&rsClients[i].m_PacketData);
						lpPacket->address = rsClients[i].m_IPAddress;
						lpPacket->address.port = RSConsts::CLIENT_RECV_PORT;
						lpPacket->len = PACKET_DATA_LENGTH;
						SDLNet_UDP_Send( sdServerSocket, -1, lpPacket );
					}

				}
			}
		}
	}

	// wait quitting
	int status = 0;
	SDL_WaitThread( lpTimeOutThread , &status );

	// free and quit
	SDLNet_FreePacket( lpPacket );
	SDLNet_Quit();
	return 0;
}
