# coding=utf-8
'''
pymaze
Copyright (C) 2012-2014 Moses Palmér

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.
'''

import sys

def print_maze(maze, solution, wall_char = '@', path_char = '.',
        floor_char = ' ', room_size = (5, 4)):
    """
    Prints a maze and its solution.

    This function works only for mazes with square rooms.

    @param maze
        The maze to print. If this is not a maze with square rooms, False is
        immediately returned.
    @param solution
        The solution, as a list generated by list(maze[start:end]).
    @param wall_char, path_char, floor_char
        The characters to use to print the walls, the solution path and the
        floor. The lengths of each of these string must be equal.
    @param room_size
        The size, expressed as (width, height), of a room in characters.
    @return True if the maze could be printed and False otherwise
    """
    if len(maze.Wall.WALLS) != 4:
        print('This maze cannot be printed as it is not square')
        return False

    def output(s):
        sys.stdout.write(s)

    # Iterate over all rows and make sure to start with the last one to maintain
    # the orientation of the maze
    for y in reversed(range(maze.height)):
        # Print one line for each height unit of a room
        for line in range(room_size[1]):
            # Calculate the vertical offset of the neighbouring room
            dy = 1 if not line else -1 if line == room_size[1] - 1 else 0
            for x in range(maze.width):
                # Print one line of the current room for every room in the
                # current row
                if line == 0 or line == room_size[1] - 1:
                    # This is the first or the last line
                    output(''.join((
                        # The left wall
                        wall_char,

                        # The opening or top/bottom wall
                        (path_char if \
                            int(maze.Wall.from_direction((x, y), (0, dy))) \
                                in maze[x, y] \
                            and (x, y) in solution \
                            and (x, y + dy) in solution
                        else floor_char \
                            if int(maze.Wall.from_direction((x, y), (0, dy))) \
                                in maze[x, y]
                        else wall_char) * (room_size[0] - 2),

                        # The right wall
                        wall_char)))
                else:
                    # This is a line in the middle of a room
                    output(''.join((
                        # The left opening or wall
                        path_char if int(maze.Wall.from_direction(
                                (x, y), (-1, 0))) in maze[x, y] \
                            and (x, y) in solution \
                            and (x - 1, y) in solution
                        else floor_char if \
                            int(maze.Wall.from_direction((x, y), (-1, 0))) \
                                in maze[x, y]
                        else wall_char,

                        # The center
                        (path_char if (x, y) in solution \
                        else floor_char) * (room_size[0] - 2),

                        # The right opening or wall
                        path_char if int(maze.Wall.from_direction(
                                (x, y), (1, 0))) in maze[x, y] \
                            and (x, y) in solution \
                            and (x + 1, y) in solution
                        else floor_char if \
                            int(maze.Wall.from_direction((x, y), (1, 0))) \
                                in maze[x, y]
                        else wall_char)))
            output('\n')

    return True

