/*
	Lan Wars.
	Copyright (c) 2009, Darragh Coy.
	All rights reserved.
	Original work(s), source code & author(s) details available at: http://www.darraghcoy.com

	Redistribution and use in source and binary forms, with or without modification, are permitted 
	provided that the following conditions are met:

		* 	Redistributions of source code must retain the above copyright notice, this list of 
			conditions and the following disclaimer.
		* 	Redistributions in binary form must reproduce the above copyright notice, this list of 
			conditions and the following disclaimer in the documentation.
		* 	Neither the name of the author nor the names of contributors may be used to endorse or 
			promote products derived from this software without specific prior written permission.
		* 	The use of any third party libraries, modules or data files provided with the source 
			form of the program must follow and respect the individual licensing terms of these 
			components. You do not have permission to modify or circumvent the licensing terms for 
			provided third party components unless the third party licenses specifically allow this. 
			If you do not agree to the terms of provided third party components then you do not have 
			permission to use them in your derived work(s).
		* 	The terms of this license do not apply to separate (but related) distributions if supplied 
			by the author(s), only to the contents of this source distribution, derived works, and the 
			binaries produced by either modified or unmodified versions of the source code. The terms 
			of this license do not also apply to any third party libraries or components provided with 
			the source distribution. Such third party elements are licensed under their own separate 
			agreements.

	THIS SOFTWARE IS PROVIDED BY DARRAGH COY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
	BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
	ARE DISCLAIMED. IN NO EVENT SHALL DARRAGH COY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
	OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//=====================================================================================================================
/// @brief		Class that represents the menus for the game. This class is responsible for both drawing the menus
///				and for handling user input on the menus.
//=====================================================================================================================

#include "Precompiled.h"
#include "Game\GameMenus.h"
#include "Game\GameCore.h"
#include "Game\GameSession.h"
#include "GameObjects\GamePlayer.h"
#include "Resources\BitmapFontManager.h"
#include "Resources\TextureManager.h"
#include "Graphics\Camera2D.h"
#include "Graphics\PrimitivesRenderer.h"
#include "Graphics\BitmapFont.h"
#include "Windows\Window.h"
#include "Network\NetworkAddress.h"

using namespace Game;

//=====================================================================================================================
/// @brief		Creates the menus
/// @pre		The game must exist
/// @pre		The game must have a texture manager
/// @pre		The game must have a bitmap font manager
//=====================================================================================================================

GameMenus::GameMenus()
{
	// Make sure ok:

	ENSURE( GameCore::GetSingleton()							, "The game must exist"							)
	ENSURE( GameCore::GetSingleton()->GetTextureManager()		, "The game must have a texture manager"		)
	ENSURE( GameCore::GetSingleton()->GetBitmapFontManager()	, "The game must have a bitmap font manager"	)
	
	// Get the game:
	
	GameCore * game = GameCore::GetSingleton();
	
	// Load our font:
	
	m_font = game->GetBitmapFontManager()->GetBitmapFont("Fonts\\Game64.xml");
	
	// Load our background texture:
	
	m_background_tex = game->GetTextureManager()->GetTexture("Textures\\MenuBackground.dds");
	
	// Load the hud bar texture
	
	m_hud_bar_tex = game->GetTextureManager()->GetTexture("Textures\\Hudbar.dds");
	
	// Create our camera:
	
	m_camera = new Camera2D( game->GetWindow() , Vec2f::Zero() , GameCore::NATIVE_RES , 1.0f , 10000.0f );
	
	// See if we have valid resources:
	
	if ( m_background_tex.IsValid() && m_hud_bar_tex.IsValid() && m_font.IsValid() )
	{
		m_valid_resources = true;
	}
	else
	{
		m_valid_resources = false;
	}
	
	// Don't show instructions
	
	m_show_instructions = false;
	
	// Reset previous kb state:
	
	m_kbs_prev.Clear();
}

//=====================================================================================================================
/// @brief		Destroys the menus
//=====================================================================================================================

GameMenus::~GameMenus()
{
	// Free all resources
	
	m_camera->RemoveReference();
}

//=====================================================================================================================
/// @brief		Annouces the type name for this object.
/// @returns	Type name of this object
//=====================================================================================================================

const char * GameMenus::GetTypeName() const
{
	return "GameMenus";
}

//=====================================================================================================================
/// @brief		Draws the current menu
/// @pre		The game must exist
/// @pre		The game must have a display
//=====================================================================================================================

void GameMenus::Draw()
{
	// Make sure ok
	
	ENSURE( GameCore::GetSingleton()				, "The game must exist"				)
	ENSURE( GameCore::GetSingleton()->GetDisplay()	, "The game must have a display"	)
	
	// Enable alpha blending for this:
	
	GameCore::GetSingleton()->GetDisplay()->GetDevice()->SetRenderState(D3DRS_ALPHABLENDENABLE,1);
	
	// Only if we have valid resources:
	
	if ( m_valid_resources )
	{
		// Draw the menu background:
		
		if ( m_menu != MENU_NONE ) DrawBackground();
		
		// See what menu we are on:
		
		switch ( m_menu )
		{
			case MENU_NONE:						DrawHud();					break;
			case MENU_START:					DrawStartMenu();			break;
			case MENU_HOST_NAME:				DrawHostNameMenu();			break;
			case MENU_SERVER_PORT:				DrawServerPortMenu();		break;
			case MENU_CLIENT_PORT:				DrawClientPortMenu();		break;
			case MENU_INVALID_PORT:				DrawInvalidPort();			break;
			case MENU_CONNECTING:				DrawConnectingMenu();		break;
			case MENU_CONNECTION_REFUSED:		DrawConnectionRefused();	break;
			case MENU_CONNECTION_LOST:			DrawConnectionLost();		break;
			case MENU_INVALID_HOST_NAME:		DrawInvalidHostName();		break;
			case MENU_SERVER_DISCONNECT:		DrawServerDisconnected();	break;
			case MENU_INVALID_SERVER_SOCKET:	DrawInvalidServerSocket();	break;
		}
		
		// Draw the instructions prompt or instructions themselves if in-game:
		
		if ( m_menu == MENU_NONE && GameCore::GetSingleton()->GetSession()->IsConnected() )
		{
			if ( m_show_instructions )
			{
				DrawInstructions();
			}
			else
			{
				DrawInstructionsPrompt();
			}
		}
		else
		{
			m_show_instructions = false;
		}			
	}
	
	// Disable alpha blending after done
	
	GameCore::GetSingleton()->GetDisplay()->GetDevice()->SetRenderState(D3DRS_ALPHABLENDENABLE,0);	
}

//=====================================================================================================================
/// @brief		Does input etc. for the current menu
/// @pre		The game must exist
/// @pre		The game must have a window
/// @pre		The game must have a session object
//=====================================================================================================================

void GameMenus::DoInput()
{
	// Make sure ok:
	
	ENSURE( GameCore::GetSingleton()				, "The game must exist"					)
	ENSURE( GameCore::GetSingleton()->GetWindow()	, "The game must have a window"			)
	ENSURE( GameCore::GetSingleton()->GetSession()	, "The game must have a session object"	)
	
	// Do nothing if we have invalid resources
	
	if ( m_valid_resources == false ) return;
	
	// Get the state of the keyboard:
	
	Keyboard::State kbs = Keyboard::GetState();
	
	// See what menu we are on:
	
	switch ( m_menu )
	{
		// In-Game:
		
		case MENU_NONE:
		
			// Toggle instructions with 'I':
			
			if ( kbs.IsKeyPressed(Keyboard::KB_I) && ( m_kbs_prev.IsKeyPressed(Keyboard::KB_I) == false ))
			{
				m_show_instructions = ! m_show_instructions;
			}
		
		break;
	
		// Starting the game
	
		case MENU_START:
		
			// See what is pressed:
			
			if ( kbs.IsKeyPressed(Keyboard::KB_E) && ( m_kbs_prev.IsKeyPressed( Keyboard::KB_E ) == false ))
			{
				// Exit: close the window
			
				GameCore::GetSingleton()->GetWindow()->Close();
			}
			else if ( kbs.IsKeyPressed(Keyboard::KB_S) && ( m_kbs_prev.IsKeyPressed( Keyboard::KB_S ) == false ))
			{							
				// Set the default server port:
				
				m_server_port_string = String::ToString(GameSession::DEFAULT_SERVER_PORT);
				
				// Enter server port numebr				
				
				SetMenu( MENU_SERVER_PORT );
			}
			else if ( kbs.IsKeyPressed(Keyboard::KB_C) && ( m_kbs_prev.IsKeyPressed( Keyboard::KB_C ) == false ))
			{
				// Set the default server port:
				
				m_server_port_string = String::ToString(GameSession::DEFAULT_SERVER_PORT);			
			
				// Set host name to localhost by default
				
				m_host_name = "localhost";
				
				// Go to this menu
			
				SetMenu(MENU_HOST_NAME);
			}
		
		break;

		// Enter server port number:

		case MENU_SERVER_PORT:

			// See if enter has been pressed:
			
			if ( kbs.IsKeyPressed(Keyboard::KB_ENTER) && m_kbs_prev.IsKeyPressed(Keyboard::KB_ENTER) == false )
			{
				// See if no server port is entered:
				
				if ( m_server_port_string.size() == 0 )
				{
					// Back to start menu
				
					SetMenu(MENU_START);
				}
				else
				{
					// Convert the port to a string:
					
					unsigned port = String::ToInt(m_server_port_string,0xffffffff);
					
					// See if valid:
					
					if ( port <= 0xffff )
					{
						// Connect as a server:
						
						GameCore::GetSingleton()->GetSession()->Connect(GameSession::SESSION_SERVER, NetworkAddress("localhost",unsigned(port&0xffff)) );
						
						// Make sure connected:
						
						if ( GameCore::GetSingleton()->GetSession()->IsConnected() )
						{
							// Done with menus:
							
							SetMenu(MENU_NONE);											
						}
						else
						{
							// Error making server socket:
							
							SetMenu(MENU_INVALID_SERVER_SOCKET);
						}						
					}
					else
					{
						// Invalid port number:
						
						SetMenu(MENU_INVALID_PORT);					
					}
				}			
			}
			else
			{
				// See what keys were typed:
				
				Keyboard::GenerateCharEvents(this,m_kbs_prev,kbs);				
			}

		break;
		
		// Entering client port number:
		
		case MENU_CLIENT_PORT:
		
			// See if enter has been pressed:
			
			if ( kbs.IsKeyPressed(Keyboard::KB_ENTER) && m_kbs_prev.IsKeyPressed(Keyboard::KB_ENTER) == false )
			{
				// See if no server port is entered:
				
				if ( m_server_port_string.size() == 0 )
				{
					// Back to start menu
				
					SetMenu(MENU_HOST_NAME);
				}
				else
				{
					// Convert the port to a string:
					
					unsigned port = String::ToInt(m_server_port_string,0xffffffff);
					
					// See if valid:
					
					if ( port <= 0xffff )
					{
						// Make a network address:
						
						NetworkAddress addr( m_host_name.c_str() , (unsigned short)(port&0xffff) );

						// Make sure is valid:

						if ( addr.IsValid() == false )
						{
							// Invalid host name

							SetMenu( GameMenus::MENU_INVALID_HOST_NAME );
						}
						else
						{			
							// Connect to it:
							
							GameCore::GetSingleton()->GetSession()->Connect(GameSession::SESSION_CLIENT,addr);
							
							// Go to the connecting menu:
							
							SetMenu( GameMenus::MENU_CONNECTING );
						}				
					}
					else
					{
						// Invalid port number:
						
						SetMenu(MENU_INVALID_PORT);					
					}
				}			
			}
			else
			{
				// See what keys were typed:
				
				Keyboard::GenerateCharEvents(this,m_kbs_prev,kbs);				
			}		
		
		break;
		
		// Entering host name:
		
		case MENU_HOST_NAME:
		
			// See if enter is pressed:
			
			if ( kbs.IsKeyPressed(Keyboard::KB_ENTER) && m_kbs_prev.IsKeyPressed(Keyboard::KB_ENTER) == false )
			{
				// Goto the connecting screen if there is a host name, otherwise go back to main
				
				if ( m_host_name.size() > 0 )
				{	
					// Get the port number of the server:
						
					SetMenu(MENU_CLIENT_PORT);							
				}
				else
				{
					// Back to start menu
				
					SetMenu(MENU_START);
				}
			}
			else
			{
				// See what keys were typed:
				
				Keyboard::GenerateCharEvents(this,m_kbs_prev,kbs);
			}
		
		break;
		
		// Client is attempting to connect to the server
		
		case MENU_CONNECTING:
		
			// See if exit key is pressed:
			
			if ( kbs.IsKeyPressed( Keyboard::KB_M ) && ( m_kbs_prev.IsKeyPressed( Keyboard::KB_M ) == false ) )
			{
				// Disconnect:
				
				GameCore::GetSingleton()->GetSession()->Disconnect();
				
				// Back to main menu:
	
				SetMenu(MENU_START);
			}
		
		break;
		
		case MENU_CONNECTION_REFUSED:
		case MENU_CONNECTION_LOST:
		case MENU_INVALID_HOST_NAME:
		case MENU_INVALID_PORT:
		case MENU_SERVER_DISCONNECT:	
		case MENU_INVALID_SERVER_SOCKET:	
		
			// See if exit key is pressed:
			
			if ( kbs.IsKeyPressed( Keyboard::KB_M ) && ( m_kbs_prev.IsKeyPressed( Keyboard::KB_M ) == false ) )
			{
				// Back to main menu:
	
				SetMenu(MENU_START);
			}
		
		break;
	}
	
	// Save previous state of the keyboard:
	
	m_kbs_prev = kbs;
}

//=====================================================================================================================
/// @brief		Draws the prompt for instructions
/// @pre		Must have valid resources
/// @pre		GameCore must exist
//=====================================================================================================================				

void GameMenus::DrawInstructionsPrompt()
{
	// Make sure ok:
		
	ENSURE( m_valid_resources			, "Must have valid resources"	)	
	ENSURE( GameCore::GetSingleton()	, "GameCore must exist"			)
		
	// Get the game core object:
	
	GameCore * game_core = GameCore::GetSingleton();	
	
	// Disable z testing:
	
	game_core->GetDisplay()->GetDevice()->SetRenderState( D3DRS_ZENABLE , 0 );	
	
	// Get the view area:
	
	Vec2f view_area = m_camera->GetViewArea();
	
	// Draw the instructions prompt:
	
	m_font.DrawCentered
	(
		"Press 'I' for instructions." , 
		
		Vec3f
		(
			0					,
			view_area.y * 0.42f	,
			- 500
		),
		
		m_camera->GetViewProjectionMatrix()
	);
	
	// Enable z testing:
	
	game_core->GetDisplay()->GetDevice()->SetRenderState( D3DRS_ZENABLE , 1 );	
}

//=====================================================================================================================
/// @brief		Draws the actual instructions themselves
/// @pre		Must have valid resources
/// @pre		Game must exist
/// @pre		Game session must be connected
//=====================================================================================================================

void GameMenus::DrawInstructions()
{
	// Make sure ok:
		
	ENSURE( m_valid_resources			, "Must have valid resources"	)	
	ENSURE( GameCore::GetSingleton()	, "GameCore must exist"			)
	
	// Get the game core object:
	
	GameCore * game_core = GameCore::GetSingleton();	
	
	// Make sure the session is connected:
	
	ENSURE( GameCore::GetSingleton()->GetSession()->IsConnected() , "Game session must be connected" )
	
	// Disable z testing:
	
	game_core->GetDisplay()->GetDevice()->SetRenderState( D3DRS_ZENABLE , 0 );	
	
	// Get the view area:
	
	Vec2f view_area = m_camera->GetViewArea();
		
	// See if we are client or server: draw different instructions for each
	
	if ( game_core->GetSession()->IsClient() )
	{
		m_font.DrawCentered
		(
			"Kill the monsters! Try not to be killed: \n\n" 
			"WASD move the player.\n"
			"Use the mouse to turn.\n"
			"Left click to shoot.\n"	
			"Esc disconnects.\n" 
			"'I' to close this dialog.",			
			
			Vec3f
			(
				0						,
				view_area.y * 0.25f		,
				- 500
			),
			
			m_camera->GetViewProjectionMatrix()
		);		
	}
	else
	{
		m_font.DrawCentered
		(
			"Observe clients & monsters in the game: \n\n" 
			"WASD moves the camera.\n"
			"Keyboard arrows to turn.\n"
			"Esc disconnects.\n"
			"'I' to close this dialog.",
			
			Vec3f
			(
				0						,
				view_area.y * 0.25f		,
				- 500
			),
			
			m_camera->GetViewProjectionMatrix()
		);	
	}
	
	// Enable z testing:
	
	game_core->GetDisplay()->GetDevice()->SetRenderState( D3DRS_ZENABLE , 1 );		
}

//=====================================================================================================================
/// @brief		Draws the background for all the menus
/// @pre		Must have valid resources
/// @pre		Game must exist
/// @pre		Game must have a primitives renderer
//=====================================================================================================================

void GameMenus::DrawBackground()
{
	// Make sure ok:
		
	ENSURE( m_valid_resources									, "Must have valid resources"				)
	ENSURE( GameCore::GetSingleton()							, "Game must exist"							)
	ENSURE( GameCore::GetSingleton()->GetPrimitivesRenderer()	, "Game must have a primitives renderer"	)
	
	// Get the reference view area:
	
	Vec2f refa = m_camera->GetReferenceViewArea();
	
	// Get the view area:
	
	Vec2f cura = m_camera->GetViewArea();
	
	// Calculate how much of the background texture to show:
	
	float tx = cura.x / refa.x;
	float ty = cura.y / refa.y;
	
	// Half this 
	
	tx *= 0.5f;
	ty *= 0.5f;
	
	// Draw a quad to the screen for the background:
	
	GameCore::GetSingleton()->GetPrimitivesRenderer()->DrawTexturedQuad
	(
		Matrix4f::Identity()		,
		Vec3f(-1.0f,+1.0f,0.99f)	,	
		Vec2f(-tx,-ty)				,
		Vec3f(+1.0f,+1.0f,0.99f)	,	
		Vec2f(+tx,-ty)				,
		Vec3f(+1.0f,-1.0f,0.99f)	,	
		Vec2f(+tx,+ty)				,
		Vec3f(-1.0f,-1.0f,0.99f)	,	
		Vec2f(-tx,+ty)				,
		0xffffffff					,
		m_background_tex		
	);			
}

//=====================================================================================================================
/// @brief		Draws the game start menu
//=====================================================================================================================

void GameMenus::DrawStartMenu()
{
	// Make sure ok:
		
	ENSURE( m_valid_resources , "Must have valid resources"	)
	
	// Draw the two menu choices:
	
	m_font.DrawCentered
	(
		"Welcome to Room-Wars!\n"
		"Please select action:\n"
		" \n"
		"S - Dedicated server: Host game\n"
		"C - Client: Join game\n"
		" \n"
		"E - Exit game\n"
		" \n"
		"Press a key to select." ,
		Vec3f(0.0f,200.0f,-500.0f)		,
		m_camera->GetViewProjectionMatrix()
	);
}

//=====================================================================================================================
/// @brief		Draws the host name screen
/// @pre		Must have valid resources
//=====================================================================================================================

void GameMenus::DrawHostNameMenu()
{
	// Make sure ok:
		
	ENSURE( m_valid_resources , "Must have valid resources"	)
	
	// Draw the prompt:
	
	m_font.DrawCentered
	(
		"Enter host/machine name or IP.\n"
		"Enter no name to abort:\n",
		Vec3f(0.0f,200.0f,-500.0f)		,
		m_camera->GetViewProjectionMatrix()
	);
	
	// Draw the current host name:
	
	m_font.DrawCentered
	(
		m_host_name + "_" ,
		Vec3f(0.0f,0.0f,-500.0f)		,
		m_camera->GetViewProjectionMatrix()
	);	
}

//=====================================================================================================================
/// @brief		Draws the server port screen
/// @pre		Must have valid resources
//=====================================================================================================================

void GameMenus::DrawServerPortMenu()
{
	// Make sure ok:
		
	ENSURE( m_valid_resources , "Must have valid resources"	)

	// Draw the menu choice:
	
	m_font.DrawCentered
	(
		"Enter server/host port number.\n"
		"Enter no port to abort:\n",
		Vec3f(0.0f,200.0f,-500.0f) ,
		m_camera->GetViewProjectionMatrix()
	);
	
	// Draw the current server port string:
	
	m_font.DrawCentered
	(
		m_server_port_string + "_" ,
		Vec3f(0.0f,0.0f,-500.0f)		,
		m_camera->GetViewProjectionMatrix()
	);	
}

//=====================================================================================================================
/// @brief		Draws the client port screen
/// @pre		Must have valid resources
//=====================================================================================================================

void GameMenus::DrawClientPortMenu()
{
	// Make sure ok:
		
	ENSURE( m_valid_resources , "Must have valid resources"	)

	// Draw the menu choice:
	
	m_font.DrawCentered
	(
		"Enter port number of server/host.\n"
		"Enter no port to abort:\n",
		Vec3f(0.0f,200.0f,-500.0f) ,
		m_camera->GetViewProjectionMatrix()
	);
	
	// Draw the current server port string:
	
	m_font.DrawCentered
	(
		m_server_port_string + "_" ,
		Vec3f(0.0f,0.0f,-500.0f)		,
		m_camera->GetViewProjectionMatrix()
	);	
}

//=====================================================================================================================
/// @brief		Draws the connecting screen
/// @pre		Must have valid resources
//=====================================================================================================================

void GameMenus::DrawConnectingMenu()
{
	// Make sure ok:
		
	ENSURE( m_valid_resources , "Must have valid resources"	)
	
	// Draw the menu choice:
	
	m_font.DrawCentered
	(
		"Awaiting host connection...\n"
		"Please select action:\n"
		" \n"
		"M - Back to main\n"
		" \n"
		"Press a key to select." ,
		Vec3f(0.0f,200.0f,-500.0f)		,
		m_camera->GetViewProjectionMatrix()
	);
}

//=====================================================================================================================
/// @brief		Draws the connection lost screen
/// @pre		Must have valid resources
//=====================================================================================================================

void GameMenus::DrawConnectionLost()
{
	// Make sure ok:
		
	ENSURE( m_valid_resources , "Must have valid resources"	)

	// Draw the menu choice:
	
	m_font.DrawCentered
	(
		"Connection timeout!\n"
		"Unable to connect to server.\n"
		"Please select action:\n"
		" \n"
		"M - Back to main\n"
		" \n"
		"Press a key to select." ,
		Vec3f(0.0f,200.0f,-500.0f)		,
		m_camera->GetViewProjectionMatrix()
	);
}

//=====================================================================================================================
/// @brief		Draws the connection refused screen
/// @pre		Must have valid resources
//=====================================================================================================================

void GameMenus::DrawConnectionRefused()
{
	// Make sure ok:
		
	ENSURE( m_valid_resources , "Must have valid resources"	)

	// Draw the menu choice:
	
	m_font.DrawCentered
	(
		"Connection refused by the server!\n"
		"Please select action:\n"
		" \n"
		"M - Back to main\n"
		" \n"
		"Press a key to select." ,
		Vec3f(0.0f,200.0f,-500.0f)		,
		m_camera->GetViewProjectionMatrix()
	);
}

//=====================================================================================================================
/// @brief		Draws the invalid host name screen
/// @pre		Must have valid resources
//=====================================================================================================================

void GameMenus::DrawInvalidHostName()
{
	// Make sure ok:
		
	ENSURE( m_valid_resources , "Must have valid resources"	)

	// Draw the menu choice:
	
	m_font.DrawCentered
	(
		"Invalid host name and/or port!\n"
		"No game server found."
		"Please select action:\n"
		" \n"
		"M - Back to main\n"
		" \n"
		"Press a key to select." ,
		Vec3f(0.0f,200.0f,-500.0f)		,
		m_camera->GetViewProjectionMatrix()
	);
}

//=====================================================================================================================
/// @brief		Draws the invalid server socket screen
/// @pre		Must have valid resources
//=====================================================================================================================

void GameMenus::DrawInvalidServerSocket()
{
	// Make sure ok:
		
	ENSURE( m_valid_resources , "Must have valid resources"	)

	// Draw the menu choice:
	
	m_font.DrawCentered
	(
		"Could not create server socket!\n"
		"The specified port may already be in use.\n"
		"A firewall may also be blocking the socket.\n"
		"Please select action:\n"
		" \n"
		"M - Back to main\n"
		" \n"
		"Press a key to select." ,
		Vec3f(0.0f,200.0f,-500.0f)		,
		m_camera->GetViewProjectionMatrix()
	);
}

//=====================================================================================================================
/// @brief		Draws the invalid port screen
/// @pre		Must have valid resources
//=====================================================================================================================

void GameMenus::DrawInvalidPort()
{
	// Make sure ok:
		
	ENSURE( m_valid_resources , "Must have valid resources"	)

	// Draw the menu choice:
	
	m_font.DrawCentered
	(
		"Invalid port number!\n"
		"Port must be a number between 0 and 65535.\n"
		"Please select action:\n"
		" \n"
		"M - Back to main\n"
		" \n"
		"Press a key to select." ,
		Vec3f(0.0f,200.0f,-500.0f)		,
		m_camera->GetViewProjectionMatrix()
	);
}

//=====================================================================================================================
/// @brief		Draws the server disconnected screen
//=====================================================================================================================

void GameMenus::DrawServerDisconnected()
{
	// Make sure ok:
		
	ENSURE( m_valid_resources , "Must have valid resources"	)

	// Draw the menu choice:
	
	m_font.DrawCentered
	(
		"Server disconnected.\n"
		"Please select action:\n"
		" \n"
		"M - Back to main\n"
		" \n"
		"Press a key to select." ,
		Vec3f(0.0f,200.0f,-500.0f)		,
		m_camera->GetViewProjectionMatrix()
	);
}

//=====================================================================================================================
/// @brief		Draws the in game hud for the client
/// @pre		GameCore must exist
/// @pre		GameCore must have a session object
/// @pre		GameCore must have an object manager
/// @pre		Must have valid resources
/// @pre		Game must have a primitives renderer
//=====================================================================================================================

void GameMenus::DrawHud()
{
	// Make sure ok
	
	ENSURE( GameCore::GetSingleton()							, "GameCore must exist"						)
	ENSURE( GameCore::GetSingleton()->GetSession()				, "GameCore must have a session object"		)
	ENSURE( GameCore::GetSingleton()->GetObjectManager()		, "GameCore must have an object manager"	)
	ENSURE( m_valid_resources									, "Must have valid resources"				)
	ENSURE( GameCore::GetSingleton()->GetPrimitivesRenderer()	, "Game must have a primitives renderer"	)
	
	// Get the game core object:
	
	GameCore * game_core = GameCore::GetSingleton();
	
	// Get the game session object:
	
	GameSession * session = game_core->GetSession();

	// Only if we are connected and are a client:
	
	if ( session->IsConnected() && session->IsClient() )
	{
		// Get the view area:
		
		Vec2f cura = m_camera->GetViewArea();	
		
		// Size of the hud bar in normalised device coordinates:
		
		const float SIZE = 0.125f;
		
		// Disable z testing:
		
		game_core->GetDisplay()->GetDevice()->SetRenderState( D3DRS_ZENABLE , 0 );
		
		// Draw a quad to the screen for the background:
		
		GameCore::GetSingleton()->GetPrimitivesRenderer()->DrawTexturedQuad
		(
			Matrix4f::Identity()				,
			Vec3f( - 1 , + 1 , 0.5f )			,	
			Vec2f(0,0)							,
			Vec3f( + 1 , + 1 , 0.5f )			,
			Vec2f(1,0)							,
			Vec3f( + 1 , + 1 - SIZE , 0.5f )	,
			Vec2f(1,1)							,
			Vec3f( - 1 , + 1 - SIZE , 0.5f )	,
			Vec2f(0,1)							,
			0xffffffff							,
			m_hud_bar_tex
		);
		
		// Save player health and ammo here:
		
		int health = 0; int ammo = 0;
		
		// Try and get the player:
		
		{
			// See if we have a control object:
			
			if ( session->GetControlObject() )
			{
				// Cast to a player:
				
				GamePlayer * player = dynamic_cast<GamePlayer*>(session->GetControlObject());
				
				// See if thats ok:
				
				if ( player )
				{
					// Save the health and ammo:
					
					ammo = player->GetAmmo();
					
					// Do this:
					
					if ( player->GetHealth() < 1 )
					{
						if ( health != 0 )
						{
							health = 1;
						}
						else
						{
							health = 0;
						}
					}
					else
					{
						health = int( Float::Round(player->GetHealth(),0) );
					}					
				}
			}		
		}
		
		// Buffer for printing:
		
		char buffer[1024];
		
		// Draw the player's health:
		
		sprintf_s(buffer,1024,"Health: %i",health);
		
		// Draw:
		
		m_font.Draw(buffer,Vec3f( - cura.x * 0.5f + 20 , + cura.y * 0.5f , -500 ),m_camera->GetViewProjectionMatrix());		
				
		// Draw the player's ammo:
		
		sprintf_s(buffer,1024,"Ammo: %i",ammo);
		
		// Draw:
		
		m_font.Draw(buffer,Vec3f( + cura.x * 0.5f - 20 - m_font.GetSize(buffer).x , + cura.y * 0.5f , -500 ),m_camera->GetViewProjectionMatrix());
		
		// Enable z testing:
		
		game_core->GetDisplay()->GetDevice()->SetRenderState( D3DRS_ZENABLE , 1 );
	}
}

//=====================================================================================================================
/// @brief		Called when a character is typed into the keyboard
/// @param		c - character that was typed
//=====================================================================================================================

void GameMenus::OnKeyboardTyped( char c )
{
	// See which menu we are in:
	
	switch ( GetMenu() )
	{
		// Client is entering host name:
		
		case MENU_HOST_NAME:
				
			// See if backspace:
			
			if ( c == '\b' )
			{
				// Remove one char from the host name:
				
				if ( m_host_name.size() > 0 )
				{
					m_host_name = m_host_name.substr(0,m_host_name.size()-1);
				}
			}
			else
			{
				// Add one char to the host name
				
				m_host_name += c;
			}			
		
		break;
		
		// Server is entering port number to use
		
		case MENU_CLIENT_PORT:
		case MENU_SERVER_PORT:
		
			// See if backspace:
			
			if ( c == '\b' )
			{
				// Remove one char from the host name:
				
				if ( m_server_port_string.size() > 0 )
				{
					m_server_port_string = m_server_port_string.substr(0,m_server_port_string.size()-1);
				}
			}
			else
			{
				// Add one char to the host name
				
				m_server_port_string += c;
			}		
		
		break;
	}
}
