import pygame
from pygame.locals import *
import globalvars
from game import *
import math
import sys
import text as ptxt


class GameInstance:
	""" Class for handelling pygame init() and other pygame modules"""

	def __init__(self,name,w,h):
		pygame.init()
		pygame.display.set_caption(name)
		pygame.display.set_icon(pygame.image.load("images/icon.png"))
		self.display = pygame.display.set_mode((w,h))
		self.fps     = pygame.time.Clock()
		self.background = pygame.image.load("images/testbg.png")
		self.gamestate = GameState() 
		


	def events(self):
		"""returns a list of pygame events"""
		return pygame.event.get()

	def quit(self):
		"""Closes the application"""
		globalvars.state = globalvars.STATE_KILL
		pygame.quit()
		sys.exit(0)


	def vistext(self,TextObj,txt,colour = False):
		"""Renders given text to screen using preferences stored in a Text object"""
		if not colour:
			surface = TextObj.font.render(str(txt),True,TextObj.colour,TextObj.background)
		else:
			surface = TextObj.font.render(str(txt),True,colour,TextObj.background)

		position         = surface.get_rect()
		position.topleft = TextObj.xy
		self.display.blit(surface,position)

	def vissurf(self,surface,xy):
		"""Renders the given pygame surface to the screen at given xy co-ordinate"""
		position         = surface.get_rect()
		position.topleft = xy
		self.display.blit(surface,position)

	def visbutton(self,button):
		"""Renders an interactive Button object"""
		if button.state == True:
			self.display.blit(button.surface,button.position)

	def update(self,speed):
		"""Updates screen"""
		self.fps.tick(speed)
		pygame.display.update()

	def showMenu(self):

		PlayButton = Button((497,349),globalvars.StdFont,30,globalvars.GREEN,"Play",globalvars.YELLOW,globalvars.CYAN)
		QuitButton = Button((497,429), globalvars.StdFont,30, globalvars.BLACK, "Quit", globalvars.BLUE, globalvars.CYAN)
		NameInput  = TextBox((100,100),globalvars.StdFont,30,globalvars.BLACK,globalvars.YELLOW)

		while True:
			self.display.fill((255, 255, 255))
			self.visbutton(QuitButton)
			self.visbutton(PlayButton)

			for event in self.events():
				if event.type == pygame.QUIT or QuitButton.check(event):
					self.quit()
					return 1
				if PlayButton.check(event):
					self.gamestate.setupPlayers(NameInput.input_string,7)
					return 2
				NameInput.check(event)

			NameInput.update()
			self.vissurf(NameInput.surface,NameInput.xy)
			self.update(globalvars.GameSpeed)
					
	def runGame(self):

		running = True
		self.gamestate.my_player.gameplaying = self.gamestate
		self.gamestate.startGame()
		playarea = PlayArea(self.gamestate.players, self)
		ExitButton = Button((30, 15), globalvars.StdFont, 30, globalvars.GREEN, "Quit", globalvars.YELLOW, globalvars.CYAN)
		StayButton = Button((630,700),globalvars.StdFont,30,globalvars.GREEN,"Stay",globalvars.YELLOW,globalvars.CYAN)
		DrawButton = Button((330,700),globalvars.StdFont,30,globalvars.GREEN,"Draw",globalvars.YELLOW,globalvars.CYAN)
		ResolveButton = Button((800,700),globalvars.StdFont,30,globalvars.GREEN,"Resolve",globalvars.YELLOW,globalvars.CYAN)
		ResolveButton.disable()

		while running and self.gamestate:
			if self.gamestate.isrunning:
				# Draw the screen and controls
				self.display.blit(self.background,(0,0))
				self.visbutton(DrawButton)
				self.visbutton(StayButton)
				self.visbutton(ResolveButton)
			
			self.visbutton(ExitButton)

			# check your players score
			if self.gamestate.my_player.playing:
				if self.gamestate.my_player.checkLoseCondition():
					self.gamestate.my_player.bust(self.gamestate)

			# correct options
			if not self.gamestate.my_player.playing:
				StayButton.disable()
				DrawButton.disable()
				ResolveButton.enable()

			#Draw the card areas and cards

			for loc in playarea.locs:
				coords = playarea.locs[loc]
				self.display.blit(globalvars.playerimg, coords)
			
			for area in playarea.cardareas:
				area.cardarea.render(self)

			if not self.gamestate.waitforplayer:
				self.gamestate.fire()

			# Player names
			y_offset = 110
			for player in self.gamestate.players:
				loc = (player.loc["x"], player.loc["y"] + y_offset)
				text = Text(loc, globalvars.StdFont,16,globalvars.WHITE)
				self.vistext(text, player.name)

			# Dealer
			loc = (self.gamestate.dealer.loc["x"], self.gamestate.dealer.loc["y"] + y_offset)
			text = Text(loc, globalvars.StdFont,16,globalvars.WHITE)
			self.vistext(text, self.gamestate.dealer.name + " the dealer")

			# player status
			y_offset = 50
			for player in self.gamestate.players:
				if player.isbust == True:
					loc = (player.loc["x"], player.loc["y"] - y_offset)
					text = Text(loc, globalvars.StdFont,16,globalvars.RED)
					self.vistext(text, "Bust")
				elif player.isstay == True:
					loc = (player.loc["x"], player.loc["y"] - y_offset)
					text = Text(loc, globalvars.StdFont,16,globalvars.ORANGE)
					self.vistext(text, "Stay")

			# Show gamelog
			log = self.gamestate.gamelog
			start = len(log) - 15
			if start < 0:
				start = 0
			x = 724
			y = 20
			for item in log[start:]:
				loc = (x,y)
				strings = ptxt.trimOnSpace(item, 55)
				line = 1
				for logline in strings:
					if line > 1:
						y = y + 14
						loc = (x + 20 , y)
					text = Text(loc, globalvars.StdFont,12,globalvars.WHITE)
					self.vistext(text, logline)
					line = line + 1
				y = y + 14

			self.update(globalvars.GameSpeed)


			# Event handling
			for event in self.events():
				if event.type == pygame.QUIT:
					self.quit()
					return 0 
				if DrawButton.check(event):
					self.gamestate.dealToPlayer(self.gamestate.my_player)
					self.gamestate.waitforplayer = False
				if StayButton.check(event):
					DrawButton.disable()
					self.gamestate.my_player.stay(self.gamestate)
					self.gamestate.waitforplayer = False
				if ResolveButton.check(event):
					# end game when all players done and all cards revealed
					if all([not player.playing for player in self.gamestate.players]):
						if not self.gamestate.getFaceDowns():
							return 2	
						else:
							for card in self.gamestate.getFaceDowns():
								card.setFaceUp()
					self.gamestate.waitforplayer = False
				if ExitButton.check(event):
					return 1

	def showPostgame(self):

		ExitButton = Button((30, 15), globalvars.StdFont, 30, globalvars.GREEN, "Quit", globalvars.YELLOW, globalvars.CYAN)
		NextButton = Button((800, 700), globalvars.StdFont, 30, globalvars.GREEN, "Next Hand", globalvars.YELLOW, globalvars.CYAN)
		self.gamestate.updateScore()

		while True:

			# Event handling
			for event in self.events():
				if event.type == pygame.QUIT:
					self.quit()
					return 0
				if ExitButton.check(event):
					return 1
				if NextButton.check(event):
					self.gamestate.resetGame()
					return 2


			self.display.fill((255, 255, 255))

			for count, player in enumerate([player for player in self.gamestate.players if not player.isdealer]):
				self.vistext(Text((400,30*count), globalvars.StdFont,16,globalvars.BLACK),"{0} scored {1}".format(player.name, player.score))
			self.visbutton(ExitButton)
			self.visbutton(NextButton)
			self.update(globalvars.GameSpeed)


class Text:
	"""Basic class for storing text values such as location font and colour"""
	
	def __init__(self,xy,font,size,colour,background = False):
		self.background = background
		self.xy         = xy
		self.colour     = colour
		self.font       = pygame.font.Font("fonts/" + font + ".ttf",size)
		
	

class Button(Text):
	"""Extrapolation on the Text class which facilitates user input"""

	def __init__(self,xy,font,size,colour,txt,background,hover):
		Text.__init__(self,xy,font,size,colour,background)
		self.hover            = hover
		self.txt              = txt
		self.state            = True
		self.surface          = self.font.render(str(self.txt),True,self.colour,self.background)
		self.position         = self.surface.get_rect()
		self.position.topleft = self.xy

	def disable(self):
		"""disable button display and input"""
		self.state = False

	def enable(self):
		"""enables button diplay and input"""
		self.state = True

	def check(self,event):
		"""Returns True for a mouse click on the button"""

		if self.state:

			if event.type == MOUSEBUTTONUP:
				if self.position.collidepoint(event.pos):
					return True
		          
			if event.type == MOUSEMOTION or event.type == MOUSEBUTTONDOWN:
				if self.position.collidepoint(event.pos):
					self.surface = self.font.render(str(self.txt),True,self.colour,self.hover)
				else:
					self.surface = self.font.render(str(self.txt),True,self.colour,self.background)

class PlayArea():
	def __init__(self, players,surface):
		# Calculate the correct distribution of players
		circle = 360
		angle = circle / len(players)
		print(len(players))
		radian = angle * 0.0174532925
		radangle = radian
		radius = 250 # Radius of the display circle
		Woffset = 58 # Width co-ord adjustment
		Hoffset = 57 # Height co-ord adjustment
		areadist = 0 # How far in is the card area rendered
		self.locs = {}
		self.cardareas = {}

		for player in players:
			x = (radius * math.cos(radangle)) + (globalvars.WindowWidth / 2) - Woffset
			y = (radius * math.sin(radangle)) + (globalvars.WindowHeight / 2) - Hoffset

			coords = (x, y)
			self.locs[player] = coords
			player.loc = {"x" : x, "y" : y}

			#Card areas
			x = ((radius - areadist) * math.cos(radangle)) + (globalvars.WindowWidth / 2) - Woffset - 60
			y = ((radius - areadist) * math.sin(radangle)) + (globalvars.WindowHeight / 2) - Hoffset

			cardarea = PlayerArea(player, {"x" : x,"y" : y})
			player.cardarea = cardarea
			self.cardareas[player] = cardarea

			radangle += radian


class PlayerArea():
	def __init__(self, player, loc):
		self.player = player
		self.loc = loc

	def render(self, game):
		if not self.player.isdealer:
			count = 1
			for card in self.player.getCards():
				img = card.img
				x = self.loc["x"] + (count * 30)
				y = self.loc["y"]
				cardloc = (x, y)
				if not card.faceup:
					img = globalvars.facedownimg
					
				game.vissurf(img, cardloc)
				count += 1

		return

class TextBox(Text):

	def __init__(self,xy,font,size,colour,background = False):
		Text.__init__(self,xy,font,size,colour,background)
		self.surface = pygame.Surface(xy)
		self.cursor_surface = pygame.Surface((int(size/20+1),size))
		self.cursor_surface.fill(globalvars.BLACK)
		self.cursor_visible = True 
		self.cursor_interval  = 100
		self.cursor_counter = 0
		self.input_string = "Your name here.."
		self.cursor_position = len(self.input_string)
		self.complete = False

	def check(self, event):
		if event.type == pygame.KEYDOWN and not self.complete:
			self.cursor_visible = True 

			if event.key == K_BACKSPACE: 
				self.input_string = self.input_string[:max(self.cursor_position - 1, 0)] + self.input_string[self.cursor_position:]
                # Subtract one from cursor_pos, but do not go below zero:
				self.cursor_position = max(self.cursor_position - 1, 0)

			elif event.key == K_DELETE:
				self.input_string = self.input_string[:self.cursor_position] + self.input_string[self.cursor_position + 1:]

			elif event.key == K_RETURN:
				self.complete = True

			elif event.key == K_RIGHT:
                # Add one to cursor_pos, but do not exceed len(input_string)
				self.cursor_position = min(self.cursor_position + 1, len(self.input_string))

			elif event.key == K_LEFT:
                # Subtract one from cursor_pos, but do not go below zero:
				self.cursor_position = max(self.cursor_position - 1, 0)

			elif event.key == K_END:
				self.cursor_position = len(self.input_string)

			elif event.key == K_HOME:
				self.cursor_position = 0

			else:
                # If no other key is pressed, add unicode of key to input_string
				self.input_string = self.input_string[:self.cursor_position] + event.unicode + self.input_string[self.cursor_position:]
				self.cursor_position += len(event.unicode) # Some are empty, e.g. K_UP

	def update(self):

		# Rerender text surface:
		self.surface = self.font.render(self.input_string, True, self.colour, self.background)

		if not self.complete:
	        # Update self.cursor_visible
			self.cursor_counter += 10
			if self.cursor_counter >= self.cursor_interval:
				self.cursor_counter %= self.cursor_interval
				self.cursor_visible = not self.cursor_visible

			if self.cursor_visible:
				self.cursor_y_pos = self.font.size(self.input_string[:self.cursor_position])[0]
				# Without this, the cursor is invisible when self.cursor_position > 0:
				if self.cursor_position > 0:
					self.cursor_y_pos -= self.cursor_surface.get_width()
				self.surface.blit(self.cursor_surface, (self.cursor_y_pos, 0))

