"""
A board is a 2D list containing ones or zeros. A "shape" is a nested
tuple, where the real world shape is represented as ones. For example, an "L"
shape could be represented as 

   shape = ((False, False, True),(True, True, True))
"""

from draw_packing import *
import time
import random

"""
Begin board related code
"""

class Board:
    """
    squares is a 2D list containing ones or zeros.
    """
    pass

def create_board(rows, cols, squares):
    """
    Board constructor
    """

def update(self, shape, view):
    """
    Top-level def for placing a single shape on board. Finds best
    position and rotation for shape, update
    board squares.
    Calls: find_best_place show_and_rotate 
    Returns tuple:  (fits board) boolean and board
    """
    #1) call find best place
    #2) if find best place said the shape fit, go to 3, otherwise stop
    #3) call show and rotate for the number of rotations given by find best
    #    place
    #4) update the shape's row and column based on what find best place told us
    #5) fill in the squares on the board where the shape now rests

def find_best_place(self, shape):
    """
    Takes a single shape, finds best position on self. Tries original and 
    three possible 90 degree rotations. Mutates shape.
    Returns tuple:  (fits, max_score_row, max_score_col, num_rotations)
    fits: bool
    max_score_row, max_score_col: upper left coordinates of best position
    for shape on board num_rotations: 0-3 rotations required for best fit.
    Calls: find_one_place, rotate90
    """

def find_one_place(self, shape):
    """
    Takes a single shape in one position and finds the best fit on the
    board. If two fits are the same, then it defaults to the lowest,
    rightmost position on the board. 
    Returns a tuple:  (fits, best_row, best_col score)
    fits: bool
    best_row, best_col: upper left coordinates of best position for shape
    on self
    score: fill, or other heuristic. Higher is better.
    Calls: fit
    """ 

def fit(self, upleft_Row, upleft_Col, shape):
    """
    upleft_Row, upleft_Col are upper left coordinates of position we wish to
    fit shape on self.
    Returns tuple: (it_fits, fill) where it_fits is true if the shape fits
    in the specified location on the board;  fill is the amount of
    "fill" the shape has with other filled space on the board (that is, 
    where a zero in the shape lines up with a one on the board). 
    """

"""
End board related code
"""

"""
Begin shape related code
"""
class Shape:
    """
    A "shape" is a nested tuple, where the real world shape is
    represented as ones. For example, an "L" shape could be
    represented as

    shape = ((False, False, True),(True, True, True))
    """
    pass

def create_shape(letter, squares, color):
    """
    Shape constructor
    """

def rotate90(self):
    """
    Rotates self 90 degrees clockwise (yes, direction matters).
    Returns: None
    """
    self.squares = tuple(zip(*self.squares[::-1]))
    self.rotations = (self.rotations + 1) % 4

def show_and_rotate(self, num_rotations, view):
    """
    Draws shape  and shows it rotating to correct orientation
    with a brief pause at each orientation.
    Calls: GameView.draw_shape, rotate90
    Returns: None
    """
    time.sleep(0.5) # does nothing for one full half of a second
 
def get_shape(letter):
    """
    Returns the shape corresponding to the letter parameter: I, J, L, O, S, T, 
    or Z.
    """

"""
End Shape related code
"""

def start(rows, cols):
    """
    Makes a blank Board of size rows by cols, makes a corresponding GameView on
    which to draw the game happening, seeds the random number generator,
    schedules run, and starts the event loop.
    Calls: run
    Returns: None
    """
    b = create_board(rows, cols, [])
    shapes = []
    game_view = GameView(rows, cols, shapes)
    game_view.after(10, run, b, shapes, game_view)
    game_view.mainloop()

def run(board, shapes, game_view):
    """
    Repeatedly generates a new shape and then fits that shape on the current
    board.  On each pass, the new shape should be shown in the upper left
    corner of the board, then rotated to the appropriate orientation (the
    rotation should be animated to show each step,) and finally placed in
    the appropriate location on the board.
    calls: get_shape, GameView.draw_game_board, update.
    """
    keep_playing = True
    while keep_playing:
        #1) get a random new shape, append it to the shapes list
        shape = get_shape(random.choice('ILJSZTO'))
        shapes.append(shape)
        #2) call update on the board and that new shape
        keep_playing, board = update(board, shape, game_view)
        #3) call draw_game_board on the view
        game_view.draw_game_board()
        
if __name__ == '__main__':
    start(22,10) # You can make a board of whatever size you wish.  Here's an
                 # idea to get you started.  (The standard Tetris board size is
                 # 22 by 10.
