import pygame
from random import choice
from funciones import piton_mover, piton_comer, piton_crecer, aparece_comida, actualizar_puntaje, crear_obstaculo
from utilidades import *

# Se importan los parametros que modifican ciertos aspectos del juego.
from constantes import (
titulo_ventana,
fondo_pantalla, 
imagen_cabeza_personaje, 
imagen_cuerpo_personaje,
imagen_cola_personaje,
imagen_obstaculo,
imagen_gameover,
permitir_sonido,
melodia_principal,
sonido_de_comer,
alimentos,
pos_inicial,
dir_inicial,
velocidad,
mostrar_ultimos_movimientos,
)

# Se inicializan los modulos importados de Pygame.
pygame.init()

# Definicion de algunas constantes importantes.
negro = (0, 0, 0)
blanco = (255, 255, 255)

# Se crea la ventana de juego.
ventana = pygame.display.set_mode([800, 600])

# Se carga la imagen del fondo y se crea su superficie.
imagen = cargar_imagen(fondo_pantalla)
fondo = pygame.Surface(ventana.get_size())
fondo.blit(imagen, (0,0))

# Imagenes de la cabeza del personaje.
imagen_cabeza_personaje = cargar_imagen(imagen_cabeza_personaje)
imagen_cabeza_personaje = {
'N':imagen_cabeza_personaje,
'O':pygame.transform.rotate(imagen_cabeza_personaje, 90.0),
'S':pygame.transform.rotate(imagen_cabeza_personaje, 180.0),
'E':pygame.transform.rotate(imagen_cabeza_personaje, 270.0),
}

# Imagen de cada cuadro del cuerpo del personaje.
imagen_cuerpo_personaje = cargar_imagen(imagen_cuerpo_personaje)

# Imagenes de la cola del personaje.
imagen_cola_personaje = cargar_imagen(imagen_cola_personaje)
imagen_cola_personaje = {
'N':pygame.transform.rotate(imagen_cola_personaje, 90.0),
'O':pygame.transform.rotate(imagen_cola_personaje, 180.0),
'S':pygame.transform.rotate(imagen_cola_personaje, 270.0),
'E':imagen_cola_personaje}

# Imagenes de los objetos recolectables.
imagenes_alimentos = dict()
for comida in alimentos:
	nombre_imagen = alimentos[comida][0]
	imagenes_alimentos[comida] = cargar_imagen(nombre_imagen)

# Imagen de fin de juego.
imagen_gameover = cargar_imagen(imagen_gameover)

# Imagen de obstaculo.
imagen_obstaculo = cargar_imagen(imagen_obstaculo)

# Fuentes de escritura
fuente_de_texto = cargar_fuente("OCRAEXT.TTF", 20)

# Musica y sonidos.
melodia_principal = cargar_sonido(melodia_principal)
sonido_de_comer = cargar_sonido(sonido_de_comer)

# Se reproduce la melodia principal en un loop infinito.
if permitir_sonido:
	melodia_principal.play(-1)

# Se crea un reloj y se define la tasa de cuadros por segundo.
reloj = pygame.time.Clock()
FPS = 60

# Variables de juego.
activo = True						# Controla el loop principal.
piton = [pos_inicial]				# Lista que contiene los cuadros que componen al personaje.
tiempo_de_juego = 0.0				# Lleva cuenta del tiempo de juego en segundos.
direccion = dir_inicial				# Direccion inicial de movimiento del personaje. 
puntaje = 0							# Lleva cuenta del puntaje del jugador.
largo = 1							# Lleva cuenta del largo, en cuadros, del personaje.
movimientos = [dir_inicial]			# Lista de los movimientos que ha realizado la cabeza del personaje.

# Inicializacion de textos en pantalla.
texto_puntaje = fuente_de_texto.render("Puntaje: {0}".format(puntaje), True, negro)
texto_largo = fuente_de_texto.render("Largo: {0}".format(largo), True, negro)
texto_tiempo = fuente_de_texto.render("Tiempo: {0}".format(int(tiempo_de_juego)), True, negro)

# Configuracion del reloj de movimiento.
MOVIMIENTO = pygame.USEREVENT + 1
pygame.time.set_timer(MOVIMIENTO, int(200 / velocidad))

# Creacion de obstaculos.
obstaculo = crear_obstaculo()

# Primer objeto en pantalla.
comida = aparece_comida(alimentos, piton, obstaculo)

while activo:
	milisegundos = reloj.tick(FPS)					# Limita el programa a correr a FPS cuadros por segundo.
													# Se obtiene ademas el tiempo en milisegundos que hubo entre 
													# un llamado y otro al metodo tick() del reloj.
	tasa_fps = int(reloj.get_fps())					# Se obtiene la tasa de FPS a la cual esta corriendo el programa.
	tiempo_de_juego += milisegundos / 1000.			# Se aumenta el tiempo de juego.
	segundos = int(tiempo_de_juego)					# Se obtienen los segundos transcurridos.
	minutos = segundos / 60
	texto_tiempo = fuente_de_texto.render("Tiempo: {0}:{1:02d}".format(minutos, segundos % 60), True, negro)
	
	# Actualiza el titulo de la ventana con la informacion de la tasa de fps.
	pygame.display.set_caption(titulo_ventana + " | FPS:{0}".format(tasa_fps))
	
	# Manejo de eventos de pygame (incluidas las pulsaciones de teclas).
	for event in pygame.event.get():
		
		# Usuario cierra la ventana.
		if event.type == pygame.QUIT:
			activo = False
			
		# Usuario presiona una tecla.
		elif event.type == pygame.KEYDOWN:
					
			if event.key == pygame.K_ESCAPE:
				activo = False
			if event.key == pygame.K_UP:
				direccion = 'N'
			elif event.key == pygame.K_DOWN:
				direccion = 'S'
			elif event.key == pygame.K_LEFT:
				direccion = 'O'
			elif event.key == pygame.K_RIGHT:
				direccion = 'E'
		
		# Pulso de reloj para el movimiento del personaje.
		elif event.type == MOVIMIENTO:
			movimientos = actualizar_lista_movimientos(movimientos, direccion)
			piton = piton_mover(piton, movimientos, obstaculo)
	
	# Si personaje es False, el juego termina.
	if piton == False:
		activo = False
		break
	
	# Crecimiento de la serpiente.
	if piton_comer(piton, comida):
		if permitir_sonido:
			sonido_de_comer.play()
		piton = piton_crecer(piton, movimientos)
		puntaje = actualizar_puntaje(comida, alimentos, puntaje)
		comida = aparece_comida(alimentos, piton, obstaculo)
		largo += 1
		texto_puntaje = fuente_de_texto.render("Puntaje: {0}".format(puntaje), True, negro)
		texto_largo = fuente_de_texto.render("Largo: {0}".format(largo), True, negro)
		
	# Se limpia el fondo de pantalla.
	fondo.blit(imagen, (0,0))
	
	# Se dibuja el cuerpo del personaje sobre el fondo.
	for i in range(1, len(piton) - 1):
		fondo.blit(imagen_cuerpo_personaje, piton[i])
			
	# Se dibuja un objeto recolectable sobre el fondo.
	if comida != None:
		fondo.blit(imagenes_alimentos[comida[0]], comida[1])
	
	# Se dibuja la cola del personaje sobre el fondo.
	if largo > 1:
		fondo.blit(imagen_cola_personaje[movimientos[largo-2]], piton[-1])
	
	# Se dibuja la cabeza del personaje sobre el fondo.	
	fondo.blit(imagen_cabeza_personaje[movimientos[0]], piton[0])
	
	# En caso de haber obstaculos, se dibujan.
	if obstaculo != None:
		for posicion_obstaculo in obstaculo:
			fondo.blit(imagen_obstaculo, posicion_obstaculo)
			 
	# Se escriben las estadisticas del juego en pantalla.
	fondo.blit(texto_puntaje, (10,10))
	fondo.blit(texto_largo, (10,35))
	fondo.blit(texto_tiempo, (10, 60)) 
	
	# Si la funcionalidad esta activada, muestra los ultimos 10 movimientos realizados por la piton.
	if mostrar_ultimos_movimientos:
		texto_direcciones = fuente_de_texto.render(">" + "-".join(movimientos[:10]), True, negro)
		fondo.blit(texto_direcciones, (500, 50))
		
	# Se dibuja el fondo completo en la ventana de juego.
	ventana.blit(fondo, (0,0))
	
	# Se refresca la pantalla con los nuevos cambios.
	pygame.display.flip()

# Se detiene la melodia principal.
if permitir_sonido:
	melodia_principal.stop()

# Se muestra el mensaje de fin de juego.
ventana.blit(fondo, (0, 0))
ventana.blit(imagen_gameover, (0, 0))
pygame.display.flip()

# Esperando tecla para terminar el juego.
esperando_tecla = True

while esperando_tecla:
	for event in pygame.event.get():
		if event.type == pygame.QUIT:
			esperando_tecla = False
		elif event.type == pygame.KEYDOWN:
			esperando_tecla = False

# Se crea una imagen con la ultima jugada en el directorio de main.py.
pygame.image.save(fondo, "ultima_jugada.png")

# Se finalizan los modulos de pygame y termina el juego.
pygame.quit()
