# Calendaring is a simple CMF/Plone calendaring implementation.
# Copyright (C) 2004 Enfold Systems
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
"""
$Id: test_model.py,v 1.3 2004/09/16 13:46:09 dreamcatcher Exp $
"""
import os, sys

if __name__ == '__main__':
    execfile(os.path.join(sys.path[0], 'framework.py'))

import unittest
from doctest import DocTestSuite
from Testing import ZopeTestCase

# Install our product
ZopeTestCase.installProduct('MimetypesRegistry')
ZopeTestCase.installProduct('PortalTransforms')
ZopeTestCase.installProduct('Archetypes')
ZopeTestCase.installProduct('Calendaring')

import datetime
from dateutil.relativedelta import relativedelta
import urllib, urlparse, cgi
from Products.Calendaring.model import SECOND, DAY
from Products.Calendaring.model.year import OneYearView
from Products.Calendaring.model.month import OneMonthView
from Products.Calendaring.model.month import ThreeMonthsView
from Products.Calendaring.model.week import OneWeekView
from Products.Calendaring.model.week import ThreeWeeksView
from Products.Calendaring.model.week import WorkdaysView
from Products.Calendaring.model.day import OneDayView
from Products.Calendaring.model.hour import OneHourView
from Products.Calendaring.model import makeRange
from OFS.SimpleItem import SimpleItem

START_DATE = datetime.datetime(2004, 4, 27, 9, 5, 40)

SUBS = {OneYearView:(12, OneMonthView),
        OneMonthView:(5, OneWeekView),
        ThreeMonthsView:(3, OneMonthView),
        OneWeekView:(7, OneDayView),
        ThreeWeeksView:(3, OneWeekView),
        WorkdaysView:(5, OneDayView),
        OneDayView:(24, OneHourView),
        OneHourView:(1, OneHourView)}

def compareURL(url, other):
    parsed_url = list(urlparse.urlparse(url))
    # get the existing query string
    qs = parsed_url[4]
    # parse the query into a dict
    first = cgi.parse_qs(qs, 1)
    # now, the same with the other
    parsed_url = list(urlparse.urlparse(other))
    # get the existing query string
    qs = parsed_url[4]
    # parse the query into a dict
    second = cgi.parse_qs(qs, 1)
    for k, v in first.items():
        if second.get(k) != v:
            return False
    return True

def getSub(instance):
    return SUBS[instance.__class__][1]

def getSubCount(instance):
    return SUBS[instance.__class__][0]

class FakeRequest:

    def __init__(self, env={}):
        self.other = {}
        self.form = {}
        self.__dict__.update(env)

class TestMakeRange(unittest.TestCase):

    def _range(self, date, unit):
        return makeRange(date, unit)

    def test_year(self):
        r = self._range
        self.assertEquals(r(START_DATE, 'year'),
                          (datetime.datetime(2004, 1, 1, 0, 0, 0),
                           datetime.datetime(2005, 1, 1, 0, 0, 0),
                           relativedelta(years=1)))
        self.assertEquals(r(datetime.datetime(2005, 1, 1, 0, 0, 0), 'year'),
                          (datetime.datetime(2005, 1, 1, 0, 0, 0),
                           datetime.datetime(2006, 1, 1, 0, 0, 0),
                           relativedelta(years=1)))

    def test_month(self):
        r = self._range
        self.assertEquals(r(START_DATE, 'month'),
                          (datetime.datetime(2004, 4, 1, 0, 0, 0),
                           datetime.datetime(2004, 5, 1, 0, 0, 0),
                           relativedelta(months=1)))
        self.assertEquals(r(datetime.datetime(2004, 5, 1, 0, 0, 0), 'month'),
                          (datetime.datetime(2004, 5, 1, 0, 0, 0),
                           datetime.datetime(2004, 6, 1, 0, 0, 0),
                           relativedelta(months=1)))

    def test_3month(self):
        r = self._range
        self.assertEquals(r(START_DATE, '3month'),
                          (datetime.datetime(2004, 3, 1, 0, 0, 0),
                           datetime.datetime(2004, 6, 1, 0, 0, 0),
                           relativedelta(months=3)))
        self.assertEquals(r(datetime.datetime(2004, 6, 1, 0, 0, 0), '3month'),
                          (datetime.datetime(2004, 5, 1, 0, 0, 0),
                           datetime.datetime(2004, 8, 1, 0, 0, 0),
                           relativedelta(months=3)))

    def test_week(self):
        r = self._range
        self.assertEquals(r(START_DATE, 'week'),
                          (datetime.datetime(2004, 4, 26, 0, 0, 0),
                           datetime.datetime(2004, 5, 3, 0, 0, 0),
                           relativedelta(days=7)))
        self.assertEquals(r(datetime.datetime(2004, 5, 2, 0, 0, 0), 'week'),
                          (datetime.datetime(2004, 4, 26, 0, 0, 0),
                           datetime.datetime(2004, 5, 3, 0, 0, 0),
                           relativedelta(days=7)))
        self.assertEquals(r(datetime.datetime(2004, 5, 3, 0, 0, 0), 'week'),
                          (datetime.datetime(2004, 5, 3, 0, 0, 0),
                           datetime.datetime(2004, 5, 10, 0, 0, 0),
                           relativedelta(days=7)))

    def test_3week(self):
        r = self._range
        self.assertEquals(r(START_DATE, '3week'),
                          (datetime.datetime(2004, 4, 19, 0, 0, 0),
                           datetime.datetime(2004, 5, 10, 0, 0, 0),
                           relativedelta(days=21)))
        self.assertEquals(r(datetime.datetime(2004, 5, 2, 0, 0, 0), '3week'),
                          (datetime.datetime(2004, 4, 19, 0, 0, 0),
                           datetime.datetime(2004, 5, 10, 0, 0, 0),
                           relativedelta(days=21)))
        self.assertEquals(r(datetime.datetime(2004, 5, 10, 0, 0, 0), '3week'),
                          (datetime.datetime(2004, 5, 3, 0, 0, 0),
                           datetime.datetime(2004, 5, 24, 0, 0, 0),
                           relativedelta(days=21)))

class TestModel(unittest.TestCase):

    factory = None

    def setUp(self):
        req = FakeRequest(env={'URL1':''})
        self.root = SimpleItem()
        self.root.REQUEST = req
        self.factory._factory_hook = getSub
        self.view = self.factory(START_DATE, START_DATE)
        self.view = self.view.__of__(self.root)

    def test_next_previous(self):
        view = self.view
        self.failUnless(isinstance(view.next(), self.factory))
        self.failUnless(isinstance(view.previous(), self.factory))
        n = view.next()
        p = view.previous()
        self.assertEquals(n.start, view.end, (view, n))
        self.assertEquals(n.end, n.start + n.resolution, n)
        self.assertEquals(p.end, view.start, (view, p))
        self.assertEquals(p.start, p.end - p.resolution, p)

    def test_sub(self):
        view = self.view
        self.assertEquals(view.sub_factory, getSub(view))
        subs = list(view.parts)
        self.assertEquals(len(subs), getSubCount(view))
        self.failUnless(isinstance(subs[0], getSub(view)))

    def test_current(self):
        view = self.view
        next = view.next()
        previous = view.previous()
        self.assertEquals(view.today, START_DATE)
        self.failUnless(view.current, view)
        self.assertEquals(next.today, START_DATE)
        self.failIf(next.current, next)
        self.assertEquals(previous.today, START_DATE)
        self.failIf(previous.current, previous)

class TestOneYearModel(TestModel):

    factory = OneYearView

    def test_next_previous_url(self):
        view = self.view
        next = view.next()
        previous = view.previous()
        got = view.next_url()
        expected = '%s?cyear=%s' % (view.name, next.start.year)
        self.failUnless(
            compareURL(got, expected), (got, expected))
        got = view.previous_url()
        expected = '%s?cyear=%s' % (view.name, previous.start.year)
        self.failUnless(
            compareURL(got, expected), (got, expected))

class TestMonthsModel(TestModel):

    factory = OneMonthView

    def test_next_previous_url(self):
        view = self.view
        next = view.next()
        previous = view.previous()
        got = view.next_url()
        expected = '%s?cyear=%s&cmonth=%s' % (view.name, next.start.year,
                                              next.start.month)
        self.failUnless(
            compareURL(got, expected), (got, expected))
        got = view.previous_url()
        expected = '%s?cyear=%s&cmonth=%s' % (view.name, previous.start.year,
                                              previous.start.month)
        self.failUnless(
            compareURL(got, expected), (got, expected))

class TestThreeMonthsModel(TestMonthsModel):

    factory = ThreeMonthsView

class TestDaysModel(TestModel):

    factory = OneDayView

    def test_next_previous_url(self):
        view = self.view
        next = view.next()
        previous = view.previous()
        got = view.next_url()
        expected = '%s?cyear=%s&cmonth=%s&cday=%s' % (view.name,
                                                   next.start.year,
                                                   next.start.month,
                                                   next.start.day)
        self.failUnless(
            compareURL(got, expected), (got, expected))
        got = view.previous_url()
        expected = '%s?cyear=%s&cmonth=%s&cday=%s' % (view.name,
                                                   previous.start.year,
                                                   previous.start.month,
                                                   previous.start.day)
        self.failUnless(
            compareURL(got, expected), (got, expected))

class TestWorkdaysModel(TestDaysModel):

    factory = WorkdaysView

    def test_next_previous(self):
        view = self.view
        self.failUnless(isinstance(view.next(), self.factory))
        self.failUnless(isinstance(view.previous(), self.factory))
        n = view.next()
        p = view.previous()
        self.assertEquals(n.start, view.end + datetime.timedelta(2), (view, n))
        self.assertEquals(n.end, n.start + n.resolution, n)
        self.assertEquals(p.end + datetime.timedelta(2), view.start, (view, p))
        self.assertEquals(p.start, p.end - p.resolution, p)

class TestOneWeekModel(TestDaysModel):

    factory = OneWeekView

class TestThreeWeeksModel(TestDaysModel):

    factory = ThreeWeeksView


class TestHoursModel(TestModel):

    factory = OneHourView

    def test_next_previous_url(self):
        view = self.view
        next = view.next()
        previous = view.previous()
        got = view.next_url()
        expected = '%s?cyear=%s&cmonth=%s&cday=%s&hour=%s' % (view.name,
                                                           next.start.year,
                                                           next.start.month,
                                                           next.start.day,
                                                           next.start.hour)
        self.failUnless(
            compareURL(got, expected), (got, expected))
        got = view.previous_url()
        expected = '%s?cyear=%s&cmonth=%s&cday=%s&hour=%s' % (view.name,
                                                           previous.start.year,
                                                           previous.start.month,
                                                           previous.start.day,
                                                           previous.start.hour)
        self.failUnless(
            compareURL(got, expected), (got, expected))


def test_suite():
    suite = unittest.TestSuite()
    suite.addTest(unittest.makeSuite(TestMakeRange))
    suite.addTest(unittest.makeSuite(TestOneYearModel))
    suite.addTest(unittest.makeSuite(TestMonthsModel))
    suite.addTest(unittest.makeSuite(TestThreeMonthsModel))
    suite.addTest(unittest.makeSuite(TestDaysModel))
    suite.addTest(unittest.makeSuite(TestWorkdaysModel))
    suite.addTest(unittest.makeSuite(TestOneWeekModel))
    suite.addTest(unittest.makeSuite(TestThreeWeeksModel))
    suite.addTest(unittest.makeSuite(TestHoursModel))
    return suite

if __name__ == '__main__':
    framework(descriptions=1, verbosity=1)
