"""

Code pour les niveaux :

-1 : position du joueur
0  : case vide
1  : caisse
2  : croix
3  : mur

"""

import lvls as l

levels_save = l.levels_save
levels_no_cross = [[k2[:] for k2 in k1] for k1 in levels_save]
for k1 in levels_no_cross:
    for k2 in k1:
        for k3 in k2:
            if k3 == 2:
                k3 = 0
levels = [[k2[:] for k2 in k1] for k1 in levels_no_cross]
cur = 0
cross = [[[[k3,k2[k3] == 2] for k3 in range(len(k2))] for k2 in k1] for k1 in levels_save]

"""---------------------------------------------------------------------------------------------------------------------------------------------------"""

def gate():
    """Renvoie la grille du niveau actuel"""
    
    global cur
    
    if cur >= len(levels_save):
        cur = 0
    t = [len(k) for k in levels[cur]]
    if t.count(t[0]) == len(t):
        return levels[cur]
    else:
        return levels[0]

def gateC():
    """Renvoie la grille des croix du niveau actuel"""

    global cur
    
    if cur >= len(levels_save):
        cur = 0
    t = [len(k) for k in levels[cur]]
    
    return cross[cur]

def get_cur():
    """Renvoie la variable CUR, du niveau actuel"""
    
    global cur
    
    if cur > len(levels_save) - 1:
        cur = 0
    
    return cur

def get_levels():
    """Renvoie la grille des niveaux"""
    
    return levels

def get_gateC():
    """Renvoie la grille des croix"""

    return gateC

"""---------------------------------------------------------------------------------------------------------------------------------------------------"""

x1 = [levels[0].index(k) for k in levels[cur] if -1 in k][0]
x2 = [k.index(-1) for k in levels[cur] if -1 in k][0]

"""---------------------------------------------------------------------------------------------------------------------------------------------------"""

class event:
    """Permet de créer un faux EVENT de Tkinter pour éxecuter des tests dans la console"""
    
    def __init__(self,keycode):
        
        self.keycode = keycode

        return

class player:
    """Class d'un joueur"""

    ALL = []
    nb = 0

    def __init__(self,x=x1,y=x2):
        
        player.ALL.append(self)
        player.nb += 1
        
        self.x,self.y = x,y

        return

    def move(self,event):
        """Permet de bouger un joueur et, parfois, une caisse"""
        
        try:
            c_up = event.keycode == 38 and not (gate()[self.x][self.y-1] in [-1,3] or (gate()[self.x][self.y-1] == 1 and (gate()[self.x][self.y-2] in [-1,1,3] or self.y-2 < 0)) or self.y-1 < 0)
        except Exception:
            c_up = False
        try:
            c_do = event.keycode == 40 and not (gate()[self.x][self.y+1] in [-1,3] or (gate()[self.x][self.y+1] == 1 and gate()[self.x][self.y+2] in [-1,1,3]))
        except Exception:
            c_do = False
        try:
            c_ri = event.keycode == 39 and not (gate()[self.x+1][self.y] in [-1,3] or (gate()[self.x+1][self.y] == 1 and gate()[self.x+2][self.y] in [-1,1,3]))
        except Exception:
            c_ri = False
        try:
            c_le = event.keycode == 37 and not (gate()[self.x-1][self.y] in [-1,3] or (gate()[self.x-1][self.y] == 1 and (gate()[self.x-2][self.y] in [-1,1,3] or self.x-2 < 0))  or self.x-1 < 0)
        except Exception:
            c_le = False

        returned = [(c_up,c_do,c_ri,c_le),(-1,-1)]

        if c_up or c_do or c_ri or c_le:

            levels[cur][self.x][self.y] = 0

            if c_up:
                self.y -= 1
                if gate()[self.x][self.y] == 1:
                    levels[cur][self.x][self.y-1] = 1
                    returned[1] = (self.x,self.y-1)
                    e = cross[cur][self.x][self.y-1]
                    e[1] = not (self.y-1 in [k[0] for k in gateC()[self.x]])

            elif c_do:
                self.y += 1
                if gate()[self.x][self.y] == 1:
                    levels[cur][self.x][self.y+1] = 1
                    returned[1] = (self.x,self.y+1)
                    e = cross[cur][self.x][self.y+1]
                    e[1] = not (self.y+1 in [k[0] for k in gateC()[self.x]])

            elif c_ri:
                self.x += 1
                if gate()[self.x][self.y] == 1:
                    levels[cur][self.x+1][self.y] = 1
                    returned[1] = (self.x+1,self.y)
                    e = cross[cur][self.x+1][self.y]
                    e[1] = not (self.y in [k[0] for k in gateC()[self.x+1]])

            elif c_le:
                self.x -= 1
                if gate()[self.x][self.y] == 1:
                    levels[cur][self.x-1][self.y] = 1
                    returned[1] = (self.x-1,self.y)
                    e = cross[cur][self.x-1][self.y]
                    e[1] = not (self.y in [k[0] for k in gateC()[self.x-1]])

            if not gateC()[self.x][self.y][1] and levels_save[cur][self.x][self.y] == 2:
                cross[cur][self.x][self.y][1] = True
            
            levels[cur][self.x][self.y] = -1

        return returned

    def repos(self,x,y):
        """Actualise les coordonnées du joueur"""
        
        self.x,self.y = x,y

        return

    def repos_all(cls):
        """Actualise les coordonnées de tous les joueurs"""
        
        p = []
        for k1 in range(len(gate())):
            for k2 in range(len(gate()[k1])):
                if k2 == -1:
                    p.append((k1,k2))
        for k in ALL:
            tup = p.pop()
            k.repos(tup[0],tup[1])
        
        return

    repos_all = classmethod(repos_all)

"""---------------------------------------------------------------------------------------------------------------------------------------------------"""

def restart():
    """Fait le niveau actuel recommencer"""
    
    new_level(actu=False)
    #x1 = [levels[cur].index(k) for k in levels[cur] if -1 in k][0]
    #x2 = [k.index(-1) for k in levels[cur] if -1 in k][0]
    #for k in player.ALL:
    #    k.repos(x1,x2)

    return

"""---------------------------------------------------------------------------------------------------------------------------------------------------"""

def check_end(ins=False,want_ins=True):
    """
    Renvoie si le niveau est terminé
    ins : permet de directement passer au prochain niveau ; variable intérieure au programme
    want_ins : permet de gérer si le programme passe automatiquement au prochain niveau
    """
    
    if want_ins and not ins:
        if check_end(True,want_ins):
            new_level()
            player.repos_all()

    return sum([sum([k[1] for k in i]) for i in gateC()]) == 0

def new_level(actu=True):
    """Actualise cur"""
    
    global cur

    levels[cur] = [k[:] for k in levels_no_cross[cur]]
    cross[cur] = [[[k2,k1[k2] == 2] for k2 in range(len(k1))] for k1 in levels_save[cur]]
    for k in player.ALL:
        del k
    player.ALL = []
    if actu:
        cur += 1
        if cur > len(levels_save):
            cur = 0
    
    return
