import pygame
import time
import datetime
import os.path
import json

from pygame.locals import *
from simulation.board import Board


class Interface:

    FOOD_COLOR = (0, 150, 0)
    TOUCHED_COLOR = (50, 50, 0)
    BLOB_LOWER_COLOR = (255, 255, 0)
    BLOB_HIGHER_COLOR = (255, 0, 0)
    BACKGROUND = (0, 0, 0)
    BOARD_SEPARATOR = (120, 120, 120)

    def __init__(self, board, player, blob, scale, save_dir, mode, hidden=False, colors_file=None):
        """
        :type board: Board
        :type player: Player
        :type blob: Blob_Manager
        :type scale: float
        :type save_dir: str
        """

        pygame.init()
        # pygame.key.set_repeat(5, 50)

        if colors_file is not None:
            with open(colors_file, 'r') as file:
                colors = json.load(file)

            Interface.FOOD_COLOR = tuple(colors['FOOD_COLOR'])
            Interface.TOUCHED_COLOR = tuple(colors['TOUCHED_COLOR'])
            Interface.BLOB_LOWER_COLOR = tuple(colors['BLOB_LOWER_COLOR'])
            Interface.BLOB_HIGHER_COLOR = tuple(colors['BLOB_HIGHER_COLOR'])
            Interface.BACKGROUND = tuple(colors['BACKGROUND'])
            Interface.BOARD_SEPARATOR = tuple(colors['BOARD_SEPARATOR'])

        self.board = board
        self.player = player
        self.blob = blob
        self.scale = scale

        self.save_dir = save_dir

        self.debug_mode = False
        self.play = False
        self.do_step = False
        self.show_ants = True

        width = self.board.width * scale
        height = self.board.height * scale

        self.hidden = hidden
        if not self.hidden:
            self.window = pygame.display.set_mode((width, height), mode)

        self.window_surface = pygame.Surface((width, height))

        cross_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), "cross.png")

        discovered_food = pygame.image.load(cross_file)
        if not self.hidden:
            discovered_food = discovered_food.convert()
        discovered_food.set_colorkey((255, 255, 255))
        self.discovered_food = pygame.transform.scale(discovered_food, (scale, scale))

    def draw(self):

        width = self.board.width * self.scale
        height = self.board.height * self.scale

        game_surface = pygame.Surface((self.board.width, self.board.height))
        pixel_array = pygame.PixelArray(game_surface)

        for x in range(self.board.width):
            for y in range(self.board.height):
                pixel_array[x, y] = Interface.BACKGROUND

                if self.board.has_food(x, y):
                    pixel_array[x, y] = Interface.FOOD_COLOR

                if self.board.is_touched(x, y):
                    pixel_array[x, y] = Interface.TOUCHED_COLOR

                val = self.board.get_blob(x, y)
                if val != Board.MIN_BLOB:
                    val = (val - Board.MIN_BLOB) / (Board.MAX_BLOB - Board.MIN_BLOB)
                    red = (Interface.BLOB_HIGHER_COLOR[0] - Interface.BLOB_LOWER_COLOR[0]) * val + \
                          Interface.BLOB_LOWER_COLOR[0]
                    green = (Interface.BLOB_HIGHER_COLOR[1] - Interface.BLOB_LOWER_COLOR[1]) * val + \
                          Interface.BLOB_LOWER_COLOR[1]
                    blue = (Interface.BLOB_HIGHER_COLOR[2] - Interface.BLOB_LOWER_COLOR[2]) * val + \
                          Interface.BLOB_LOWER_COLOR[2]
                    pixel_array[x, y] = (red, green, blue)

        if self.show_ants:
            for scouter in self.blob.scouters:
                pixel_array[scouter.x, scouter.y] = (255, 255, 255)

        del pixel_array

        game_window = pygame.transform.scale(game_surface, (width, height))

        pygame.draw.line(game_window, Interface.BOARD_SEPARATOR, (0, height / 2), (width, height / 2))

        self.window_surface.blit(game_window, (0, 0))
        for food in self.blob.knowledge['food']:
            self.window_surface.blit(self.discovered_food, (food[0] * self.scale, food[1] * self.scale))

        if not self.hidden:
            self.window.blit(self.window_surface, (0, 0))
            pygame.display.flip()

    def save(self, name=None):
        if name is None:
            name = datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d_%H.%M.%S')

        print("Data saved at " + name)
        f = open(self.save_dir + name + ".board", 'w')
        f.write(self.board.save())
        f.close()

        f = open(self.save_dir + name + ".blob.json", 'w')
        f.write(self.blob.save())
        f.close()

        f = open(self.save_dir + name + ".player.json", 'w')
        f.write(self.player.save())
        f.close()

        if self.hidden:
            self.draw()
        pygame.image.save(self.window_surface, self.save_dir + name + ".jpg")

        return name

    def event_listener(self, event):

        # ADMIN ACTIONS
        if event.type == KEYDOWN and event.key == 100:  # D Letter
            self.debug_mode = not self.debug_mode
            print("Debug Mode: " + str(self.debug_mode))

        elif event.type == KEYDOWN and event.key == K_UP:
            self.blob.knowledge["Global Decrease"] += 0.1
            print("Pheromone evaporation : " + str(self.blob.knowledge["Global Decrease"]))

        elif event.type == KEYDOWN and event.key == K_DOWN:
            self.blob.knowledge["Global Decrease"] -= 0.1
            print("Pheromone evaporation : " + str(self.blob.knowledge["Global Decrease"]))

        elif event.type == KEYDOWN and event.key == K_SPACE:
            self.show_ants = not self.show_ants

        elif event.type == KEYDOWN and event.key == 115:  # S Letter
            self.save()

        # DEBUG ACTIONS
        elif self.debug_mode and event.type == MOUSEBUTTONDOWN and event.button == 1:  # Right Click
            x = int(pygame.mouse.get_pos()[0] / self.scale)
            y = int(pygame.mouse.get_pos()[1] / self.scale)
            self.board.update_blob(x, y, 10)

        # PLAYER ACTIONS
        elif event.type == MOUSEBUTTONDOWN and event.button == 1:  # Right Click
            x = int(pygame.mouse.get_pos()[0]/self.scale)
            y = int(pygame.mouse.get_pos()[1]/self.scale)
            if self.board.has_food(x, y):
                self.player.remove_food(x, y)
            else:
                self.player.set_food(x, y)

        elif event.type == KEYDOWN and event.key == 99:  # C Letter
            self.player.clean_board()

        elif event.type == KEYDOWN and event.key == 114:  # R Letter
            self.player.set_random_food(10, not self.player.clean_top)

        elif event.type == KEYDOWN and event.key == 104:  # H Letter
            up_size_percent, down_size_percent = self.player.check_blob_cover()
            print("Blob covering:")
            print("\t{:.2f}% of the board.".format((up_size_percent + down_size_percent)/2))
            print("\t{:.2f}% of the upper board.".format(up_size_percent))
            print("\t{:.2f}% of the lower board.".format(down_size_percent))

        # BLOB ACTIONS
        elif event.type == KEYDOWN and event.key == 112:  # P Letter
            self.play = not self.play

        elif event.type == KEYDOWN and event.key == K_RETURN:
            self.do_step = True

        elif event.type == KEYDOWN and event.key == 107:  # K Letter
            if self.blob.knowledge["Scouters"]["Min"] > 0:
                self.blob.knowledge["Scouters"]["Min"] -= 1
                print("New minimal scouters : " + str(self.blob.knowledge["Scouters"]["Min"]) + " - Currently : "
                      + str(len(self.blob.scouters)))

        elif event.type == KEYDOWN and event.key == 113:  # A letter
            self.blob.knowledge["Scouters"]["Min"] += 1
            print("New minimal scouters : " + str(self.blob.knowledge["Scouters"]["Min"]) + " - Currently : "
                  + str(len(self.blob.scouters)))

        elif event.type == KEYDOWN:
            print("Unrecognised key code : " + str(event.key))
            return False

        else:
            return False

        return True
