class TestDateTimeProxies(TestCase):
    def setUp(self):
        translation.activate('en_GB')
        self.datetime = datetime(1982, 8, 17)
        self.year     = Year(self.datetime)
        self.month    = Month(self.datetime)
        self.week     = Week(self.datetime)
        self.day      = Day(self.datetime)
        self.hour     = Hour(datetime.combine(self.datetime.date(), time(6, 30, 5)))

    def tearDown(self):
        translation.deactivate()

    def test_default_datetimeproxy_conversion(self):
        mapping = (
            (date(1982, 8, 17), datetime(1982, 8, 17)),
            (datetime(1982, 8, 17, 6), datetime(1982, 8, 17, 6, 0, 0)),
            (datetime(1982, 8, 17, 6, 30), datetime(1982, 8, 17, 6, 30, 0)),
            (datetime(1982, 8, 17, 6, 30, 5), datetime(1982, 8, 17, 6, 30, 5)),
        )
        for inp, expected in mapping:
            assert_equal(Period(inp).start, expected)

    def test_hour_equality(self):
        equal = (
            datetime(1982, 8, 17, 6, 30, 5),
            datetime(1982, 8, 17, 6, 0, 0),
            datetime(1982, 8, 17, 7, 0, 0) - timedelta.resolution,
        )
        not_equal = (
            date(1982, 8, 17),
            datetime(1982, 8, 17, 6, 0, 0) - timedelta.resolution,
            datetime(1982, 8, 17, 7, 0, 0),
        )
        for dt in equal:
            assert_equal(self.hour, dt)
            assert self.hour >= dt
            assert self.hour <= dt
            assert dt in self.hour
        for dt in not_equal:
            assert_not_equal(self.hour, dt)
            assert_false(dt in self.hour)

    def test_day_equality(self):
        equal = (
            date(1982, 8, 17),
            datetime(1982, 8, 17),
            datetime(1982, 8, 17, 0, 0, 1),
            datetime(1982, 8, 17, 12, 30, 33),
            datetime(1982, 8, 18) - timedelta.resolution,
        )
        not_equal = (
            date(1982, 8, 16),
            date(1982, 8, 18),
            datetime(1982, 8, 16),
            datetime(1982, 8, 17) - timedelta.resolution,
            datetime(1982, 8, 18),
        )
        for dt in equal:
            assert_equal(self.day, dt)
            assert self.day >= dt
            assert self.day <= dt
            assert dt in self.day
        for dt in not_equal:
            assert_not_equal(self.day, dt)
            assert_false(dt in self.day)

    def test_week_equality(self):
        equal = (
            date(1982, 8, 16),
            date(1982, 8, 22),
            datetime(1982, 8, 16),
            datetime(1982, 8, 23) - timedelta.resolution,
        )
        not_equal = (
            date(1982, 8, 15),
            date(1982, 8, 23),
            datetime(1982, 8, 16) - timedelta.resolution,
            datetime(1982, 8, 23),
        )
        for dt in equal:
            assert_equal(self.week, dt)
            assert self.week >= dt
            assert self.week <= dt
            assert dt in self.week
        for dt in not_equal:
            assert_not_equal(self.week, dt)
            assert_false(dt in self.week)

    def test_month_equality(self):
        equal = (
            self.datetime.date(),
            date(1982, 8, 1),
            date(1982, 9, 1) - timedelta(1),
            self.datetime,
            datetime(1982, 8, 1),
            datetime(1982, 9, 1) - timedelta.resolution,
        )
        not_equal = (
            date(1982, 8, 1) - timedelta(1),
            date(1982, 9, 1),
            datetime(1982, 8, 1) - timedelta.resolution,
            datetime(1982, 9, 1),
        )
        for dt in equal:
            assert_equal(self.month, dt)
            assert self.month >= dt
            assert self.month <= dt
            assert dt in self.month
        for dt in not_equal:
            assert_not_equal(self.month, dt)
            assert_false(dt in self.month)

    def test_year_equality(self):
        equal = (
            date(1982, 1, 1),
            date(1982, 12, 31),
            datetime(1982, 1, 1),
            datetime(1983, 1, 1) - timedelta.resolution,
        )
        not_equal = (
            date(1982, 1, 1) - timedelta(1),
            date(1982, 12, 31) + timedelta(1),
            datetime(1982, 1, 1) - timedelta.resolution,
            datetime(1983, 1, 1),
        )
        for dt in equal:
            assert_equal(self.year, dt)
            assert self.year >= dt
            assert self.year <= dt
            assert dt in self.year
        for dt in not_equal:
            assert_not_equal(self.year, dt)
            assert_false(dt in self.year)

    def test_membership(self):
        for i in (self.hour, self.day, self.week, self.month, self.year):
            assert i in self.year
        for i in (self.hour, self.day, self.week, self.month):
            assert i in self.month
        for i in (self.hour, self.day, self.week):
            assert i in self.week
        for i in (self.hour, self.day,):
            assert i in self.day
        for i in (self.hour,):
            assert i in self.hour


        class TenMinuteInterval(Period):
            interval = timedelta(minutes=10)
            def convert(self, dt):
                dt = super(TenMinuteInterval, self).convert(dt)
                return dt.replace(second=0)

        ten_min_period = TenMinuteInterval(datetime(1982, 8, 17, 6, 30, 5))
        good_inputs = (
            datetime(1982, 8, 17, 6, 30),
            datetime(1982, 8, 17, 6, 35),
            datetime(1982, 8, 17, 6, 40) - timedelta.resolution,
        )
        bad_inputs = (
            date(1982, 8, 17),
            datetime(1982, 8, 17, 6, 30) - timedelta.resolution,
            datetime(1982, 8, 17, 6, 40),
        )
        for inp in good_inputs:
            assert_in(inp, ten_min_period)
        for inp in bad_inputs:
            assert_not_in(inp, ten_min_period)

    def test_next(self):
        assert_equal(self.hour.next(),  datetime(1982, 8, 17, 7, 30, 5))
        assert_equal(self.day.next(),   datetime(1982, 8, 18))
        assert_equal(self.week.next(),  datetime(1982, 8, 24))
        assert_equal(self.month.next(), datetime(1982, 9, 17))
        assert_equal(self.year.next(),  datetime(1983, 8, 17))
        assert isinstance(self.hour.next(),  Hour)
        assert isinstance(self.day.next(),   Day)
        assert isinstance(self.week.next(),  Week)
        assert isinstance(self.month.next(), Month)
        assert isinstance(self.year.next(),  Year)

    def test_previous(self):
        assert_equal(self.hour.previous(),  datetime(1982, 8, 17, 5, 30, 5))
        assert_equal(self.day.previous(),   datetime(1982, 8, 16))
        assert_equal(self.week.previous(),  datetime(1982, 8, 10))
        assert_equal(self.month.previous(), datetime(1982, 7, 17))
        assert_equal(self.year.previous(),  datetime(1981, 8, 17))
        assert isinstance(self.hour.previous(),  Hour)
        assert isinstance(self.day.previous(),   Day)
        assert isinstance(self.week.previous(),  Week)
        assert isinstance(self.month.previous(), Month)
        assert isinstance(self.year.previous(),  Year)

    def test_day_hours_iteration(self):
        expected = list(rrule(HOURLY,
            dtstart=datetime(1982, 8, 17),
            until=datetime(1982, 8, 17, 23, 59, 59)
        ))
        actual = list(i for i in self.day.hours)
        assert_equal(expected, actual)
        assert all(isinstance(i, Hour) for i in actual)

    def test_week_days_iterator(self):
        start = datetime(1982, 8, 16) # monday
        expected = list(rrule(DAILY,
            dtstart=start,
            until=(start + timedelta(7)) - timedelta.resolution
        ))
        actual = list(i for i in self.week.days)
        assert_equal(expected, actual)
        assert all(isinstance(i, Day) for i in actual)

    def test_month_weeks_iterator(self):
        expected = list(rrule(WEEKLY,
            dtstart=datetime(1982, 8, 1),
            until=datetime(1982, 8, 31)
        ))
        actual = list(i for i in self.month.weeks)
        assert_equal(expected, actual)
        assert all(isinstance(i, Week) for i in actual)

    def test_month_days_iterator(self):
        expected = list(rrule(DAILY,
            dtstart=datetime(1982, 8, 1),
            until=datetime(1982, 8, 31)
        ))
        actual = list(i for i in self.month.days)
        assert_equal(expected, actual)
        assert all(isinstance(i, Day) for i in actual)

    def test_year_months_iterator(self):
        expected = list(rrule(MONTHLY,
            dtstart=datetime(1982, 1, 1),
            until=datetime(1982, 12, 31)
        ))
        actual = list(self.year.months)
        assert_equal(expected, actual)
        assert all(isinstance(i, Month) for i in actual)

    def test_year_days_iterator(self):
        expected = list(rrule(DAILY,
            dtstart=datetime(1982, 1, 1),
            until=datetime(1982, 12, 31)
        ))
        actual = list(self.year.days)
        assert_equal(expected, actual)
        assert all(isinstance(i, Day) for i in actual)

    def test_day_iteration_returns_hours(self):
        assert_equal(list(self.day), list(self.day.hours))

    def test_week_iteration_returns_days(self):
        assert_equal(list(self.week), list(self.week.days))

    def test_month_iteration_returns_weeks(self):
        assert_equal(list(self.month), list(self.month.weeks))

    def test_year_iteration_returns_months(self):
        assert_equal(list(self.year), list(self.year.months))

    def test_names_property(self):
        dayname = calendar.day_name[self.datetime.weekday()]
        assert_equal(dayname, self.day.name)
        assert_equal('August', self.month.name)

    def test_abbr_property(self):
        abbr = calendar.day_abbr[self.datetime.weekday()]
        assert_equal(abbr, self.day.abbr)
        assert_equal('aug', self.month.abbr)

    def test_start_property(self):
        assert_equal(self.hour.start,  datetime(1982, 8, 17, 6))
        assert_equal(self.day.start,   datetime(1982, 8, 17))
        assert_equal(self.week.start,  datetime(1982, 8, 16))
        assert_equal(self.month.start, datetime(1982, 8, 1))
        assert_equal(self.year.start,  datetime(1982, 1, 1))

    def test_finish_property(self):
        smidge = timedelta.resolution
        assert_equal(self.hour.finish,  datetime(1982, 8, 17, 7) - smidge)
        assert_equal(self.day.finish,   datetime(1982, 8, 18) - smidge)
        assert_equal(self.week.finish,  datetime(1982, 8, 23) - smidge)
        assert_equal(self.month.finish, datetime(1982, 9, 1) - smidge)
        assert_equal(self.year.finish,  datetime(1983, 1, 1) - smidge)

    def test_number_property(self):
        assert_equal(self.hour.number,  6)
        assert_equal(self.day.number,   17)
        assert_equal(self.week.number,  self.datetime.isocalendar()[1])
        assert_equal(self.month.number, 8)
        assert_equal(self.year.number,  1982)

    def test_get_methods_for_more_general_periods(self):
        assert not hasattr(self.hour, 'get_hour')
        assert_equal(self.hour.get_day(), self.day)
        assert_equal(self.hour.get_week(), self.week)
        assert_equal(self.hour.get_month(), self.month)
        assert_equal(self.hour.get_year(), self.year)

        assert not hasattr(self.day, 'get_hour')
        assert not hasattr(self.day, 'get_day')
        assert_equal(self.day.get_week(), self.week)
        assert_equal(self.day.get_month(), self.month)
        assert_equal(self.day.get_year(), self.year)

        assert not hasattr(self.week, 'get_hour')
        assert not hasattr(self.week, 'get_day')
        assert not hasattr(self.week, 'get_week')
        assert_equal(self.week.get_month(), self.month)
        assert_equal(self.week.get_year(), self.year)

        assert not hasattr(self.month, 'get_hour')
        assert not hasattr(self.month, 'get_day')
        assert not hasattr(self.month, 'get_week')
        assert not hasattr(self.month, 'get_month')
        assert_equal(self.month.get_year(), self.year)

        assert not hasattr(self.year, 'get_hour')
        assert not hasattr(self.year, 'get_day')
        assert not hasattr(self.year, 'get_week')
        assert not hasattr(self.year, 'get_month')
        assert not hasattr(self.year, 'get_year')

    def test_month_calendar_display_property(self):
        expected = calendar.monthcalendar(self.datetime.year, self.datetime.month)
        actual = self.month.calendar_display
        actual = [[i.day if i else 0 for i in lst] for lst in actual]
        assert_equal(expected, actual)

    def test_intervals(self):
        intervals = self.day.intervals
        expected_start = datetime.combine(
            self.datetime.date(), defaults.TIMESLOT_START_TIME
        )
        expected_end = expected_start + defaults.TIMESLOT_END_TIME_DURATION
        assert_equal(intervals[0],  expected_start)
        assert_equal(intervals[-1], expected_end)

        expected_interval_count = 0
        while expected_start <= expected_end:
            expected_start += defaults.TIMESLOT_INTERVAL
            expected_interval_count += 1
        assert_equal(len(intervals), expected_interval_count)