class GameEngine(Client):
    """
    The main game client:
      The game engine sends GLUT events to a gamestate class that
      manages what is happening on the screen.  It also handles
      server communication.
    """

    def __init__(self):
	"""
	Initializes the game client
	"""
    
	# since our game client is a client...
	Client.__init__(self)

	self.setsMgr = SettingsManager()
	self.res = self.setsMgr.screenRes

	self._InitGLUT_()
	self._InitGL_()

	# Make a screen object - we want to make the first here
	#   so that we can ensure the size is set appropriately.
	#   All other objects using the screen-singleton will assume
	#   it is has already been sized and, thus, won't call setSize.
	self.screen = Screen()
	self.screen.setSize( self.res )

	# be the first entity to create the managers
	self.rsrcMgr = TextureManager()
	self.fontMgr = FontManager()

	self.connected = False
	self.serverOwner = False
	self.serverName = "default"

	# the gameworld is mostly undefined at this point
	self.gameWorld = GameWorld()
	
	# this variable denotes for certain game states whether
	#   the user 'start'-ed or 'join'-ed a server so they know
	#   which state to return to when the user pushes 'back'
	self.statePath = None
	# create the initial game state
	self.gState = TitleScreenState(self)
	#self.gState = EngineState(self)


    def _InitGLUT_(self):
	"""Initialize GLUT"""
	glutInit()
	#*# Create/Initialize the Window
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA)
	glutInitWindowPosition( 0,0 )
	glutInitWindowSize( self.res[0], self.res[1] )

	self.window = glutCreateWindow( "Breakin & Poppin" )

	#*# setup the event handlers
	glutDisplayFunc(self.renderFrame)
	glutIdleFunc(self.on_tick)
	#glutReshapeFunc(self.changeSize)
	# keyboard
	glutKeyboardFunc( self.on_key_press )
	glutKeyboardUpFunc( self.on_key_release )
	glutIgnoreKeyRepeat( 1 ) # !=0 disables key repeat callbacks
	glutSpecialFunc( self.on_specialkey_press )
	glutSpecialUpFunc( self.on_specialkey_release )
	glutMouseFunc( self.on_mouse )
	glutPassiveMotionFunc( self.on_mouse_motion )
	
	#glutFullScreen()


    def _InitGL_(self):
	"""Initialize GL"""
	# Set up the rendering environment

	# setup the orthographic projection (firstly)
	glMatrixMode( GL_MODELVIEW )
	glPushMatrix()
	glLoadIdentity()

	# Set up the orthographic projection
	glOrtho(0, self.res[0], 0, self.res[1], -1, 1)
	# invert the y axis, down is positive
	glScalef(1, -1, 1)
	# mover the origin from the bottom left corner
	# to the upper left corner
	glTranslatef(0, -self.res[1], 0)

	# turn off the lighting and depth testing
	glPushAttrib( GL_DEPTH_BUFFER_BIT | GL_LIGHTING_BIT )
	glDisable( GL_LIGHTING )
	glDisable( GL_DEPTH_TEST )
	glDisable( GL_DITHER )	

    def on_key_press(self, key, x, y):
	"""On key press"""
	if self.gState:
	    self.gState = self.gState.on_key_press(key, x, y)

    def on_key_release(self, key, x, y):
	"""On key release"""
	if self.gState:
	    self.gState = self.gState.on_key_release(key, x, y)
	
    def on_specialkey_press(self, key, x, y):
	"""On special key press"""
	# game state
	if self.gState:
	    self.gState = self.gState.on_key_press(key, x, y)

    def on_specialkey_release(self, key, x, y):
	"""On special key release"""
	# game state
	if self.gState:
	    self.gState = self.gState.on_key_release(key, x, y)	

    def on_mouse_motion(self, x, y):
	"""On mouse motion"""
	# game state 
	if self.gState:
	    self.gState = self.gState.on_mouse_motion(x, y)

    def on_mouse(self, button, state, x, y):
	"""On mouse press/release"""
	# game state
	if self.gState:
	    self.gState = self.gState.on_mouse(button, state, x, y)

    def on_update(self, elapsed):
	"""
	The function that updates every object's animation status (45ms)
	"""

	# update the game state
	if self.gState:
	    self.gState = self.gState.update(elapsed)

	# gameworld
	self.gameWorld.update(elapsed)

	# gamestate
	glutTimerFunc(50, self.on_update, 50)	

    def on_socket( self, elapsed):
	"""
	"""
	# call the base class version (returns the packet)
	packet = Client.on_socket(self, elapsed)

	if packet != None:
	    #print 'client - recv - got a packet'
	    self.readPacket( packet )	# the real meat of this
	else:
	    # Oh well, no packet for some reason
	    pass

	glutTimerFunc(20, self.on_socket, 20)
	
    ###
    def readPacket(self, packet):
	"""
	This interpets a packet sent by the server
	"""

	# This case is usually handled by the GameEngine side
	#   (But this class isn't supposed to know that. :P)
	if packet['type'] == 'update':
	    #print 'Client : Got an update : ', packet
	
	    if self.connected:

		if self.gState:
		    # let the game state handle some bih'ness
		    self.gState= self.gState.on_socket(packet)


		if self.gameWorld:
		    self.gameWorld.on_socket(packet)

		# if the level is different or non-existant, load it
		#if not self.gameWorld.getLevel() \
		#	    or (packet['level'] != self.gameWorld.getLevelName()):
		#	self.gameWorld.setLevelByName( packet['level'] )


	if packet['type'] == 'message':
	    #print 'Client : Got a message : ', packet

	    # Connection Reset by Peer
	    if 'CRbP' in packet:
		print 'Disconnected: The server connection is dead.'
		self.disconnect()

	    # The server is full
	    if 'ServerFull' in packet:
		print 'Disconnected: The server is full.'
		# this is just like getting CRbP for now
		#   but the response to the user should
		#   be different at some point.
		self.disconnect()

	    if 'CurrentLevel' in packet:
		#self.engine.gameWorld.setLevel( packet['CurrentLevel'] )
		print 'Current level is ', packet['CurrentLevel']
		self.gameWorld.setLevelByName(packet['CurrentLevel'])

	    if 'NextLevel' in packet:
		print 'Next Level is ', packet['NextLevel']
		
	    if 'GameStatus' in packet:
		self.gameWorld.stopGame()
		if packet['GameStatus'] == 'winner':
		    self.gState = LoserState(self)
		elif packet['GameStatus'] == 'loser':
		    self.gState = WinnerState(self)
		    
		
	    

    def on_tick(self):
	"""Timer event: on tick"""
	# kill the app if there is no state
	if not self.gState:
	    self.on_close()
	# render the scene
	glutPostRedisplay()


    def on_close(self):
	"""On close"""
        # leave the server
	self.disconnect()
	glutDestroyWindow(self.window)
	sys.exit()


    def renderFrame(self):
	"""The glut display function"""
	# clear the buffer
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

	# Draw the game world
	if self.gameWorld:
	    self.screen.drawThis( self.gameWorld )

	# Render if we have a state
	if self.gState:
	    # the state passes any objects the screen to be rendered
	    self.gState.renderFrame()

	# The screen draws all objects it has been passed
	self.screen.draw()

	# Dump the contents to the screen
	glutSwapBuffers()
class EngineState():

    def __init__(self, engine):
	"""
	The game determines what is happening on screen
	based on what state the GameEngine instance has.
	"""
	# the game engine that owns this state
	self.engine = engine # TRYING TO DEPRECATE
	self.screen = Screen()
	self.res = self.engine.setsMgr.screenRes
	res = self.res

	# get/load the font
	self.font = FontManager().loadFont( 'JohnDoe' )
	self.str_paused = UIText( "Paused", [res[0]*0.5, res[1]*0.5]
				, self.font, 35 )
	self.str_paused.setVisible(False)

	
	gameWorld = self.engine.gameWorld
	#gameWorld.setPlayerType( 'Cop' )
	gameWorld.setPlayerType( 'Robber' )
	#gameWorld.getPlayer().setName( "Alfonso" )

	# This is an optimization...
	# If using the Cop player type, use the smaller tiles
	if gameWorld.getPlayer().getType() == "Cop":
	    gameWorld.setLevelByName( 'Level1XS' )
	else:
	    gameWorld.setLevelByName( 'Level1L' )

	glutTimerFunc(50, self.engine.on_update, 50)

    def renderFrame(self):
	""" RenderFrame - Base Class """
	if not self.screen:
	    self.screen = Screen()

	self.screen.drawThis( self.str_paused )

	return self

    def on_key_press(self, key, x, y):
	"""
	On key press
	"""
	if key == '\x1b':
	    return None

	# for now, this means to "spawn a server"
	if key == 'x':
	    if system() == "Linux" or system() == "Macintosh":
		Popen( [r'/usr/bin/python/python'
		    ,os.path.join( self.engine.setsMgr.home_dir
				    , 'StartServer.py' )] )
	    elif system() == "Windows":
		Popen([r'C:\Python25\python.exe'
		    ,os.path.join( self.engine.setsMgr.home_dir
				    , 'StartServer.py' )])
	    else:
	    	print "you are on an unsupported platform for spawning a server"
	    # declare that this game instance is the server owner
	    self.engine.serverOwner = True
	    
	# for now, its "connect"
	elif key == 'c':
	    self.engine.connect()

	elif key == 'v':
	    self.engine.disconnect()

	elif key == 'g':
	    self.str_paused.toggleVisible()
	    self.engine.gameWorld.pause()

	return self

    def on_key_release(self, key, x, y):
	"""
	On key release
	"""
	return self

    def on_specialkey_press(self, key, x, y):
	"""
	On special key press
	"""
	return self

    def on_specialkey_release(self, key, x, y):
	"""
	On special key release
	"""
	return self

    def on_mouse_motion(self, x, y):
	"""
	On mouse motion
	"""
	self.engine.gameWorld.startGame()
	return self

    def on_mouse(self, button, state, x, y):
	"""
	On mouse
	"""
	return self

    def on_socket(self, packet):
	"""
	On socket
	"""
	self.gameTime = packet['time']
	return self

    def update(self, elapsed):
	"""
	switches the state based on 
	"""
	return self
class GameState(EngineState):

    def __init__(self, engine):
	"""
	The game determines what is happening on screen
	based on what state the GameEngine instance has.
	"""
	self.engine = engine
	self.res = self.engine.setsMgr.screenRes
	self.screen = None

	# get/load the font
	self.font = FontManager().loadFont( 'Basic' )
	self.str_paused = UIText( "Paused",
		[self.res[0]*0.5, self.res[1]*0.5],
		self.font, 0.05 )
	self.str_paused.setVisible(False)

	engine.gameWorld.setLevelByName( 'Level1L' )
	engine.gameWorld.gameTime = 0.0

	engine.gameWorld.startGame()
	#glutTimerFunc(300, self.print_game_world, 300)

    def print_game_world(self, elapsed):
	gW = self.engine.gameWorld
	tileSize = gW.level.getTileSize()
	peerPos = gW.peers.values()[0].pos
	print ''
	print '--- Gameworld ---'
	print 'Player = {', gW.player.playerName, ":", gW.player.pos, "}"
	print 'mapPixelPos = ', gW.player.pos[0] + gW.scrScroll[0]\
				, gW.player.pos[1] + gW.scrScroll[1]
	print 'mapTilePos = ', gW.player.pos[0] / tileSize[0],\
				gW.player.pos[1] / tileSize[1]
	print 'renderPos = ', gW.player.pos[0] - gW.scrScroll[0]\
			    , gW.player.pos[1] - gW.scrScroll[1]
	print '  ------ ------ '
	print 'Peers = {', gW.peers.values()[0].playerName, ":", peerPos, "}" 
	print 'mapTilePos = ', peerPos[0] / tileSize[0],\
				peerPos[1] / tileSize[1]
	print 'renderPos = ', peerPos[0] - gW.scrScroll[0]\
			    , peerPos[1] - gW.scrScroll[1]
	print '  ------ ------ '
	print 'TileSize = ', tileSize
	print ''
	glutTimerFunc(300, self.print_game_world, 300)

    def renderFrame(self):
	""" RenderFrame - Base Class """
	if not self.screen:
	    self.screen = Screen()

	scrSize = self.screen.getSize()
	#self.engine.gameWorld.positionPlayer( [scrSize[0],scrSize[1]] )

	self.screen.drawThis( self.str_paused )
	
	return self

    def on_key_press(self, key, x, y):
	"""
	On key press
	"""
	if key == chr(27):   # Escape
	    return ChoosePlayerState(self.engine)
	elif key == 'g':
	    self.str_paused.toggleVisible()
	    self.engine.gameWorld.pause()
	
	# controller
	self.engine.gameWorld.on_key_press(key, x, y)

	return self


    def on_key_release(self, key, x, y):
	"""On key release"""
	# controller	
	self.engine.gameWorld.on_key_release(key, x, y)
	return self


    def on_specialkey_press(self, key, x, y):
	"""On special key press"""
	# controller
	self.engine.gameWorld.on_specialkey_press(key, x, y)
	return self

    def on_specialkey_release(self, key, x, y):
	"""On special key release"""
	# controller
	self.engine.gameWorld.on_specialkey_release(key, x, y)
	return self

    def on_mouse_motion(self, x, y):
	"""On mouse motion"""
	# controller
	self.engine.gameWorld.on_mouse_motion(x, y)
	return self

    def on_mouse(self, button, state, x, y):
	"""On mouse press/release"""
	# controller
	self.engine.gameWorld.on_mouse(button, state, x, y)
	return self

    def update(self, elapsed):
	"""
	switches the state based on 
	"""
	if self.engine.gameWorld.gameStatus == "winner":
	    # Send a signal to the server that this player
	    #	seems to have won the game ( the server will
	    #	have to agree with our word )
	    
	    # Go to the appropriate engine-state screen
	    #self.engine.gameWorld = GameWorld()
	    print 'switching to winner state'
	    return WinnerState(self.engine)

	elif self.engine.gameWorld.gameStatus == "loser":
	    # Go to the appropriate engine-state screen
	    #self.engine.gameWorld = GameWorld()
	    return LoserState(self.engine)
	else:
	    return self
class WinnerState(EngineState):

    def __init__(self, engine):
        """
	
	"""
	self.engine = engine
	self.res = self.engine.setsMgr.screenRes
	res = self.res
	self.screen = None

	# announce that the game is over
	#engine.announceGameOver( 'winner' )
	self.engine.gameWorld.status = 'winner'
	self.engine.gameWorld.stopGame()

	self.font = FontManager().loadFont( 'Basic' )
	self.UI = {}
	self.UI['nice_work'] = UIText("Nice Work!"
		, pos=[res[0]*0.5, res[1]*0.3], font=self.font, scale=0.047)
	self.UI['nice_work'].center()

	self.UI['cop_wins'] = UIText("You Caught The Robber!"
		, pos=[res[0]*0.5, res[1]*0.5], font=self.font, scale=0.04)
	self.UI['cop_wins'].center()

	self.UI['robber_wins'] = UIText("You made it home safe!"
		, pos=[res[0]*0.5, res[1]*0.5], font=self.font, scale=0.04)
	self.UI['robber_wins'].center()

    	self.UI['press_esc'] = UIText("Press escape to continue"
		, pos=[res[0]*0.5, res[1]*0.75], font=self.font, scale=0.04)
	self.UI['press_esc'].center()

	self.titleBGImg = UIImage("black_bg.png"\
		, pos=[0,0], size=res)

    def renderFrame(self):
	""" RenderFrame - Base Class """
	
	if not self.screen:
	    self.screen = Screen()

	self.screen.drawThis( self.titleBGImg )
	self.screen.drawThis( self.UI['nice_work'] )

	if self.engine.gameWorld.getPlayerType() == "Robber":
	    self.screen.drawThis( self.UI['robber_wins'] )
	elif self.engine.gameWorld.getPlayerType() == "Cop":
	    self.screen.drawThis( self.UI['cop_wins'] )

	self.screen.drawThis( self.UI['press_esc'] )

	return self

    def on_key_press(self, key, x, y):
	"""
	On key press
	"""
	if key == chr(27):   # Escape
	    self.engine.disconnect()
	    return TitleScreenState(self.engine)
	else:
	    return self


    def on_mouse(self, button, state, x, y):
	"""
	On mouse press
	"""
	self.engine.disconnect()
	return TitleScreenState(self.engine)
class TitleScreenState(EngineState):

    def __init__(self, engine):
	"""
	The game determines what is happening on screen
	based on what state the GameEngine instance has.
	"""
	self.engine = engine

	self.screen = Screen()
	self.res = self.engine.setsMgr.screenRes
	res = self.res # saying 'self.res' was making lines too long. :P
	
	# get/load the font
	self.font = FontManager().loadFont( 'Basic' )

	# screen objects
	self.UI = {}
	self.UI['title'] = UIText("Breakin And Poppin"\
		, pos=[res[0]*.01,res[1]*.10], font=self.font, scale=0.05)
	self.UI['start_server'] = UIText("Start a Server"\
		, pos=[res[0]*0.5, res[1]*0.42], font=self.font, scale=0.04)
	self.UI['start_server'].center()
	self.UI['join_server'] = UIText("Join a Server"\
		, pos=[res[0]*0.5, res[1]*0.5], font=self.font, scale=0.04)
	self.UI['join_server'].center()
	self.UI['quit'] = UIText("Quit"\
		, pos=[res[0]*0.5, res[1]*0.58], font=self.font, scale=0.04)
	self.UI['quit'].center()
	self.titleBGImg = UIImage("TitleScreenBG.png"\
		, pos=[0,0], size=res)

	self.selected = 'start_server'

    def renderFrame(self):
	if not self.screen:
	    self.screen = Screen()

	self.screen.drawThis( self.titleBGImg )

	selectionBox = UIImage("box.png",
				pos=self.UI[self.selected].pos,
				size=[(self.res[0]*0.05)*10, self.res[1]*0.05])
	selectionBox.center()
	self.screen.drawThis( selectionBox )

	for uiObj in self.UI.values():
	    # draw the background image firstly
	    self.screen.drawThis( uiObj )

	return self

    def on_key_press(self, key, x, y):
	"""
	On key press
	"""

	if key == '\x1b':
	    return None

	elif key == chr(13):
	    if self.selected == "start_server":
		self.statePath = 'start'
		return CreateServerState(self.engine)
	    elif self.selected == "join_server":
		self.statePath = 'join'
		return JoinServerState(self.engine)
	    elif self.selected == "quit":
		return None

	elif key == 101:
	    if self.selected == "start_server":
		self.selected = "quit"
	    elif self.selected == "join_server":
		self.selected = "start_server"
	    elif self.selected == "quit":
		self.selected = "join_server"

	elif key == 103:
	    if self.selected == "start_server":
		self.selected = "join_server"
	    elif self.selected == "join_server":
		self.selected = "quit"
	    elif self.selected == "quit":
		self.selected = "start_server"

	return self


    def on_mouse_motion(self, x, y):
	"""
	On mouse motion
	"""
	# check the mouse pos against all the choices
	if self.UI['start_server'].CollidePoint( (x,y) ):
	    self.selected = "start_server"
	    
	elif self.UI['join_server'].CollidePoint( (x,y) ):
	    self.selected = "join_server"
	    
	elif self.UI['quit'].CollidePoint( (x,y) ):
	    self.selected = "quit"
    
	return self

    def on_mouse(self, button, state, x, y):
	"""
	On mouse release
	"""
	if button == GLUT_LEFT_BUTTON and state == GLUT_DOWN:
	    
	    # check the mouse pos against all the choices
	    if self.UI['start_server'].CollidePoint( (x,y) ):
		self.engine.statePath = 'start'
		return CreateServerState(self.engine)
		
	    if self.UI['join_server'].CollidePoint( (x,y) ):
		self.engine.statePath = 'join'
		return JoinServerState(self.engine)
		
	    if self.UI['quit'].CollidePoint( (x,y) ):
		return None

	return self