"""Графическая часть игры.

Отвечает за отрисовку окна игры и рендер игрового поля.
"""
import contextlib
with contextlib.redirect_stdout(None):
    import pygame as pg
from gameconfig import SCREEN_WIDTH, SCREEN_HEIGHT, \
    BACK_COLOR, FRAMERATE, DIRECTION
from .game_records import RecordWrittenException
from . import core, core_aliens, core_playground
from . import graphics
from . import ui
from . import save_load as sl


class SpaceInvadersWnd():
    def __init__(self):
        pg.init()
        ui.init()
        self.window = pg.display.set_mode(
            (SCREEN_WIDTH, SCREEN_HEIGHT))
        self.clock = pg.time.Clock()
        self.alien_spriteset = graphics.SpriteSet("alien.png")
        self.player_spriteset = graphics.SpriteSet("player.png")
        self.projectile_spriteset = graphics.SpriteSet("bullet.png")
        self.bonus_ship_spriteset = graphics.SpriteSet(
            "bonus_ship.png", is_long=True)
        self.bunker_part_spriteset = graphics.SpriteSet("bunker_part.png")
        self.player_group = pg.sprite.Group()
        self.alien_group = pg.sprite.Group()
        self.projectile_group = pg.sprite.Group()
        self.bonus_ship_group = pg.sprite.Group()
        self.bunker_part_group = pg.sprite.Group()
        self.playground = None
        self.is_in_menu = True
        self.is_on = True
        self.is_loading_save = False

    def start(self):
        while self.is_in_menu and self.is_on:
            for event in pg.event.get():
                if event.type == pg.QUIT:
                    self.is_on = False
                    break
                if event.type == pg.KEYDOWN:
                    if event.key == pg.K_ESCAPE:
                        self.is_on = False
                        break
                    if event.key == pg.K_SPACE:
                        self.is_in_menu = False
                    if event.key == pg.K_F9:
                        self.is_loading_save = True
                        self.is_in_menu = False
            self.update_menu()
            self.clock.tick(FRAMERATE)
        if self.is_on:
            if not self.is_loading_save:
                self.play_game()
            else:
                self.play_game(save=sl.get_savefile())
        pg.quit()

    def play_game(self, save=None):
        self.init_playground(save)
        try:
            while self.is_on:
                for event in pg.event.get():
                    if event.type == pg.QUIT:
                        self.is_on = False
                        break
                    if event.type == pg.KEYDOWN:
                        if event.key == pg.K_ESCAPE:
                            self.is_on = False
                            break
                        if event.key == pg.K_p:
                            if not self.playground.is_paused_manual:
                                self.playground.pause_manual()
                            else:
                                self.playground.unpause_manual()
                        if event.key == pg.K_F5:
                            sl.write_savefile(self.playground.save)
                self.player_game_input()
                self.update_game()
                self.clock.tick(FRAMERATE)
        except core_playground.GameEndedException:
            self.game_end()
        pg.quit()

    def game_end(self):
        player_input = ui.get_player_input()
        while self.is_on:
            events = pg.event.get()
            for event in events:
                if event.type == pg.QUIT:
                    self.is_on = False
                    break
                if event.type == pg.KEYDOWN:
                    if event.key == pg.K_ESCAPE:
                        self.is_on = False
                        break
            self.update_gameover(events, player_input)
            self.clock.tick(FRAMERATE)
        pg.quit()

    def player_game_input(self):
        keys = pg.key.get_pressed()
        if keys[pg.K_LEFT]:
            self.playground.player.move(DIRECTION["left"])
        if keys[pg.K_RIGHT]:
            self.playground.player.move(DIRECTION["right"])
        if keys[pg.K_SPACE]:
            projectile = self.playground.player.shoot(self.playground)
            if isinstance(projectile, core.Projectile):
                self.add_projectile(projectile)

    def update_menu(self):
        self.window.fill(BACK_COLOR)
        ui.draw_start_ui(self.window)
        pg.display.update()

    def update_gameover(self, events, player_input):
        self.window.fill(BACK_COLOR)
        try:
            ui.draw_gameover_ui(self.window, self.playground, events,
                                player_input)
            pg.display.update()
        except RecordWrittenException:
            self.is_on = False

    def update_game(self):
        if self.playground.is_new:
            self.empty_groups()
        self.playground.update()
        self.update_game_frame()

    def empty_groups(self):
        self.player_group.empty()
        self.alien_group.empty()
        self.projectile_group.empty()
        self.bonus_ship_group.empty()
        self.bunker_part_group.empty()
        for alien in self.playground.cluster.flatten_aliens:
            sprite = graphics.AlienSprite(alien, self.alien_spriteset)
            self.alien_group.add(sprite)
        for bunker in self.playground.bunker_cluster.bunkers:
            for part in bunker.parts:
                sprite = graphics.BunkerPartSprite(
                    part, self.bunker_part_spriteset)
                self.bunker_part_group.add(sprite)
        player_sprite = graphics.PlayerSprite(
            self.playground.player, self.player_spriteset)
        self.player_group.add(player_sprite)

    def update_sprite_groups(self):
        self.alien_group.draw(self.window)
        self.bunker_part_group.draw(self.window)
        self.player_group.draw(self.window)
        self.projectile_group.draw(self.window)
        self.bonus_ship_group.draw(self.window)

    def update_game_frame(self):
        self.window.fill(BACK_COLOR)
        ui.draw_game_ui(self.window, self.playground)
        self.init_enemy_projectiles()
        self.init_bonus_ship(self.playground.bonus_ship)
        for sprite in self.alien_group:
            sprite.update_sprite()
        for sprite in self.player_group:
            sprite.update_sprite()
        for sprite in self.projectile_group:
            sprite.update_sprite()
        for sprite in self.bonus_ship_group:
            sprite.update_sprite()
        for sprite in self.bunker_part_group:
            sprite.update_sprite()
        self.update_sprite_groups()
        pg.display.update()

    def add_projectile(self, projectile: core.Projectile):
        sprite = graphics.ProjectileSprite(
            projectile, self.projectile_spriteset)
        self.projectile_group.add(sprite)

    def init_playground(self, save):
        if save is None:
            self.playground = core_playground.Playground()
        else:
            self.playground = core_playground.Playground(save=save)

    def init_enemy_projectiles(self):
        for projectile in self.playground.projectiles_enemy:
            self.add_projectile(projectile)

    def init_bonus_ship(self, bonus_ship: core_aliens.BonusShip):
        if self.playground.bonus_ship is not None:
            sprite = graphics.BonusShipSprite(
                bonus_ship, self.bonus_ship_spriteset)
            self.bonus_ship_group.add(sprite)

"""Графическая часть игры.

Отвечает за отрисовку окна игры и рендер игрового поля.
"""
import contextlib
with contextlib.redirect_stdout(None):
    import pygame as pg
from gameconfig import SCREEN_WIDTH, SCREEN_HEIGHT, \
    BACK_COLOR, FRAMERATE, DIRECTION
from .game_records import RecordWrittenException
from . import core, core_aliens, core_playground
from . import graphics
from . import ui
from . import save_load as sl


class SpaceInvadersWnd():
    def __init__(self):
        pg.init()
        ui.init()
        self.window = pg.display.set_mode(
            (SCREEN_WIDTH, SCREEN_HEIGHT))
        self.clock = pg.time.Clock()
        self.alien_spriteset = graphics.SpriteSet("alien.png")
        self.player_spriteset = graphics.SpriteSet("player.png")
        self.projectile_spriteset = graphics.SpriteSet("bullet.png")
        self.bonus_ship_spriteset = graphics.SpriteSet(
            "bonus_ship.png", is_long=True)
        self.bunker_part_spriteset = graphics.SpriteSet("bunker_part.png")
        self.player_group = pg.sprite.Group()
        self.alien_group = pg.sprite.Group()
        self.projectile_group = pg.sprite.Group()
        self.bonus_ship_group = pg.sprite.Group()
        self.bunker_part_group = pg.sprite.Group()
        self.playground = None
        self.is_in_menu = True
        self.is_on = True
        self.is_loading_save = False

    def start(self):
        while self.is_in_menu and self.is_on:
            for event in pg.event.get():
                if event.type == pg.QUIT:
                    self.is_on = False
                    break
                if event.type == pg.KEYDOWN:
                    if event.key == pg.K_ESCAPE:
                        self.is_on = False
                        break
                    if event.key == pg.K_SPACE:
                        self.is_in_menu = False
                    if event.key == pg.K_F9:
                        self.is_loading_save = True
                        self.is_in_menu = False
            self.update_menu()
            self.clock.tick(FRAMERATE)
        if self.is_on:
            if not self.is_loading_save:
                self.play_game()
            else:
                self.play_game(save=sl.get_savefile())
        pg.quit()

    def play_game(self, save=None):
        self.init_playground(save)
        try:
            while self.is_on:
                for event in pg.event.get():
                    if event.type == pg.QUIT:
                        self.is_on = False
                        break
                    if event.type == pg.KEYDOWN:
                        if event.key == pg.K_ESCAPE:
                            self.is_on = False
                            break
                        if event.key == pg.K_p:
                            if not self.playground.is_paused_manual:
                                self.playground.pause_manual()
                            else:
                                self.playground.unpause_manual()
                        if event.key == pg.K_F5:
                            sl.write_savefile(self.playground.save)
                self.player_game_input()
                self.update_game()
                self.clock.tick(FRAMERATE)
        except core_playground.GameEndedException:
            self.game_end()
        pg.quit()

    def game_end(self):
        player_input = ui.get_player_input()
        while self.is_on:
            events = pg.event.get()
            for event in events:
                if event.type == pg.QUIT:
                    self.is_on = False
                    break
                if event.type == pg.KEYDOWN:
                    if event.key == pg.K_ESCAPE:
                        self.is_on = False
                        break
            self.update_gameover(events, player_input)
            self.clock.tick(FRAMERATE)
        pg.quit()

    def player_game_input(self):
        keys = pg.key.get_pressed()
        if keys[pg.K_LEFT]:
            self.playground.player.move(DIRECTION["left"])
        if keys[pg.K_RIGHT]:
            self.playground.player.move(DIRECTION["right"])
        if keys[pg.K_SPACE]:
            projectile = self.playground.player.shoot(self.playground)
            if isinstance(projectile, core.Projectile):
                self.add_projectile(projectile)

    def update_menu(self):
        self.window.fill(BACK_COLOR)
        ui.draw_start_ui(self.window)
        pg.display.update()

    def update_gameover(self, events, player_input):
        self.window.fill(BACK_COLOR)
        try:
            ui.draw_gameover_ui(self.window, self.playground, events,
                                player_input)
            pg.display.update()
        except RecordWrittenException:
            self.is_on = False

    def update_game(self):
        if self.playground.is_new:
            self.empty_groups()
        self.playground.update()
        self.update_game_frame()

    def empty_groups(self):
        self.player_group.empty()
        self.alien_group.empty()
        self.projectile_group.empty()
        self.bonus_ship_group.empty()
        self.bunker_part_group.empty()
        for alien in self.playground.cluster.flatten_aliens:
            sprite = graphics.AlienSprite(alien, self.alien_spriteset)
            self.alien_group.add(sprite)
        for bunker in self.playground.bunker_cluster.bunkers:
            for part in bunker.parts:
                sprite = graphics.BunkerPartSprite(
                    part, self.bunker_part_spriteset)
                self.bunker_part_group.add(sprite)
        player_sprite = graphics.PlayerSprite(
            self.playground.player, self.player_spriteset)
        self.player_group.add(player_sprite)

    def update_sprite_groups(self):
        self.alien_group.draw(self.window)
        self.bunker_part_group.draw(self.window)
        self.player_group.draw(self.window)
        self.projectile_group.draw(self.window)
        self.bonus_ship_group.draw(self.window)

    def update_game_frame(self):
        self.window.fill(BACK_COLOR)
        ui.draw_game_ui(self.window, self.playground)
        self.init_enemy_projectiles()
        self.init_bonus_ship(self.playground.bonus_ship)
        for sprite in self.alien_group:
            sprite.update_sprite()
        for sprite in self.player_group:
            sprite.update_sprite()
        for sprite in self.projectile_group:
            sprite.update_sprite()
        for sprite in self.bonus_ship_group:
            sprite.update_sprite()
        for sprite in self.bunker_part_group:
            sprite.update_sprite()
        self.update_sprite_groups()
        pg.display.update()

    def add_projectile(self, projectile: core.Projectile):
        sprite = graphics.ProjectileSprite(
            projectile, self.projectile_spriteset)
        self.projectile_group.add(sprite)

    def init_playground(self, save):
        if save is None:
            self.playground = core_playground.Playground()
        else:
            self.playground = core_playground.Playground(save=save)

    def init_enemy_projectiles(self):
        for projectile in self.playground.projectiles_enemy:
            self.add_projectile(projectile)

    def init_bonus_ship(self, bonus_ship: core_aliens.BonusShip):
        if self.playground.bonus_ship is not None:
            sprite = graphics.BonusShipSprite(
                bonus_ship, self.bonus_ship_spriteset)
            self.bonus_ship_group.add(sprite)

Графическая часть игры.  Отвечает за отрисовку окна игры и рендер игрового поля.