#!/usr/bin/python

import unittest
import sys
import os
import time
import gtk
import gobject

sys.path.append((os.path.dirname(__file__) or '.') + '/..')
from gameclock.gtkui import GameclockUI, ClockUI
from gameclock.clock import ChessClock
from gameclock.game import *

class BaseGtkUITest(unittest.TestCase):
    """base class for UI tests, will not be called directly"""
    def refresh_gui(self, delay=0):
        """process gtk events

The idea here is to do this without entering the main loop and loosing
control. Taken from
http://unpythonic.blogspot.ca/2007/03/unit-testing-pygtk.html and
ultimately http://www.async.com.br/projects/kiwi/.
"""
        while gtk.events_pending():
            gtk.main_iteration_do(block=False)
        time.sleep(delay)
        self.ui.refresh_current()

class TimeoutHandlerUITest(BaseGtkUITest):
    def notice_cb(self):
        self.noticed += 1

    def setUp(self):
        self.noticed = 0
        self.timeout_source = gobject.timeout_add(10, self.notice_cb)

    @unittest.expectedFailure
    def test_cb(self):
        """test if the callback gets called in unit tests by the timeout handler"""
        self.refresh_gui(0.100)
        self.assertGreater(self.noticed, 0)

class DummyGameclockUI(GameclockUI):
    """a dumber GameclockUI that doesn't fire up all those windows"""
    def __init__(self, players = RegularChessGame.players, time = RegularChessGame.time):
        GameclockUI.__init__(self, players = players, time = time)

    #def debug(self, msg):
    #    print msg

class ClockUITest(BaseGtkUITest):
    settings = {'start_time': 100}

    def setUp(self):
        self.clockui = ClockUI(DummyGameclockUI(), ChessClock(**self.settings))

    def test_refresh(self):
        """test if label displays the right time after refresh"""
        self.clockui.refresh()
        self.assertEqual(self.clockui.label.get_label(), self.clockui.clock.format(self.clockui.format))

class BaseGameclockUITest(BaseGtkUITest):
    """base class for GameclockUI tests, will not be called directly"""
    settings = { 'players': RegularChessGame.players, 'time': RegularChessGame.time }

    def setUp(self):
        self.ui = DummyGameclockUI(**self.settings)
        self.ui.setup_clocks()

class GameclockUITest(BaseGameclockUITest):
    def test_setup(self):
        """test if clock setup sets the right number of clocks"""
        self.assertEqual(len(self.ui.clock_table.get_children()), self.ui.game.players)
        self.assertEqual(self.ui.clock_table.get_property('n-rows'), self.ui.game.players/2)
        self.assertEqual(self.ui.clock_table.get_property('n-columns'), 2)
        # iterate through the list and make sure we have the right count
        p = self.ui.cur_clock
        i = 0
        while p:
            p = p.next
            i += 1
        self.assertEqual(i, self.ui.game.players)

    def test_setup_twice(self):
        """test for bug #9658 - make sure we can recreate functional clocks"""
        game = self.ui.game # keep a backup
        self.refresh_gui(0.100) # 100ms
        self.ui.move()
        self.refresh_gui(0.100) # 100ms
        clockui = self.ui.cur_clock
        # create a *second* game, which is what handle_new_dialog is doing in effect
        self.ui.game = RegularChessGame(**self.settings)
        self.ui.setup_clocks()
        self.refresh_gui(0.100) # 100ms
        # those should be different clocks
        self.assertNotEqual(game.cur_clock, self.ui.game.cur_clock)
        self.assertEqual(self.ui.cur_clock.label.get_label(), '60:00')
        self.assertTrue(self.ui.cur_clock in self.ui.clock_table.get_children())
        # this old clock widget should be gone
        self.assertFalse(clockui in self.ui.clock_table.get_children())

    def test_time_passing(self):
        self.assertFalse(self.ui.game.running())
        self.ui.handle_move() # should start the game
        self.assertTrue(self.ui.game.running())
        self.assertTrue(self.ui.cur_clock.clock.running())
        self.assertFalse(self.ui.first_clock.clock.running())
        self.assertNotEqual(self.ui.cur_clock, self.ui.first_clock)
        self.refresh_gui(0.100)
        self.assertEqual(self.ui.cur_clock.label.get_label(), '59:59')
        self.refresh_gui(1.000)
        self.assertEqual(self.ui.cur_clock.label.get_label(), '59:58')
        self.assertLess(self.ui.cur_clock.clock.get_time(), 60 * 60 * 1000)

class SinglePlayerGameclockUITest(BaseGameclockUITest):
    settings = { 'players': 1, 'time': RegularChessGame.time }

    def test_setup(self):
        self.assertEqual(len(self.ui.clock_table.get_children()), self.ui.game.players)
        #self.assertEqual(self.ui.clock_table.get_property('n-rows'), self.ui.game.players/2)
        self.assertEqual(self.ui.clock_table.get_property('n-columns'), 2)
        # iterate through the list and make sure we have the right count
        p = self.ui.first_clock
        i = 0
        while p:
            p = p.next
            i += 1
        self.assertEqual(i, 1)
        p = self.ui.game.first_clock
        i = 0
        while p:
            p = p.next
            i += 1
        self.assertEqual(i, 1)

    def test_time_passing(self):
        self.assertFalse(self.ui.game.running())
        self.ui.handle_move() # should start the game
        self.assertTrue(self.ui.game.running())
        self.assertTrue(self.ui.cur_clock.clock.running())
        self.assertTrue(self.ui.first_clock.clock.running())
        self.assertEqual(self.ui.cur_clock, self.ui.first_clock)
        self.refresh_gui(0.100)
        self.assertEqual(self.ui.cur_clock, self.ui.first_clock)
        self.assertEqual(self.ui.cur_clock.label.get_label(), '59:59')
        self.refresh_gui(1.000)
        self.assertEqual(self.ui.cur_clock.label.get_label(), '59:58')
        self.assertLess(self.ui.cur_clock.clock.get_time(), 60 * 60 * 1000)

class HourglassUITest(BaseGameclockUITest):
    def setUp(self):
        self.ui = DummyGameclockUI(**self.settings)
        self.ui.game = HourglassGame()
        self.ui.setup_clocks()
        self.ui.refresh()

    def test_first_clock_increments(self):
        """check that the first clock goes up while the other one goes down"""
        self.ui.handle_move()
        self.refresh_gui(0.100)
        self.assertGreater(self.ui.first_clock.clock.get_time(), 60000)
        self.ui.handle_move()
        self.refresh_gui(0.100)
        self.ui.handle_move()
        self.refresh_gui(0.200)
        self.assertGreater(self.ui.first_clock.clock.get_time(), 60000)

class ThreePlayerUITest(BaseGameclockUITest):
    def setUp(self):
        self.ui = DummyGameclockUI(**self.settings)
        self.ui.game.resize(3)
        self.ui.setup_clocks()
        self.ui.refresh()

    def test_third_player(self):
        first_clockui = self.ui.cur_clock
        first_clock = self.ui.cur_clock.clock
        self.assertEqual(self.ui.game.cur_clock, self.ui.cur_clock.clock, "the game agrees with the UI about the current clock")
        self.assertFalse(self.ui.game.running(), 'the game starts stopped')
        self.ui.handle_move()
        self.assertEqual(self.ui.game.cur_clock, self.ui.cur_clock.clock, "the game agrees with the UI about the current clock")
        self.refresh_gui(0.100)
        self.assertLess(self.ui.cur_clock.clock.get_time(), 60 * 60 * 1000, 'time has passed on the second clock')
        self.ui.handle_move()
        self.assertEqual(self.ui.game.cur_clock, self.ui.cur_clock.clock, "the game agrees with the UI about the current clock")
        self.ui.handle_move()
        self.refresh_gui(0.100) # 1 second, for the counter of the first clock to change
        self.assertTrue(self.ui.game.running(), 'the game is still running')
        self.assertEqual(self.ui.game.first_clock, self.ui.game.cur_clock, 'the game engine is on the first clock')
        self.assertEqual(self.ui.cur_clock, self.ui.first_clock, 'we are back on the first clock after three moves')
        self.assertEqual(self.ui.cur_clock, first_clockui, "it's the same clockUI as when we started")
        self.assertEqual(self.ui.game.cur_clock, self.ui.cur_clock.clock, "the game agrees with the UI about the current clock")
        self.assertEqual(self.ui.cur_clock.clock, first_clock, "it's the same clock too")
        self.assertTrue(self.ui.cur_clock.clock.running(), "that clock is running")
        self.assertLess(self.ui.cur_clock.clock.get_time(), 60 * 60 * 1000, "the clock has passed some time")
        self.assertNotEqual(self.ui.cur_clock.label.get_label(), '60:00')

class ShortGameclockUITest(BaseGameclockUITest):
    """test code for games shorter than 60 seconds"""
    settings = { 'players': RegularChessGame.players, 'time': 59000 }

    def test_dc_start(self):
        """test if the display is showing tenths of a second if the game is started with less than 60 seconds"""
        self.assertEqual(self.ui.cur_clock.label.get_label(), '00:59.0')

class GameclockMenuUITest(BaseGameclockUITest):
    """test the menus generated by the constructor"""

    def debug(self, s):
        print s.name

    def assertRadio(self, m):
        self.debug(m)
        print repr(m)
        if m.name is not None:
            self.assertEqual(m.__class__.__name__, 'RadioMenuItem')

    @unittest.expectedFailure
    def test_radio_menu(self):
        """for some reason, the new radio items are not radios... """
        found_games = False
        for m in self.ui.menubar.get_children():
            for n in m.get_submenu().get_children():
                if n.name == 'new':
                    for g in n.get_submenu().get_children():
                        if g.name is not None:
                            found_games = True
                            self.assertEqual(m.__class__.__name__, 'RadioMenuItem')
        self.assertTrue(found_games)

    def test_sort_menu(self):
        """make sure the new menu is sorted"""
        found_games = False
        n = self.ui.uimanager.get_widget('/menubar/game/new')
        previous = ''
        for g in n.get_submenu().get_children():
            if g.name is not None:
                found_games = True
                self.assertLess(previous, g.get_label())
                previous = g.get_label()
        self.assertTrue(found_games)

class StyleTest(unittest.TestCase):
    """basic gtk self-tests so i understand how the style shit works"""

    def setUp(self):
        # we draw colors in evenboxes around here
        self.e = gtk.EventBox()
        self.e.show()
        # we need to wrap this in a window for some obscure reason
        self.w = gtk.Window()
        self.w.add(self.e)
        self.w.realize()

    def test_color_change(self):
        """make sure our own logic for checking background colors is sound"""
        self.e.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color('green'))
        self.assertEqual(self.e.style.bg[gtk.STATE_NORMAL], gtk.gdk.Color('green'))

    def test_style_change(self):
        """check if we can change the color with modify_style()"""
        style = gtk.RcStyle()
        style.bg[gtk.STATE_NORMAL] = gtk.gdk.Color('green')
        self.e.modify_style(style)
        self.assertEqual(self.e.style.bg[gtk.STATE_NORMAL], gtk.gdk.Color('green'))

class GtkUiStyleTest(BaseGameclockUITest):

    def test_green(self):
        """make sure we can change the theme manually"""
        gtk.rc_parse_string("""
style "clockui" {
  bg[NORMAL] = "black"
  fg[NORMAL] = "white"
  bg[SELECTED] = "green"
  fg[SELECTED] = "black"
  bg[ACTIVE] = "red"
  fg[ACTIVE] = "black"
}

widget "*EventBox" style "clockui"
""")
        self.ui.refresh()
        self.ui.window.realize() # hack to make sure the window is drawn, but without showing it.
        self.assertEqual(self.ui.cur_clock.evbox.style.bg[gtk.STATE_NORMAL], gtk.gdk.Color('black'))
        self.assertEqual(self.ui.cur_clock.evbox.style.bg[gtk.STATE_SELECTED], gtk.gdk.Color('green'))
        self.assertEqual(self.ui.cur_clock.evbox.style.bg[gtk.STATE_ACTIVE], gtk.gdk.Color('red'))
