#!/usr/bin/python
# -*- coding:utf-8 -*-
# definition des objets items, foods, snake, player
# initialisation des objets

import random
import my_pygame_wrapper
from level import *

########## Items ##########
class Items(object) :
    def __init__(self, coord_list, image):
        self.coord_list = coord_list
        self.image = image
    def display(self):
        for coord in self.coord_list:
            my_pygame_wrapper.display_square(self.image, coord)
    def lay(self, coord):
        return coord in self.coord_list
########## end Items ##########

########## Wall ##########
class Wall(Items) :
    def __init__(self, coord_list):
        Items.__init__(self, coord_list, my_pygame_wrapper.wall_image)
########## end Wall ##########
        
########## Foods ##########
class Foods(Items) :
    def __init__(self, delay, waiting, alter, image):
        self.coord_list = []
        self.delay = delay
        self.waiting = list(waiting)
        self.alter_player = alter
        self.image = image

    def remove(self, coord):
        self.coord_list.remove(coord)

    def add(self, forbidden):
        self.coord_list.append(self.choose_new_place(forbidden))
    
    def choose_new_place(self, forbidden):
        empty = False
        while not empty:
            # prendre une case du plateau au hasard
            coord = (random.choice (range (1, current_level.GRID_SIZE[0])), random.choice (range (1,current_level.GRID_SIZE[1])))
            # tester si elle est vide
            empty = not coord in forbidden + self.coord_list
        return coord

    # supprime le food et insere un element dans waiting
    def eaten(self, player, coord):
        self.remove(coord)
        self.waiting.append(self.delay)

    def alter_player(self, player):
        """ defini dans les sous-classes
        """
        pass

    # decremente le delai d'attente avant apparition
    # ajoute un food si necessaire (delay == 0)
    def step_forward(self, non_free_squares):
        # traiter les food en attente
        i = 0
        while i < len(self.waiting):
            if self.waiting[i] == 0:
                self.waiting.pop(i)
                self.add(non_free_squares)
            else:
                self.waiting[i] -= 1
                i += 1

class Cherry1(Foods):
    def __init__(self, delay, waiting, alter):
        Foods.__init__(self, delay, waiting, alter, my_pygame_wrapper.food_simple_image)

class Cherry2(Foods):
    def __init__(self, delay, waiting, alter):
        Foods.__init__(self, delay, waiting, alter, my_pygame_wrapper.food_double_image)

class Cherry3(Foods):
    def __init__(self, delay, waiting, alter):
        Foods.__init__(self, delay, waiting, alter, my_pygame_wrapper.food_triple_image)

class Cherryminus(Foods):
    def __init__(self, delay, waiting, alter):
        Foods.__init__(self, delay, waiting, alter, my_pygame_wrapper.food_rotten_image)

class Heart(Foods):
    def __init__(self, delay, waiting, alter):
        Foods.__init__(self, delay, waiting, alter, my_pygame_wrapper.food_heart_image)

class Egg(Foods):
    def __init__(self, delay, waiting, alter):
        Foods.__init__(self, delay, waiting, alter, my_pygame_wrapper.food_egg_image)

########## end Foods ##########

########## snake ##########
class Snake(object) :    
    def __init__(self, SNAKE_CONFIG_INIT, SNAKE_PARA):
        self.coord_list, self.image_list, self.length, self.old_direc, self.direc = SNAKE_CONFIG_INIT
        self.coord_list_init, self.image_list_init, self.length_init, self.old_direc_init, self.direc_init = SNAKE_CONFIG_INIT
        self.length_min, self.length_max = SNAKE_PARA

    def reinitialise(self):
        self.coord_list, self.image_list, self.length, self.old_direc, self.direc = \
                         self.coord_list_init, self.image_list_init, self.length_init, self.old_direc_init, self.direc_init
        
    #################################################
    # methodes pour modifier proporement le serpent #
    #################################################

    def alter_length(self, length=1):
        """
        length can be negative        
        """
        self.length += length
        if self.length > self.length_max:
            self.length = self.length_max
        elif self.length < self.length_min:
            self.length = self.length_min

    # ne marche pas du tout
    def reverse(self):
        """
        change le sens du serpent : la tete a la place de la queue
        """
        self.coord_list.reverse()
        self.image_list.reverse()
        # calcule des directions
        x0, y0 = self.coord_list[0]
        x1, y1 = self.coord_list[1]
        if x0-x1 == 1:
            self.direc = self.old_direc = "E"
        elif x0-x1 == -1:
            self.direc = self.old_direc = "W"
        elif y0-y1 == 1:
            self.direc = self.old_direc = "S"
        else:
            self.direc = self.old_direc = "N"

    ########################
    # methodes d'affichage #
    ########################

    def display(self, etat):
        if etat == "explosing":
            self.display_explosing()
        else:
            length = len(self.coord_list)
            self.display_head(0)
            for i in range(1,length-1):
                self.display_body(i)
            self.display_queue(length-1)

    def display_explosing(self):
        image = my_pygame_wrapper.snake_explosion
        for ind in range(len(self.coord_list)):
            my_pygame_wrapper.display_square(image, self.coord_list[ind])
            
    def display_head(self, ind):
        if self.image_list[ind] == "N":
            image = my_pygame_wrapper.snake_tete_N_image
        elif self.image_list[ind] == "E":
            image = my_pygame_wrapper.snake_tete_E_image
        elif self.image_list[ind] == "S":
            image = my_pygame_wrapper.snake_tete_S_image
        else:
            image = my_pygame_wrapper.snake_tete_W_image
        my_pygame_wrapper.display_square(image, self.coord_list[ind])

    def display_queue(self, ind):
        if self.image_list[ind] == "N":
            image = my_pygame_wrapper.snake_queue_N_image
        elif self.image_list[ind] == "E":
            image = my_pygame_wrapper.snake_queue_E_image
        elif self.image_list[ind] == "S":
            image = my_pygame_wrapper.snake_queue_S_image
        else:
            image = my_pygame_wrapper.snake_queue_W_image
        my_pygame_wrapper.display_square(image, self.coord_list[ind])

    def display_body(self, ind):
        image_symb = self.image_list[ind]
        if image_symb == "NS" or image_symb == "SN":
            image = my_pygame_wrapper.snake_NS_image
        elif image_symb == "EW" or image_symb == "WE":
            image = my_pygame_wrapper.snake_EW_image
        elif image_symb == "NE" or image_symb == "EN":
            image = my_pygame_wrapper.snake_NE_image
        elif image_symb == "NW" or image_symb == "WN":
            image = my_pygame_wrapper.snake_NW_image
        elif image_symb == "SE" or image_symb == "ES":
            image = my_pygame_wrapper.snake_SE_image
        elif image_symb == "SW" or image_symb == "WS":
            image = my_pygame_wrapper.snake_SW_image
        my_pygame_wrapper.display_square(image, self.coord_list[ind])

    #####################
    # methodes diverses #
    #####################

    def change_direc(self, direc):
        if (self.old_direc, direc) in [("N", "S"), ("S", "N"), ("E", "W"), ("W", "E")]:
            return False
        else:
            self.direc = direc
            return True

    def lay(self, coord):
        """
        retourne vrai ssi le serpent occupe la case coord au prochain step
        """
        # on va grandir
        if self.length > len(self.coord_list):
            return coord in self.coord_list
        # on ne grandit pas
        else:
            return coord in self.coord_list[:-1]
        # cas particulier si on retrecit ?

    def next_head(self):
        direction = self.direc
        x, y = self.coord_list[0]
        if direction == "E":
            new_head = (x+1, y)
        elif direction == "W":
            new_head = (x-1, y)
        elif direction == "N":
            new_head = (x, y-1)
        elif direction == "S":
            new_head = (x, y+1)
        return new_head
        
    def move(self, new_head):
        direction = self.direc

        # ajouter la nouvelle tete
        self.coord_list = [new_head] + self.coord_list

        # modifier l'image de l'ancienne tete
        dir_old_head = self.image_list[0]
        if dir_old_head == "N":
            self.image_list[0] = direction+"S"    
        elif dir_old_head == "E":
            self.image_list[0] = direction+"W"    
        elif dir_old_head == "S":
            self.image_list[0] = direction+"N"
        elif dir_old_head == "W":
            self.image_list[0] = direction+"E"    
            
        # ajouter l'image de la nouvelle tete
        self.image_list = [direction] + self.image_list
        
        # retirer la queue si le serpent doit conserver sa taille
        if len(self.coord_list) - 1 == self.length :
            self.coord_list = self.coord_list[:-1]
            # retirer l'image de l'ancienne queue
            self.image_list = self.image_list[:-1]
            # modifier l'image de la nouvelle queue
            new_queue = self.coord_list[-1]
            next_queue = self.coord_list[-2]
            depl = (new_queue[0]-next_queue[0], new_queue[1]-next_queue[1])
            if depl[0] == 1:
                self.image_list[-1] = "W"
            elif depl[0] == -1:
                self.image_list[-1] = "E"
            elif depl[1] == 1:
                self.image_list[-1] = "N"
            else:
                self.image_list[-1] = "S"
                
        # retirer 2 carres si le serpent doit retrecir
        elif len(self.coord_list) - 1 > self.length :
            self.coord_list = self.coord_list[:-2]        
            # retirer les images de l'ancienne queue
            self.image_list = self.image_list[:-2]
            # modifier l'image de la nouvelle queue
            new_queue = self.coord_list[-1]
            next_queue = self.coord_list[-2]
            depl = (new_queue[0]-next_queue[0], new_queue[1]-next_queue[1])
            if depl[0] == 1:
                self.image_list[-1] = "W"
            elif depl[0] == -1:
                self.image_list[-1] = "E"
            elif depl[1] == 1:
                self.image_list[-1] = "N"
            else:
                self.image_list[-1] = "S"
                
        # maj ancienne direction
        self.old_direc = direction
        
########## end snake ##########

########## player ##########
class Player(object) :
    def __init__(self, SNAKE_CONFIG_INIT, SNAKE_PARA, PLAYER_CONFIG_INIT, PLAYER_PARA, pass_level, note):
        self.snake = Snake(SNAKE_CONFIG_INIT, SNAKE_PARA)
        self.energy, self.life = PLAYER_CONFIG_INIT
        self.energy_init = self.energy
        self.points = 0
        self.explosion = -1
        self.energy_max, self.life_max, self.duree_explosion = PLAYER_PARA
        self.pass_level = pass_level
        self.note = note

    ################################################
    # methodes pour modifier proporement le joueur #
    ################################################
    
    def alter_life(self, life=1):
        self.life += life
        if self.life > self.life_max:
            self.life = self.life_max

    def alter_energy(self, energy):
        self.energy += energy
        if self.energy > self.energy_max:
            self.energy = self.energy_max

    def alter_points(self, points):
        self.points += points

    ###################
    # autres methodes #
    ###################
    
    def next_head(self):
        if self.explosing():
            return (-1, -1)
        return self.snake.next_head()
        
    def eat(self, energy, life, points, length):
        # appliquer betement les modif
        self.energy += energy
        self.life += life
        self.points += points
        self.snake.grow(length)
    
    def move(self, new_head):
        # explosing
        if self.explosion >= 0:
            # fin explosion
            if self.explosion == 0:
                self.die()
            self.explosion = self.explosion - 1
        # marche normale
        else:
            self.snake.move(new_head)
            self.energy -= 1
            
    def asphixie(self):
        return self.energy <= 0

    # retourne vrai ssi il reste des vies
    def dead(self):
        return self.life < 0

    def explose(self):
        self.explosion = self.duree_explosion
        
    def explosing(self):
        return self.explosion >= 0

    def end_explosing(self):
        return self.explosion == 0
    
    # fait perdre une vie et reinitialise
    def die(self):
        if self.life < 0:
            return "dead"
        # il reste des vies, on recommence
        self.snake.reinitialise()
        self.life -= 1
        self.energy = self.energy_init
        return None
        
    def display(self):
        # afficher le serpent
        if self.explosing():
            self.snake.display("explosing")
        else:
            self.snake.display("normal")
        # afficher l'etat du joueur (energie, points, vies)
        my_pygame_wrapper.display_player_status(self.energy, self.points, self.life)

    def lay(self, coord):
        return self.snake.lay(coord)

##     def pass_level(self):
##         return current_level.player_pass_level(self)

##     def note(self):
##         return current_level.player_note(self)
        
########## end player ##########
