import os
import sys
import math

import pygame
from pygame.locals import *
import sgc
from sgc.locals import *
import socket

import goban
import gtpsocket
import networkthread


class GUI:
    def __init__(self, goban, settings):
        # Basic screen init
        pygame.init()
        pygame.fastevent.init()
        # screen = pygame.display.set_mode((1000, 800))
        self.screen = sgc.surface.Screen((1000,800))
        pygame.display.set_caption('pyGo')
        
        # SGC font color
        sgc.Font.col = (10,10,10)
    
        # Create the background object, make it blank
        # background = pygame.Surface(screen.get_size())
        # background = background.convert()
        # background.fill((250, 250, 250))

        # Build the dict of image objects
        self.img_res = _build_img_res()

        self.goban = goban
        self.settings = settings

        # Network-related settings
        self.net_thread = None
        self.socket = None
        self.network_mode = False
        self.our_color = None


        self.board_size = 800
        self.board_inc = self.board_size / 19

        self.screen.fill((250, 250, 250))

        self.join_btn = sgc.widgets.Button(label="Join Game", pos=(850,400))
        self.join_btn.activate = self.join_game
        self.join_btn.add()

        self.wait_btn = sgc.widgets.Button(label="Listen", pos=(850,475))
        self.wait_btn.activate = self.wait_for_game
        self.wait_btn.add()
    
        self.pass_btn = sgc.widgets.Button(label="Pass", pos=(850,550))
        self.pass_btn.activate = goban.pass_move
        self.pass_btn.add()

        self.resign_btn = sgc.widgets.Button(label="Resign", pos=(850,625))
        self.resign_btn.activate = goban.resign
        self.resign_btn.add()

        self.quit_btn = sgc.widgets.Button(label="Quit", pos=(850,700))
        self.quit_btn.activate = sys.exit
        self.quit_btn.add()

        wait_label = sgc.widgets.Label(text='Waiting for a connection')
        self.wait_dialog = sgc.widgets.Dialog(title="Please wait...", widget=wait_label)
        self.wait_dialog.rect.center = self.screen.rect.center

        # Generate a spurious event 5 times a second, to force an 'fps' of 5
        pygame.time.set_timer(USEREVENT, 200)


    def do_event(self):
        event = pygame.fastevent.wait()
        sgc.widgets.event(event)

        if event.type == QUIT:
            return
        
        if self.network_mode:
            # This set of events should only be called if we can currently play
            if self.goban.to_move == self.our_color:
                # Hover a transparent stone over our cursor position, assuming play is legal
                if event.type == MOUSEMOTION:
                    with self.net_thread.goban_lock:
                        self.do_hover(event)

                if event.type == MOUSEBUTTONDOWN:
                    x, y = event.pos
                    row = y / self.board_inc
                    col = x / self.board_inc

                    if x <= self.board_size:
                        if event.button == 1:
                            with self.net_thread.send_lock:
                                col_letter = chr(col + 96)
                                self.socket.send(col_letter + str(row))
                            self.goban.play_move((row, col))

        # Local play mode
        else:
            # Hover a transparent stone over our
            # cursor position, assuming play is legal
            if event.type == MOUSEMOTION:
                self.do_hover(event)

            # Place a stone on left-click
            if event.type == MOUSEBUTTONDOWN:
                x, y = event.pos
                row = y / self.board_inc
                col = x / self.board_inc

                if x < self.board_size and y < self.board_size:
                    if event.button == 1:
                        self.goban.play_move((row, col))

        # if event.type == USEREVENT:
        #     goban.elapsed_time += 1

        # Cleanup removed windows
        # for widget in dialogs:
        #     if not widget.active():
        #         dialogs.remove(widget)


    def update(self):
        board = self.goban.draw_board(self.board_size, self.img_res)
        self.screen.blit(board, (0,0))
    
        text = self.goban.draw_info()
        self.screen.blit(text, (815, 25))

        sgc.widgets.update(0)
        pygame.display.flip()


    # fixme: this uses localhost as a stub
    def join_game(self):
        try:
            sock = socket.create_connection(("127.0.0.1", 6859))
        except socket.error as exception:
            print 'Error: Socket creation failed: {}'.format(exception.args)
        else:
            sock.setblocking(0)
            self.socket = gtpsocket.GTPSocket(sock)
            self.net_thread = networkthread.NetworkThread(self.goban, sock)
            self.net_thread.start()
            self.network_mode = True
            self.our_color = goban.Goban.BLACK


    # fixme: this uses localhost as a stub
    def wait_for_game(self):
        self.wait_dialog.add()
        self.update()

        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.bind(("127.0.0.1", 6859))
            sock.listen(1)
            conn, addr = sock.accept()
            conn.setblocking(0)
            sock.close()
        except socket.error as exception:
            print 'Error: Socket creation failed: {}'.format(exception.args)
        else:
            self.socket = gtpsocket.GTPSocket(conn)
            self.net_thread = networkthread.NetworkThread(self.goban, conn)
            self.net_thread.start()
            self.network_mode = True
            self.our_color = goban.Goban.WHITE
        finally:
            self.wait_dialog.remove()
            self.update()


    def do_hover(self, event):
        x, y = event.pos
        row = y / self.board_inc
        col = x / self.board_inc

        if _magnitude(event.rel) < 3:
            if x < self.board_size and y < self.board_size:
                self.goban.set_hover((row,col))
            else:
                self.goban.clear_hover()

        elif self.goban.hover != self.goban._real_pos((row,col)):
            self.goban.clear_hover()




def _magnitude(vector):
    x,y = vector
    return math.sqrt(x*x + y*y)


def _load_png(name, alpha=None):
    """ Load image and return image object"""
    fullname = os.path.join('res', name)

    try:
        image = pygame.image.load(fullname)
        if image.get_alpha() is None:
            image = image.convert()
        else:
            image = image.convert_alpha()

        if alpha is not None:
            image.set_alpha(alpha)

    except pygame.error, message:
        print 'Cannot load image:', fullname
        raise SystemExit, message

    return image


def _build_img_res():
    ret = {}
    
    triangle = _load_png('go_t.png')
    
    ret['w'] = _load_png('go_w.png')
    ret['wT'] = _load_png('go_w.png')
    ret['wT'].blit(triangle, (0,0))
    ret['wH'] = _load_png('go_w.png', 128)

    ret['b'] = _load_png('go_b.png')
    ret['bT'] = _load_png('go_b.png')
    ret['bT'].blit(triangle, (0,0))
    ret['bH'] = _load_png('go_b.png', 128)

    circle = _load_png('go_c.png')

    for d in ('u', 'd', 'l', 'r', 'm', 'dl', 'dr', 'ul', 'ur', 'h'):
        ret[d] = _load_png('go_' + d + '.png')
        ret[d + 'C'] = _load_png('go_' + d + '.png')
        ret[d + 'C'].blit(circle, (0,0))
        
    return ret