#!/usr/bin/python

import unittest
import sys
import os
import time

sys.path.append((os.path.dirname(__file__) or '.') + '/..')
import gameclock.clock
import gameclock.game
import gameclock.i18n

class BaseClockTest(unittest.TestCase):
    """
    This is the base classe for all clock tests and shouldn't be used directly.
    """

    settings = { 'start_time': 1000 }
    decisecs = True # deciseconds, aka tenth of a second

    def setUp(self):
        self.clock = gameclock.clock.ChessClock(**self.settings)

class SimpleClockTest(BaseClockTest):
    """those are tests that don't need to be ran on all clocks"""

    def test_format(self):
        """test if the output is readable"""
        self.assertEqual(self.clock.format(), '00:01')

    def test_str(self):
        self.assertRegexpMatches(str(self.clock), 'gameclock.clock.ChessClock')

    def test_moves_format(self):
        self.assertEqual(self.clock.moves_fmt(), _('0 moves'))

class NegativeClockTest(BaseClockTest):
    settings = { 'start_time': -1000 }

    def test_format(self):
        self.assertEqual(self.clock.format(), '-00:01')

class ChessClockTest(BaseClockTest):
    """this tests the basic chess clock, but also contains tests
    which should be ran on all clocks"""

    settings = { 'start_time': 10 } # 10ms, may need to be bumped up on slow computers

    def test_start(self):
        """test if the clock starts without error and is running"""
        self.clock.start()
        self.assertTrue(self.clock.running())

    def test_stopped(self):
        """test if the clock is stopped when initialised"""
        self.assertFalse(self.clock.running())

    def test_stop(self):
        """test if the clock stops without error and is stopped"""
        self.clock.start()
        self.clock.stop()
        self.test_stopped()

    def test_dead(self):
        """test if clock is alive when started then dies after set time"""
        self.clock.start()
        self.assertFalse(self.clock.is_dead())
        time.sleep(self.settings['start_time']/1000.0)
        self.assertLess(self.clock.get_time(), 0)
        self.assertTrue(self.clock.is_dead())
        self.assertRegexpMatches(self.clock.format(), '^-')

    def test_time(self):
        """test if the current time makes sense"""
        self.assertEqual(self.clock.get_time(), self.settings['start_time'])
        self.clock.start()
        time.sleep(0.010) # 10ms
        self.assertLess(self.clock.get_time(), self.settings['start_time'])

    def test_turn_one(self):
        """test if the first turn is turn 0"""
        self.clock.start()
        self.assertEqual(self.clock.moves, 0)

class FischerChessClockTest(ChessClockTest):
    settings = { 'start_time': 10, 'delay': 1000 }

    def setUp(self):
        self.clock = gameclock.clock.FischerChessClock(**self.settings)

    def test_stop_fischer(self):
        """test that stop adds time to the clock"""
        self.clock.stop()
        self.assertEqual(self.clock.get_time(), self.settings['start_time'] + self.settings['delay'])

class BoardClockTest(ChessClockTest):
    def setUp(self):
        self.clock = gameclock.clock.BoardClock(**self.settings)

    def test_stop_board(self):
        """test that stop resets the clock"""
        self.test_time() # safety check, but also expected to start the clock
        self.clock.stop()
        self.assertEqual(self.clock.get_time(), self.settings['start_time'])

class HourglassClockTest(ChessClockTest):
    def setUp(self):
        self.clock = gameclock.clock.HourglassClock(**self.settings)

    def test_stop(self):
        """test that time goes backwards when the clock is stopped"""
        self.test_time() # safety check, but also expected to start the clock
        self.clock.stop()
        time.sleep(0.100) # 100ms, should be enough to go backwards
        self.assertGreater(self.clock.get_time(), self.settings['start_time'])

class GoStandardByoyomiClockTest(ChessClockTest):
    settings = { 'start_time': 100, 'byoyomi': 2, 'delay': 50 } # 100ms, 2 byoyomis, 10ms

    def setUp(self):
        self.clock = gameclock.clock.GoStandardByoyomiClock(**self.settings)

    def test_dead(self):
        self.clock.start()
        self.assertFalse(self.clock.is_dead(), "game should start alive")
        self.assertFalse(self.clock.is_byoyomi(), "we shouldn't be in byoyomi yet")
        time.sleep(0.110) # 110 ms should cross the above 100ms
        self.assertEqual(self.clock.get_byoyomi(), self.settings['byoyomi'], "we should be in our first byoyomi: %d" % self.clock.get_byoyomi())
        self.assertTrue(self.clock.is_byoyomi(), "we should be in a byoyomi however")
        self.assertFalse(self.clock.is_dead(), "go games have a byoyomi after regular time, so this should not die just yet")
        time.sleep(0.110) # 110 ms should cross the first byoyomi, but not die yet
        self.assertEqual(self.clock.get_byoyomi(), self.settings['byoyomi'] - 1, "we should be in our second byoyomi: %d" % self.clock.get_byoyomi())
        self.assertTrue(self.clock.is_byoyomi(), "we should be in a byoyomi however")
        self.assertFalse(self.clock.is_dead(), "go games have a byoyomi after regular time, so this should not die just yet (clock time: %d, byoyomis: %d)" % (self.clock.time, self.clock.get_byoyomi()))
        time.sleep(0.110) # 110 ms should cross the first byoyomi, but not die yet
        self.assertEqual(self.clock.get_byoyomi(), 0, "we should be in our last byoyomi")
        self.assertTrue(self.clock.is_dead(), "we have crossed the byoyomi, we should die")
        self.assertEqual(self.clock.get_byoyomi(), 0, "we should STILL be in our last byoyomi")

    def test_stop_go(self):
        """test that the clock doesn't reset for nothing"""
        self.clock.start()
        self.clock.stop()
        self.assertLess(self.clock.get_time(), self.settings['start_time'])
        self.assertNotEqual(self.clock.get_time(), self.settings['delay'])
        self.assertFalse(self.clock.is_byoyomi(), "we shouldn't be in byoyomi yet")

    def test_moves_format(self):
        self.assertEqual(self.clock.moves_fmt(), _('0 moves'))
        self.clock.start()
        time.sleep(0.110)
        self.assertEqual(self.clock.moves_fmt(), _('0 moves 2 byoyomis'))
        time.sleep(0.110)
        self.assertEqual(self.clock.moves_fmt(), _('0 moves 1 byoyomi'))
        time.sleep(0.110)
        self.assertEqual(self.clock.moves_fmt(), _('0 moves 0 byoyomis (lost)'))


class WeirdGoStandardByoyomiClockTest(BaseClockTest):
    settings = { 'start_time': 100, 'byoyomi': 1, 'delay': 50 } # 100ms, 2 byoyomis, 10ms

    def setUp(self):
        self.clock = gameclock.clock.GoStandardByoyomiClock(**self.settings)

    def test_die_clock(self):
        """test that the clock dies in the last byoyomi"""
        self.clock.start()
        self.assertFalse(self.clock.is_dead(), "game should start alive")
        self.assertFalse(self.clock.is_byoyomi(), "we shouldn't be in byoyomi yet")
        time.sleep(0.100)
        self.assertTrue(self.clock.is_byoyomi(), "we should be in a byoyomi now")
        self.assertEqual(self.clock.get_byoyomi(), 1, "we should be in our first byoyomi: %d" % self.clock.get_byoyomi())
        time.sleep(0.05)
        self.assertLess(self.clock.get_time(), 0)
        self.assertEqual(self.clock.get_byoyomi(), 0, "we should be in our second byoyomi: %d" % self.clock.get_byoyomi())
        self.assertTrue(self.clock.is_dead())
        self.assertTrue(gameclock.clock.Clock.is_dead(self.clock), "time clock should also die when byoyomi")



if __name__ == '__main__':
    unittest.main()
