# coding: utf-8
import cocos
from cocos.actions import ScaleBy, Repeat, Reverse, RotateBy
from cocos.director import director
from cocos.layer import ScrollableLayer, Layer
from cocos.sprite import Sprite
from pyglet.window import key as wkey
from random import randint
from sandbox.life_game.simulation import CellBornEvent
from sandbox.life_game.simulation import CellDieEvent, Cell, InvertCellStateBehaviour, \
    EmptyPositionWithLotOfCellAroundEvent
from synergine2.config import Config
from synergine2.log import SynergineLogger
from synergine2.terminals import Terminal
from synergine2.terminals import TerminalPackage
from synergine2_cocos2d.gui import Gui, GridLayerMixin, MainLayer as BaseMainLayer

cell_scale = ScaleBy(1.1, duration=0.25)
cell_rotate = RotateBy(360, duration=30)
flash_flash = ScaleBy(8, duration=0.5)
flash_rotate = RotateBy(360, duration=6)


class Cells(GridLayerMixin, Layer):
    def __init__(self):
        super().__init__()
        self.cells = {}
        self.flashs = []

    def born(self, grid_position):
        if grid_position in self.cells:
            return  # cell can be added by gui

        cell = Sprite('resources/cells_l.png')
        cell.rotation = randint(0, 360)
        self.grid_manager.scale_sprite(cell)
        self.grid_manager.position_sprite(cell, grid_position)
        cell.do(Repeat(cell_scale + Reverse(cell_scale)))
        cell.do(Repeat(cell_rotate + Reverse(cell_rotate)))
        self.cells[grid_position] = cell
        self.add(cell)

    def die(self, grid_position):
        try:
            self.remove(self.cells[grid_position])
            del self.cells[grid_position]
        except KeyError:
            pass  # Cell can be removed by gui

    def flash(self, position):
        flash = Sprite('resources/flash.png')
        flash.opacity = 40
        flash.scale = 0.1
        flash.rotation = randint(0, 360)
        flash.do(flash_flash + Reverse(flash_flash))
        flash.do(Repeat(flash_rotate + Reverse(flash_rotate)))
        self.grid_manager.position_sprite(flash, position)
        self.flashs.append(flash)
        self.add(flash)


class MainLayer(GridLayerMixin, BaseMainLayer):
    is_event_handler = True

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.background = Sprite('resources/banner-1711735_640.jpg')
        self.background.position = 0, 0
        self.background.opacity = 70
        self.background.scale = 5
        self.add(self.background, z=1)

        self.cells = Cells()
        self.add(self.cells)

        self.cross = Sprite('resources/cross31x31.png')
        self.cross.position = 0, 0
        self.cross.opacity = 50
        self.add(self.cross)

        # Set scene center on center of screen
        window_size = director.get_window_size()
        self.position = window_size[0] // 2, window_size[1] // 2

    def on_mouse_press(self, x, y, buttons, modifiers):
        x, y = director.get_virtual_coordinates(x, y)
        grid_position = self.grid_manager.get_grid_position(x, y)

        self.terminal.send(TerminalPackage(
            simulation_actions=[(InvertCellStateBehaviour, {'position': grid_position})],
        ))

    def on_mouse_motion(self, x, y, dx, dy):
        x, y = director.get_virtual_coordinates(x, y)
        grid_position = self.grid_manager.get_grid_position(x, y)
        window_position = self.grid_manager.get_window_position(grid_position[0], grid_position[1])

        self.cross.position = window_position


class LifeGameGui(Gui):
    def __init__(
            self,
            config: Config,
            logger: SynergineLogger,
            terminal: Terminal,
            read_queue_interval: float=1 / 60.0,
    ):
        super().__init__(config, logger, terminal, read_queue_interval)

        self.main_layer = MainLayer(terminal=self.terminal)
        self.main_scene = cocos.scene.Scene(self.main_layer)
        self.positions = {}

        self.terminal.register_event_handler(CellDieEvent, self.on_cell_die)
        self.terminal.register_event_handler(CellBornEvent, self.on_cell_born)
        self.terminal.register_event_handler(
            EmptyPositionWithLotOfCellAroundEvent,
            self.on_empty_cell_with_lot_of_cell_around,
        )

    def get_main_scene(self):
        return self.main_scene

    def before_received(self, package: TerminalPackage):
        if package.subjects:  # It's thirst package
            for subject in package.subjects:
                if isinstance(subject, Cell):
                    self.positions[subject.id] = subject.position
                    self.main_layer.cells.born(subject.position)

        for flash in self.main_layer.cells.flashs[:]:
            self.main_layer.cells.flashs.remove(flash)
            self.main_layer.cells.remove(flash)

    def on_cell_die(self, event: CellDieEvent):
        try:
            self.main_layer.cells.die(self.positions[event.subject_id])
        except KeyError:
            pass

    def on_cell_born(self, event: CellBornEvent):
        if event.subject_id not in self.terminal.subjects:
            return

        subject = self.terminal.subjects.get(event.subject_id)
        self.positions[event.subject_id] = subject.position
        self.main_layer.cells.born(subject.position)

    def on_empty_cell_with_lot_of_cell_around(self, event: EmptyPositionWithLotOfCellAroundEvent):
        self.main_layer.cells.flash(event.position)