import tkinter
from tkinter import *
from PIL import ImageTk, Image

# initialization of variables
move = 0
direction = None
position = None
position2 = None
actual_player = 1
number_of_buttons = 0
max_num = 0
all_moves = []
player_move = []
width_playing_screen = 820
height_playing_screen = 530
analyse_is_small = False
is_clicked = False

# arrays of playing field
triangular_playing_field = [
    [0],
    [-1, 1],
    [-2, 0, 2],
    [-3, -1, 1, 3],
    [-4, -2, 0, 2, 4],
    [-5, -3, -1, 1, 3, 5],
    [-6, -4, -2, 0, 2, 4, 6],
    [-7, -5, -3, -1, 1, 3, 5, 7],
    [-8, -6, -4, -2, 0, 2, 4, 6, 8]
]

hexagonal_playing_field = [
    [-4, -2, 0, 2, 4],
    [-5, -3, -1, 1, 3, 5],
    [-6, -4, -2, 0, 2, 4, 6],
    [-7, -5, -3, -1, 1, 3, 5, 7],
    [-8, -6, -4, -2, 0, 2, 4, 6, 8],
    [-7, -5, -3, -1, 1, 3, 5, 7],
    [-6, -4, -2, 0, 2, 4, 6],
    [-5, -3, -1, 1, 3, 5],
    [-4, -2, 0, 2, 4],
]

square_playing_field = [
    [-3, -1, 1, 3],
    [-3, -1, 1, 3],
    [-3, -1, 1, 3],
    [-3, -1, 1, 3],
]


def playing_field(tk, canvas_out, game_type_out):  # create playing field / create buttons, background...
    global game_type, canvas, player_img, player_btn, max_num
    count = 0

    ws = init_canvas(game_type_out,canvas_out,tk)
    border, set_position = prepare_playing_field(game_type_out)
    bg_img, player_img, stone_img = prepare_img()

    background = Label(canvas, image=bg_img)
    background.place(x=0, y=0, relwidth=1, relheight=1)
    player_btn = tkinter.Button(canvas, image=player_img, command= change_player, borderwidth=0)
    player_btn.place(x=0, y=0)

    for i in range(len(border)):
        count=0
        for j in border[i]:
            globals()['button3'+str(count)+str(i)] = tkinter.Button(canvas, image=stone_img, command=lambda x=(count, i): click(x), borderwidth=0)
            globals()['button3'+str(count)+str(i)].place(x=width_playing_screen/2+(j*25), y=set_position+(55*i))
            count = count + 1

    ws.mainloop()


def prepare_playing_field(game_type_out):  # use game_type_out to set the parameters of the playing field
    global max_num
    if game_type_out == 'small':
        max_num = 16
        return square_playing_field, width_playing_screen/4.5
    elif game_type_out == 'medium':
        max_num = 45
        return triangular_playing_field, 30
    else:
        max_num = 61
        return hexagonal_playing_field, 30


def prepare_img():  # load images from file
    global win_banner1, win_banner2, info_img
    bg_img = PhotoImage(file='images/bk2.png')
    player_img = PhotoImage(file='images/next_player1.png')
    win_banner1 = PhotoImage(file='images/winner_1.png')
    win_banner2 = PhotoImage(file='images/winner_2.png')
    info_img = PhotoImage(file='images/info2.png')
    stone_img = Image.open("images/gula.png").resize((50,50), Image.ANTIALIAS)
    stone_img = ImageTk.PhotoImage(stone_img)
    return bg_img, player_img, stone_img


def init_canvas(game_type_out,canvas_out, tk):  # init canvas, tk and game_type variable
    global game_type, canvas
    game_type = game_type_out
    canvas = canvas_out
    ws = tk
    ws.title('Bulo : ' + game_type_out)
    canvas.config(width=width_playing_screen, height=height_playing_screen)
    return ws


def click(i):  # check clicked button / if pressed correctly it will delete
    global is_clicked
    x, y = i
    global position, move, direction
    if move == 0:
        set_position_move(x, y)
        delete_btn(x, y)
        is_clicked = True
    elif move == 1:
        check_1_move(x, y)
        is_clicked = True
    else:
        check_2_more_moves(x, y)
        is_clicked = True


def set_position_move(x, y):  # set position and move variables
    global position, move
    position = (x, y)
    move = move + 1


def check_1_move(x,y):  # check that the button is pressed correctly and can be deleted / only when is 1 move done
    global position,  direction
    x1, y1 = position
    if (x - x1) != 0 and (y - y1) == 0 and abs(x - x1) == 1:
        delete_btn(x, y)
        set_position_move(x, y)
        direction = (x - x1, None, 'x')
    elif (y - y1) != 0 and (x - x1) == 0 and abs(y - y1) == 1:
        delete_btn(x, y)
        set_position_move(x, y)
        direction = (None, y - y1, 'y')
    if game_type == 'medium' or game_type == 'big':
        if (y - y1) != 0 and (x - x1) != 0 and abs(y - y1) == 1 and abs(x - x1) == 1:
            delete_btn(x, y)
            set_position_move(x, y)
            direction = (x - x1, y - y1, 'xy')


def check_2_more_moves(x,y):  # check that the button is pressed correctly and can be deleted / only when are 2 and more moves done
    global position, direction
    direction1, direction2, coord_axis = direction
    x1, y1 = position
    if coord_axis == 'x':
        if (x - x1) == direction1 and (y - y1) == 0:
            delete_btn(x, y)
            set_position_move(x, y)

    elif coord_axis == 'y':
        if (x - x1) == 0 and (y - y1) == direction2:
            delete_btn(x, y)
            set_position_move(x, y)

    elif coord_axis == 'xy':
        if (x - x1) == direction1 and (y - y1) == direction2:
            delete_btn(x, y)
            set_position_move(x, y)


def change_player():  # change parameters when player end move
    global actual_player, is_clicked
    if is_clicked:
        is_clicked = False
        all_moves.append(player_move.copy())
        player_move.clear()

        if actual_player == 1:
            actual_player = 2
            set_change_player_param('images/next_player2.png', 670, 0)

        else:
            actual_player = 1
            set_change_player_param('images/next_player1.png', 0, 0)


def set_change_player_param(path, x, y):  # destroy player_change button, reset position, move, direction and set new button
    global position, move, direction, canvas, player_img, player_btn
    position, move, direction = 0, 0, 0
    player_btn.destroy()
    player_img = PhotoImage(file=path)
    player_btn = tkinter.Button(canvas, image=player_img, command=change_player, borderwidth=0)
    player_btn.place(x=x, y=y)


def delete_btn(x, y):  # delete button and check if someone win game
    global max_num, number_of_buttons, actual_player
    number_of_buttons = number_of_buttons+1
    player_move.append((x, y))
    globals()['button3' + str(x) + str(y)].destroy()
    if number_of_buttons == max_num:
        all_moves.append(player_move.copy())
        winner(actual_player)


def winner(looser_player):  # show win banner and delete player_btn
    global canvas, win_banner1, win_banner2
    if looser_player == 2:
        win_banner_btn = tkinter.Button(canvas, image=win_banner1, command=empty_func, borderwidth=0)
    else:
        win_banner_btn = tkinter.Button(canvas, image=win_banner2, command=empty_func, borderwidth=0)
    win_banner_btn.place(x=width_playing_screen/2 - 130, y=100)
    delete_player_btn_add_analysis_btn(win_banner_btn)


def delete_player_btn_add_analysis_btn(win_banner_btn):  # delete player_btn and create button for start tree analysis
    global player_btn, info_img, game_type
    player_btn.destroy()
    if game_type == 'small':
        tree_btn = tkinter.Button(canvas, image=info_img, command=lambda: tree_path(tree_btn, win_banner_btn), borderwidth=0)
        tree_btn.place(x=width_playing_screen/2, y=300)


def delete_tree_btn_and_win_banner(tree_btn, win_banner_btn):  # delete tree button and win banner
    tree_btn.destroy()
    win_banner_btn.destroy()


def tree_path(tree_btn, win_banner_btn):  # find win path for looser and show current path
    global items, pairs
    delete_tree_btn_and_win_banner(tree_btn, win_banner_btn)
    last_3_moves = all_moves[len(all_moves)-1]+all_moves[len(all_moves)-2]+all_moves[len(all_moves)-3]
    pairs, items = [], []

    if len(last_3_moves) % 2 == 0:
        if len(last_3_moves) == 6 or len(last_3_moves) == 8:
            tree_path_equals_to_8_6(last_3_moves)

        if len(last_3_moves) == 12:
            tree_path_equals_to_12(last_3_moves)

        if len(last_3_moves) < 5:
            for i in last_3_moves:
                items.append(i)

    else:
        res = find_pairs(last_3_moves)
        if len(last_3_moves) == 3 or len(last_3_moves) == 5:
            tree_path_equals_to_3_5(res,last_3_moves)

        if len(last_3_moves) == 7:
            tree_path_equals_to_7(res, last_3_moves)

        if len(last_3_moves) == 9:
            tree_path_equals_to_9(res, last_3_moves)

        if len(last_3_moves) == 11:
            tree_path_equals_to_11(res, last_3_moves)

    tree_vizualization(pairs,items, all_moves)


def find_items(last_3_moves):
    global items, pairs
    for i in last_3_moves:
        if i not in pairs:
            items.append(i)


def tree_path_equals_to_11(res, last_3_moves):
    global pairs
    if len(res) < 3:
        pairs = res[0]
        find_items(last_3_moves)

    if len(res) == 3 or len(res) == 4:
        pairs = res[0] + res[1] + res[2]
        find_items(last_3_moves, pairs)

    if len(res) == 5:
        pairs = res[0] + res[1] + res[2] + res[3] + res[4]
        find_items(last_3_moves, pairs)


def tree_path_equals_to_7(res, last_3_moves):
    global pairs
    if len(res) < 3:
        pairs = res[0]
        find_items(last_3_moves)

    if len(res) == 3:
        pairs = res[0] + res[1] + res[2]
        find_items(last_3_moves)


def tree_path_equals_to_9(res, last_3_moves):
    global pairs
    if len(res) < 3:
        pairs = res[0]
        find_items(last_3_moves)

    if len(res) > 2:
        pairs = res[0] + res[1] + res[2]
        find_items(last_3_moves)


def tree_path_equals_to_3_5(res, last_3_moves):
    global pairs, canvas, analyse_is_small
    if len(res) != 0:
        pairs = res[0]
        find_items(last_3_moves)
    else:
        without_solution = Label(canvas, font=("Arial", 16), borderwidth=0,
                                 text='you would have to go back 5 moves!!!').place(x=width_playing_screen / 4, y=300,
                                                                                  anchor="center")
        analyse_is_small = True


def tree_path_equals_to_12(last_3_moves):
    global pairs
    res = find_pairs(last_3_moves)
    if len(res) > 3:
        pairs = res[0] + res[1] + res[2] + res[3]
        find_items(last_3_moves)
    elif len(res) > 1:
        pairs = res[0] + res[1]
        find_items(last_3_moves)


def tree_path_equals_to_8_6(last_3_moves):
    global pairs
    res = find_pairs(last_3_moves)
    if len(res) > 1:
        if len(res) == 4:
            pairs = res
        else:
            pairs = res[0] + res[1]
            find_items(last_3_moves)
    else:
        for i in last_3_moves:
            items.append(i)


def find_pairs(c):  # find all pairs in last few moves
    res = []
    can_add = True
    for i in c:
        for j in c:
            if i != j:
                if ((i[0] == (j[0]-1) and i[1] == j[1]) or (i[0] == (j[0] + 1) and i[1] == j[1]) or (i[0] == j[0] and i[1] == (j[1] - 1)) or (
                        i[0] == j[0] and i[1] == (j[1] + 1))):
                    if len(res) != 0:
                        for k in res:
                            if k[0] == i or k[1] == j or k[0] == j or k[1] == i:
                                can_add = False
                        if can_add:
                            res.append([i, j])
                        if not can_add:
                            can_add = True
                    else:
                        res.append([i, j])
    return res


def tree_vizualization(pairs, items, all_moves):  # tree visualization of the loosing and winning path
    global canvas, analyse_is_small
    width = canvas.winfo_width()
    height = canvas.winfo_height()
    h_item = height/((len(pairs)/2)+len(items)+3)
    start_node = Label(canvas, font=("Arial", 16), borderwidth=2, relief="solid", text=str(all_moves[len(all_moves)-4])).place(x=width/2, y=h_item, anchor="center")

    counter = 2
    for i in range(0, len(pairs), 2):
        text = '[('+str(pairs[i][0])+','+str(pairs[i][1])+'),('+str(pairs[i+1][0])+','+str(pairs[i+1][1])+')]'
        node_1 = Label(canvas, font=("Arial", 16), borderwidth=2, relief="solid", bg="green", text=text).place(x=width/4, y=h_item*counter, anchor="center")
        counter = counter+1

    for i in items:
        text = '[('+str(i[0])+','+str(i[1])+')]'
        node_2 = Label(canvas, font=("Arial", 16), borderwidth=2, relief="solid", bg="green", text=text).place(x=width/4, y=h_item*counter, anchor="center")
        counter = counter+1

    counter = 2
    for i in range(3):
        if analyse_is_small:
            h_item = 110
        node_3 = Label(canvas, font=("Arial", 16), borderwidth=2, bg="red", relief="solid", text='' + str(all_moves[len(all_moves) + (i - 3)])).place(x=width - (width / 4), y=h_item * counter, anchor="center")
        counter = counter+1


def empty_func():
    pass