# spustit prikazen python game.py


from tkinter.messagebox import showerror
from tkinter import filedialog
from tkinter import *
import json


class Game:
    # inicializce hry

    def __init__(self, master):
        self.master = master
        self.openBtn = Button(
            master, text="Otevrit soubor", command=self.loadFile)
        self.openBtn.grid(row=0, column=0)
        self.pole = []
        self.start = None
        self.finish = None
        self.pos = None
        self.gameover = False
        self.safeMode = False
    # vyvori dialog na vybrani souboru a zkontroluje jestli byl soubor vybran

    def fileDialog(self):
        filename = filedialog.askopenfilename(initialdir="C:\\Users\\kurek\\OneDrive\\Dokumenty\\Python-DESKTOP-top\\soutez-ustredni\\porota\\json", title="Vyber soubor", filetypes=(
            ("json soubor", "*.json"), ("vsechny soubory", "*.*")))
        if filename == "":
            showerror("Otevreni souboru", "Soubor nenalezen")
            return False
        return filename
    # precteni souboru

    def readFile(self, filename):
        data = None
        try:
            f = open(filename, "r")
            data = json.load(f)
        except:
            showerror("Nacitani souboru", "Chyba pri nacitani souboru")
        return data

    def loadFile(self):
        filename = self.fileDialog()
        if filename is False:
            return
        data = self.readFile(filename)
        if data != None:
            self.data = data
            self.openBtn.destroy()
            self.gameLayout()
            self.loadData()
    # gui prvky pro samotnou hru

    def gameLayout(self):
        width = self.data["SIRKA"] * 35
        height = max(self.data["VYSKA"] * 35, 300)
        self.master.geometry(str(width+300) + "x" + str(height))
        self.canvas = Canvas(self.master, width=width, height=height)
        self.canvas.place(x=0, y=0)

        self.master.bind("<KeyPress>", self.keydown)

        self.energyText = StringVar()
        self.energyText.set("Energie: 0")
        self.energyLabel = Label(self.master, textvariable=self.energyText)
        self.energyLabel.place(x=width+10, y=10)

        Button(self.master, text="Restart",
               command=self.restart).place(x=width+10, y=40)

        Button(self.master, text="Safe mode",
               command=self.toggleSafe).place(x=width+10, y=70)

        self.safeLabelText = StringVar()
        Label(self.master, textvariable=self.safeLabelText).place(
            x=width+10, y=100)

        self.safeLabelText.set("Ocharana vypnuta")

        Button(self.master, text="Vyresit",
               command=self.solve).place(x=width+10, y=130)

        self.statLabelText = StringVar()
        Label(self.master, textvariable=self.statLabelText).place(
            x=width+10, y=160)

        Label(self.master, text="Pohyb je pomoci sipek\n"
                                + "Pokud hrac stoupne na zed nebo bombu, \n"
                                + "ubere se tolik energie, kolik je na poli napsane, \n"
                                + "pokud tam neni cislo tak to znamena nekonecno \n"
                                + "Pokud hrac stoupne na banan, energie se pricte \n"
                                + "Cilem hry je se dostat do cile (vlajka)", justify=LEFT).place(x=width+10, y=190)

        self.wallImg = [PhotoImage(file="wall32.png"),
                        PhotoImage(file="blackwall32.png")]
        self.finishImg = PhotoImage(file="finish32.png")
        self.foodImg = PhotoImage(file="banana32.png")
        self.bombImg = PhotoImage(file="bomb32.png")

    def toggleSafe(self):
        self.safeMode = not self.safeMode
        if self.safeMode:
            self.safeLabelText.set("Ochrana zapnuta")
        else:
            self.safeLabelText.set("Ocharana vypnuta")

    # ovladani
    def keydown(self, e):
        if self.gameover:
            return
        posx, posy = self.pos[0], self.pos[1]
        en_tmp = self.energy
        if e.keysym == "Up":
            if self.pos[1]-1 > 0:
                self.pos[1] -= 1
                self.energy -= 1
        elif e.keysym == "Down":
            if self.pos[1]+1 <= self.data["VYSKA"]:
                self.pos[1] += 1
                self.energy -= 1
        elif e.keysym == "Right":
            if self.pos[0]+1 <= self.data["SIRKA"]:
                self.pos[0] += 1
                self.energy -= 1
        elif e.keysym == "Left":
            if self.pos[0]-1 > 0:
                self.pos[0] -= 1
                self.energy -= 1
        if self.safeMode and not self.safe():
            self.pos[0], self.pos[1] = posx, posy
            self.energy = en_tmp
        self.updateEnergy()
        self.drawMap()
        self.rules()
    # pokud je dalsi tah safe(energie klesne pod 0) nebo ne

    def safe(self):
        curr = self.pole[self.pos[1]-1][self.pos[0]-1]
        if curr[0] == "B" or curr[0] == "Z":
            if curr[1] == None:
                return False
            else:
                if self.energy - curr[1] < 0:
                    return False
        return True

    def restart(self):
        self.pole = []
        self.loadData()
        self.gameover = False
        self.safeMode = False
        self.statLabelText.set("")
    # nacte mapu

    def loadMap(self):
        if len(self.data["PLAN"]) != self.data["VYSKA"]:
            showerror("Chyba dat", "data nejsou vporadku")
            return -1
        for vyska in range(self.data["VYSKA"]):
            self.pole.append([])
            row = self.data["PLAN"][vyska].split(",")
            if len(row) != self.data["SIRKA"]:
                showerror("Chyba dat", "data nejsou vporadku")
                return -1
            for sirka in range(self.data["SIRKA"]):
                tmp = [row[sirka], None]
                if len(row[sirka]) == 2:
                    tmp = [row[sirka][0], int(row[sirka][1])]
                self.pole[vyska].append(tmp)
        self.nprint()
    # overi jestli je to cislo

    def intVerify(self, var):
        try:
            return int(var)
        except:
            showerror("Jejda", "Nastala chyba")
            return None
    # nacte data

    def loadData(self):
        if self.data == None:
            return -1
        if self.loadMap() == -1:
            return -1
        self.start = (self.intVerify(
            self.data["START"]["X"]), self.intVerify(self.data["START"]["Y"]))
        self.pos = [self.intVerify(self.data["START"]["X"]), self.intVerify(
            self.data["START"]["Y"])]
        self.energy = self.intVerify(self.data["START"]["E"])
        self.updateEnergy()
        self.finish = (self.intVerify(
            self.data["CIL"]["X"]), self.intVerify(self.data["CIL"]["Y"]))
        self.drawMap()

    def nprint(self):
        for row in self.pole:
            print(row)
    # vzkresli mapu

    def drawMap(self):
        x, y = 0, 0
        #step = min(700 // self.data["SIRKA"], 700 // self.data["VYSKA"])
        step = 35
        for posy, row in enumerate(self.pole):
            x = 0
            for posx, col in enumerate(row):
                fillcolor = "white"
                if col[0] == "J":
                    fillcolor = "green"
                elif col[0] == "Z":
                    fillcolor = "black"
                elif col[0] == "B":
                    fillcolor = "red"
                self.canvas.create_rectangle(
                    x, y, x+step, y+step, fill=fillcolor, outline="black")
                if col[0] == "J":
                    self.canvas.create_image(
                        (x + x+step)/2, (y + y+step)/2, image=self.foodImg, anchor="center")
                elif col[0] == "Z":
                    self.canvas.create_image(
                        (x + x+step)/2, (y + y+step)/2, image=self.wallImg[0], anchor="center")
                elif col[0] == "B":
                    self.canvas.create_image(
                        (x + x+step)/2, (y + y+step)/2, image=self.bombImg, anchor="center")

                if col[1] != None:
                    text_pos = [((x + x+step)/2), ((y + y+step)/2)]
                    self.canvas.create_text(text_pos[0], text_pos[1], fill="white", font="Times 20 italic bold",
                                            text=col[1])

                if self.pos[0] == posx+1 and self.pos[1] == posy+1:
                    oval_x = ((x + x+step)/2) - 10
                    oval_y = ((y + y+step)/2) - 10
                    self.canvas.create_oval(
                        oval_x, oval_y, oval_x+20, oval_y+20, fill="blue", outline="black")
                if posx+1 == self.finish[0] and posy+1 == self.finish[1]:
                    self.canvas.create_image(
                        (x + x+step)/2, (y + y+step)/2, image=self.finishImg, anchor="center")
                x += step
            y += step

    def updateEnergy(self):
        self.energyText.set("Energie: " + str(self.energy))
    # zkontroluje pravidla

    def rules(self):
        curr = self.pole[self.pos[1]-1][self.pos[0]-1]
        if curr[0] == "J":
            self.energy += curr[1]
            curr[0] = "V"
            curr[1] = None
        elif curr[0] == "B":
            if curr[1] == None:
                self.energy = 0
            else:
                self.energy -= curr[1]
            curr[0] = "V"
            curr[1] = None
        elif curr[0] == "Z":
            if curr[1] == None:
                self.energy = 0
            else:
                self.energy -= curr[1]

        self.updateEnergy()
        if self.pos[0] == self.finish[0] and self.pos[1] == self.finish[1]:
            self.win()
            return
        if self.energy <= 0:
            self.gameOver()

    def gameOver(self):
        self.gameover = True
        self.statLabelText.set("Prohral jsi")

    def win(self):
        self.gameover = True
        self.statLabelText.set("Vyhral jsi")

    # rekurzivne projde vsechny mozne cesty, vraci None pokud nenasel cestu a energii pokud dorazi do cile
    def recursionSolve(self, pos, energy):
        # print(pos)
        if (pos[0] <= 0 or pos[0] > self.data["SIRKA"] or
                pos[1] <= 0 or pos[1] > self.data["VYSKA"]):
            return None
        curr = self.pole[pos[1]-1][pos[0]-1]
        if curr[0] == "Z" and curr[1] != None:
            energy -= curr[1]
        energy -= 1
        if pos[0] == self.finish[0] and pos[1] == self.finish[1]:
            return energy
        if energy <= 0:
            return None

        left = self.recursionSolve([pos[0]-1, pos[1]], energy)
        right = self.recursionSolve([pos[0]+1, pos[1]], energy)
        up = self.recursionSolve([pos[0], pos[1]-1], energy)
        down = self.recursionSolve([pos[0], pos[1]+1], energy)
        success = []
        if left != None:
            success.append(left)
        elif right != None:
            success.append(right)
        elif up != None:
            success.append(up)
        elif down != None:
            success.append(down)
        success.sort()
        if len(success) > 0:
            return success[-1]
        return None
    # nenajde primo cestu, jen energii v cili
    def solve(self):
        print(self.recursionSolve(self.pos, self.energy))  # energie v cily
        return


root = Tk()

game = Game(root)

root.mainloop()
