import pygame, os, sys, itertools
import Tak

#display setup
pygame.init()
#basic settings to use
resolution = (800, 1000)
width, height = 800, 800
colors = {'white':(255, 255, 255), 'black':(0, 0, 0), 'lightBrown':(251, 196, 117), 'darkBrown':(139, 69, 0),
            'lightGrey':(150, 150, 150), 'darkGrey':(100, 100, 100)}
win = pygame.display.set_mode(resolution)
pygame.display.set_caption("Tak")
font = pygame.font.SysFont('Arial', 18)
background = pygame.Surface(resolution)
background.fill(colors['black'])
pieceImages = {'lightflat':pygame.image.load('2D pieces/flat-light.png'), 'lightwall':pygame.image.load('2D pieces/wall-light.png'),
                'lightcapstone':pygame.image.load('2D pieces/capstone-light.png'), 'darkflat':pygame.image.load('2D pieces/flat-dark.png'),
                'darkwall':pygame.image.load('2D pieces/wall-dark.png'), 'darkcapstone':pygame.image.load('2D pieces/capstone-dark.png'),}

#board and button classes
class board(object):
    def __init__(self, size):
        self.width, self.height = 800, 800
        self.size = size
        self.squareSize = self.width/size
        self.bd = pygame.Surface((self.width, self.height))
        self.squareCentres = []
        self.color = [colors['lightBrown'], colors['darkBrown']]
        self.index = 1
        for row in range(size):
            for column in range(size):
                Square = (row*self.squareSize, column*self.squareSize, self.squareSize, self.squareSize)
                if Square not in self.squareCentres:
                    self.squareCentres.append(Square)
                pygame.draw.rect(self.bd, self.color[self.index], Square)
                if not (size%2 == 0 and column == size-1):
                    self.index = (self.index+1)%2

    def checkSquare(self, coordinate):
        for i in range(len(self.squareCentres)):
            square = self.squareCentres[i]
            if square[0] < coordinate[0] < square[0] + square[2] and square[1] < coordinate[1] < square[1] + square[3]:
                return [i//self.size, i%self.size]

class button(object):
    def __init__(self, x, y, text, width = 110, height = 40):
        self.width = width
        self.height = height
        self.x = x
        self.y = y
        self.text = text
        self.disp = renderStandard(text)

#move has to be built in multiple steps and needs the object to hold and output the data in the correct
#format for the move command in game
class buildMove(object):
    def __init__(self, start):
        self.start = start
        self.dropLocations = []
        self.hand = 0
        self.current = start
        self.direction = None

    def pickup(self, loc):
        if self.same(self.start, loc) and game.checkLegalPickup(loc, self.hand+1):
            self.hand += 1

    def next(self, loc):
        return loc[0] == self.current[0] + self.direction[0] and loc[1] == self.current[1] + self.direction[1]

    def same(self, loc1, loc2):
        return loc1[0] == loc2[0] and loc1[1] == loc2[1]

    def drop(self, loc):
        if game.board.isAdjacent(loc, self.start) and self.direction is None and game.checkLegalDrop(loc, game.board.getLocation(self.start)[-self.hand]):
            self.direction = [loc[0]-self.start[0], loc[1] - self.start[1]]
            self.dropLocations.append(loc)
            self.hand -= 1
            self.current = loc

        elif self.direction is not None and (self.same(self.current, loc) or self.next(loc)) and self.hand > 0 and game.checkLegalDrop(loc, game.board.getLocation(self.start)[-self.hand]):
            self.dropLocations.append(loc)
            self.hand -= 1
            self.current = loc

    def dropArray(self):
        array = []
        count = 0
        current = self.dropLocations[0]
        for location in self.dropLocations:
            if self.same(current, location):
                count += 1
            else:
                array.append(count)
                count = 1
                current = location
        array.append(count)
        return array

    def getEnd(self):
        return self.dropLocations[-1]

#get correct image to draw onto the board for each piece
def selectPieceImage(value):
    key = ''
    if value > 0:
        key += 'light'
    else:
        key += 'dark'
    if abs(value) == 3:
        key += 'capstone'
    elif abs(value) == 2:
        key += 'wall'
    else:
        key += 'flat'
    return pieceImages[key]

#render the board as a printable set to show pieces
def renderPieces(game, board):
    for i in range(game.board.size):
        for j in range(game.board.size):
            pieceStack = game.board.getLocation([i, j])
            boardSquare = board.squareCentres[i*board.size+j]
            coordinate = boardSquare[:2]
            for x in range(len(pieceStack)):
                if pieceStack[x] != 0:
                    if abs(pieceStack[x]) == 2:
                        image = pygame.transform.scale(selectPieceImage(pieceStack[x]), (int(board.squareSize*0.2), int(board.squareSize*0.6)))
                    else:
                        image = pygame.transform.scale(selectPieceImage(pieceStack[x]), (int(board.squareSize*0.6), int(board.squareSize*0.6)))
                    win.blit(image, (coordinate[0]+int(board.squareSize*(0.05*(x+1))), coordinate[1]+int(board.squareSize*(0.05*(x+1)))))

#check to see what button has been pressed
def checkButtons(coordinate):
    for butt in buttons:
        if butt.x < coordinate[0] < butt.x + butt.width and butt.y < coordinate[1] < butt.y + butt.height:
            return butt.text

#render standard font
def renderStandard(text):
    return font.render(text, True, colors['white'])

#display game results
def displayResults():
    results = game.getEndResults()
    block = pygame.Surface((250, 160))
    block.fill(colors['white'])
    winText = pygame.font.SysFont('Arial', 40).render('Winner!', True, colors['black'])
    winnerText = pygame.font.SysFont('Arial', 30).render('Player ' + str(results[0]), True, colors['black'])
    pointText = font.render('Points scored: ' + str(results[1]), True, colors['black'])
    win.blit(block, (275, 300))
    win.blit(winText, (320, 310))
    win.blit(winnerText, (335, 370))
    win.blit(pointText, (320, 430))

#display current action
def displayAction():
    actionText = [renderStandard("Current Action:")]
    if move is not None:
        actionText.append(renderStandard('Moving'))
        actionText.append(renderStandard('Holding ' + str(move.hand) + ' from ' + str(move.start)))
        if move.direction is not None:
            actionText.append(renderStandard('Dropping'))
            dropArray = move.dropArray()
            direction = move.direction
            for i in range(len(dropArray)):
                location = move.start[0] + (i+1)*direction[0], move.start[1] + (i+1)*direction[1]
                actionText.append(renderStandard(str(dropArray[i]) + ' at ' + str(location)))
    elif type != 0:
        actionText.append(renderStandard('Placing'))
        if type == 1:
            actionText.append(renderStandard('Flat stone'))
        elif type == 2:
            actionText.append(renderStandard('Wall'))
        elif type == 3:
            actionText.append(renderStandard('Capstone'))
    else:
        actionText.append(renderStandard('No current action'))
    start = (270, 820)
    for i in range(len(actionText)):
        win.blit(actionText[i], (start[0], start[1] + i*20))

#initialize components
table = board(5)
game = Tak.TakGame(5)
pastGames = []

turnLabel = renderStandard('Current Turn: ')
playerLabel = renderStandard('Current Player: ')
sizeLabel = renderStandard('Select game size (will reset game):')
piecesLabel = renderStandard('Pieces left:')
capstonesLabel = renderStandard('Capstones left:')

flatButton = button(20, 820, 'Flat')
wallButton = button(20, 880, 'Wall')
capButton = button(20, 940, 'Capstone')
moveButton = button(150, 820, 'Move')
cancelButton = button(150, 880, 'Cancel')
undoButton = button(150, 940, 'Undo')
threeButton = button(500, 940, '3', 40, 40)
fourButton = button(560, 940, '4', 40, 40)
fiveButton = button(620, 940, '5', 40, 40)
sixButton = button(680, 940, '6', 40, 40)
eightButton = button(740, 940, '8', 40, 40)

buttons = [flatButton, wallButton, capButton, moveButton, undoButton, cancelButton, threeButton, fourButton,
            fiveButton, sixButton, eightButton]

#game loop and initilize game specific settings
fps = 60
clock = pygame.time.Clock()
run = True
type = 0
location = None
buildingMove = False
move = None
player = 1

while run:
    clock.tick(fps)
    player = 2-(game.turnCount%2)
    #draw out all the features
    win.blit(background, (0,0))
    win.blit(table.bd, table.bd.get_rect())
    win.blit(turnLabel, (480, 820))
    win.blit(renderStandard(str(game.turnCount)), (600, 820))
    win.blit(playerLabel, (640, 820))
    win.blit(renderStandard(str(player)), (780, 820))
    win.blit(piecesLabel, (480, 860))
    win.blit(renderStandard(str(game.piecesLeft(player)[0])), (580, 860))
    win.blit(capstonesLabel, (640, 860))
    win.blit(renderStandard(str(game.piecesLeft(player)[1])), (780, 860))
    win.blit(sizeLabel, (480, 900))
    renderPieces(game, table)

    #actions on events
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        if event.type == pygame.MOUSEBUTTONDOWN:
            mouse = pygame.mouse.get_pos()
            selection = checkButtons(mouse)
            location = table.checkSquare(mouse)
            if selection == 'Flat':
                type = 1
            elif selection == 'Wall' and game.turnCount > 2:
                type = 2
            elif selection == 'Capstone' and game.turnCount > 2:
                type = 3
            elif selection == 'Cancel':
                if move is None:
                    type = 0
                else:
                    move = None
                    buildingMove = False
            elif selection == 'Undo':
                if game.turnCount > 1:
                    game.undo()
                elif len(pastGames) > 0:
                    last = pastGames.pop()
                    game = last[0]
                    table = last[1]
            elif selection == 'Move':
                buildingMove = True
            elif selection is not None and selection.isdigit():
                pastGames.append((game, table))
                game = Tak.TakGame(int(selection))
                table = board(int(selection))
            elif type != 0 and location is not None and game.checkLegalPlacement(location):
                game.actPlace(player, location, type)
                location = None
                type = 0
            elif move is not None and buildingMove:
                if move.same(move.start, location):
                    move.pickup(location)
                elif move.hand > 0:
                    move.drop(location)
                else:
                    game.actMove(move.start, move.getEnd(), move.dropArray())
                    move = None
                    buildingMove = False
            elif buildingMove and location is not None and game.checkLegalMoveStart(player, location):
                move = buildMove(location)
                move.pickup(location)

    #track if we are hovering over buttons and draw them in the correct color
    mouse = pygame.mouse.get_pos()
    for butt in buttons:
        if butt.x < mouse[0] < butt.x + butt.width and butt.y < mouse[1] < butt.y + butt.height:
            pygame.draw.rect(win, colors['lightGrey'], [butt.x, butt.y, butt.width, butt.height])
        else:
            pygame.draw.rect(win, colors['darkGrey'], [butt.x, butt.y, butt.width, butt.height])
        win.blit(butt.disp, (butt.x + 10, butt.y + int(butt.height/4)))
    if game.end():
        displayResults()
    displayAction()
    pygame.display.update()

pygame.quit()
sys.exit()
