# A Python interface to libboard from gnugo
# Also has functions for printing the board via pygame,
# and for controlling that printing to some degree.
#
# I'm only implementing what I need for my own purposes.
# Further API is welcome!


from ctypes import *


class board_state(Structure):
    BOARDSIZE = 19
    MAX_MOVE_HISTORY = 361

    _fields_ = [
        ('board_size', c_int),
        ('board', c_char * BOARDSIZE),
        ('board_ko_pos', c_int),
        ('black_captured', c_int),
        ('white_captured', c_int),
        ('initial_board', c_int * BOARDSIZE),

        ('initial_board_ko_pos', c_int),
        ('initial_white_captured', c_int),
        ('initial_black_captured', c_int),

        ('move_history_color', c_int * MAX_MOVE_HISTORY),
        ('move_history_pos', c_int * MAX_MOVE_HISTORY),
        ('move_history_pointer', c_int),

        ('komi', c_float),
        ('move_number', c_int)
        ]


class SGFTree(Structure):
    _fields_ = [
        ('root', c_void_p), # SGFNode *root;
        ('lastnode', c_void_p) # SGFNode *lastnode;
        ]



class Goban:
    libboard = None

    def __init__(self):
        if not Goban.libboard:
            Goban.libboard = CDLL('lib/libboard.so.0.0.0')

        self.board = board_state()
        
        Goban.libboard.clear_board()


    def play_move(pos, color):
        x,y = pos
        realpos = x * 19 + y
        
        if Goban.libboard.is_legal(realpos, color):
            Goban.libboard.play_move(realpos, color)
            return True
        else:
            return False


    def undo_move(n):
        """Undo n moves. Return True on success, False on failure. On failure, no moves are removed."""
        return Goban.libboard.undo_move(n)


    def _update_board():
        """Updates our internal cache of the board state. Needed before most accessor functions."""
        Goban.libboard.store_board(self.board)


    def _restore_board():
        """Use our cached board to update libboard's internal state."""
        Goban.libboard.restore_board(self.board)


    def draw_board():
        """ Return a pygame.Surface() with an image of the board.
        If pygame isn't available, this function prints an error and returns harmlessly."""
        pass


    def draw_info():
        """ Return a pygame.Surface() with an image of text describing the game state.
        If pygame isn't available, this function prints an error and returns harmlessly."""
        pass

            
#     def draw_board(self, size, img_res):
#         ret = pygame.Surface((size,size))

#         inc = size / 19;
#         i = 0
#         for row in self.board:
#             j = 0
#             for square in row:
#                 s = img_res[square.get_draw_code()]
#                 s = pygame.transform.scale(s, (inc, inc))
#                 ret.blit(s, (j*inc,i*inc))

#                 if self.hover == square:
#                     c = img_res['bH']
#                     if self.turn == 1:
#                         c = img_res['wH']
#                     c = pygame.transform.scale(c, (inc, inc))
#                     ret.blit(c, (j*inc,i*inc))

#                 j += 1
#             i += 1

#         return ret.convert_alpha()


#     def draw_info(self):
#         textbox = pygame.Surface((150, 300))
#         textbox = textbox.convert()
#         textbox.fill((250, 250, 250))

#         font = pygame.font.Font(None, 24)
#         time = font.render('Time: {:02d}:{:02d}'.format(self.elapsed_time / 60, self.elapsed_time % 60), 1, (10, 10, 10))
#         heading = font.render('Captures', 1, (10, 10, 10))
#         black_cap = font.render('Black: {}'.format(self.captures[0]), 1, (10, 10, 10))
#         white_cap = font.render('White: {}'.format(self.captures[1]), 1, (10, 10, 10))
#         turn = font.render('Turn: {}'.format(['Black', 'White'][self.turn]), 1, (10, 10, 10))

#         textbox.blit(heading, (0, 0))
#         textbox.blit(black_cap, (0, 28))
#         textbox.blit(white_cap, (0, 56))
#         textbox.blit(turn, (0, 100))
#         textbox.blit(time, (0, 150))

#         return textbox



#         if (self.x, self.y) == (1,1):
#             self.default_draw_code = 'ul'
#         elif (self.x, self.y) == (1,19):
#             self.default_draw_code = 'ur'
#         elif (self.x, self.y) == (19,1):
#             self.default_draw_code = 'dl'
#         elif (self.x, self.y) == (19,19):
#             self.default_draw_code = 'dr'
#         elif (self.x, self.y) in [(4,4), (4,10), (4,16), (10,4), (10,10), (10,16), (16,4), (16,10), (16,16)]:
#             self.default_draw_code = 'h'
#         elif self.x == 1:
#             self.default_draw_code = 'u'
#         elif self.y == 1:
#             self.default_draw_code = 'l'
#         elif self.x == 19:
#             self.default_draw_code = 'd'
#         elif self.y == 19:
#             self.default_draw_code = 'r'
#         else:
#             self.default_draw_code = 'm'
