# 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: _base.py,v 1.5 2005/01/11 00:26:34 dreamcatcher Exp $
"""
import urllib
from datetime import datetime
from Acquisition import Implicit, aq_inner, aq_parent
from ComputedAttribute import ComputedAttribute
from Products.CMFCore.utils import getToolByName
from Products.Calendaring.model import makeRange, DAY, getView, SECOND
from Products.Calendaring.common import dt2DT, DT2dt, toSeconds

ARG_NAMES = ['cyear', 'cmonth', 'cday', 'hour', 'minute', 'second']

class ModelView(Implicit):
    """ Base ModelView class for support of calendar rendering """

    __allow_access_to_unprotected_subobjects__ = 1

    unit = 'day'
    _sub = 'day_view'
    name = 'day_view'
    _args = 2
    _leap = DAY
    _skip = True

    # DWM: Added line to init to check the portal calendar's calendar
    # types.  Would be preferable to check the calendar container for
    # registered event types
    #calendar_types = ['Event']

    def __init__(self, dt=None, start=None, REQUEST=None):
        if dt is None:
            dt = datetime.today()
        if start is None:
            start = dt.replace(hour=0, minute=0, second=0, microsecond=0)
            if REQUEST is not None:
                start = dt.replace(hour=0, minute=0, second=0, microsecond=0)
                d = {}
                for k in ('cyear', 'cmonth', 'cday'):
                    if REQUEST.has_key(k):
                        d[k[1:]] = int(REQUEST.get(k))
                if d:
                    start = start.replace(**d)
        self.today = dt
        # So we always have a datetime inside
        # the period that we are looking at.
        # XXX DC: This is not guaranteed!
        self.cur = start
        self.start, self.end, self.resolution = makeRange(start, self.unit)

        # set calendar_types to display from portal_calendar


    def _context(self):
        return aq_parent(self)

    context = ComputedAttribute(_context, 1)

    def _factory_hook(self):
        return getView(self._sub)

    def _sub_factory(self):
        return self._factory_hook()

    sub_factory = ComputedAttribute(_sub_factory)

    def _parts(self):
        factory = self.sub_factory
        one = factory(self.today, self.start)
        end = one.end
        yield one.__of__(self.context)
        while end < self.end:
            sub = factory(self.today, end)
            end = sub.end
            yield sub.__of__(self.context)

    parts = ComputedAttribute(_parts, 1)

    def next(self):
        factory = self.__class__
        view = factory(self.today, self.end + self._leap)
        return view.__of__(self.context)

    def previous(self):
        factory = self.__class__
        leap = self._leap
        if self._skip:
            leap += DAY
        view = factory(self.today, self.start - leap)
        return view.__of__(self.context)

    def _make_url(self, date):
        request = self.REQUEST
        prefix = ''
        if hasattr(self, 'aq_parent'):
            prefix = self.context.absolute_url()
        args = dict(zip(ARG_NAMES[:self._args],
                        date.timetuple()[:self._args]))
        parts = filter(None, [prefix, self.name])
        return '%s?%s' % ('/'.join(parts), urllib.urlencode(args))

    def next_url(self):
        return self._make_url(self.next().start)

    def previous_url(self):
        return self._make_url(self.previous().start)

    def _day(self):
        return self.today.day

    day = ComputedAttribute(_day)

    def _month(self):
        return self.today.month

    month = ComputedAttribute(_month)

    def _year(self):
        return self.today.year

    year = ComputedAttribute(_year)

    def _current(self):
        return self.start <= self.today <= self.end

    current = ComputedAttribute(_current)

    def __str__(self):
        name = self.__class__.__name__
        args = ('name', self.name,
                'unit', self.unit,
                'sub', self._sub,
                'today', self.today,
                'start', self.start,
                'end', self.end,
                'resolution', self.resolution)
        return '%s%r' % (name, args)

    __repr__ = __str__

    def index_html(self):
        """ Get template from skins tool """
        st = getToolByName(self, 'portal_skins')
        template = st.restrictedTraverse(self.name)
        template = template.aq_base.__of__(self.context)
        return template(view=self)

    def getDateTimes(self):
        """
        Return the zope DateTime objects for self.today self.start
        and self.end
        """
        return {'today': dt2DT(self.today),
                'current': dt2DT(self.cur),
                'start': dt2DT(self.start),
                'end': dt2DT(self.end - SECOND),
                }

    def _ongoingEvents(self):
        pc_tool = getToolByName(self, 'portal_calendar')
        calendar_types = pc_tool.calendar_types

        ct = getToolByName(self, 'portal_catalog')
        start = dt2DT(self.start)
        end = dt2DT(self.start + SECOND)
        res = ct(portal_type=calendar_types,
                  start={'query': start,
                         'range': 'max'},
                  end={'query': end,
                       'range': 'min'},
                 sort_on='start')
        return tuple(res)

    ongoing_events = ComputedAttribute(_ongoingEvents, 1)

    def _events(self):
        ct = getToolByName(self, 'portal_catalog')
        pc_tool = getToolByName(self, 'portal_calendar')
        calendar_types = pc_tool.calendar_types
        res = ct(portal_type=calendar_types,
                  start={'query': [dt2DT(self.start),dt2DT(self.end - SECOND)],
                         'range': 'min:max'},
                 sort_on='start')
        return tuple(res)

    events = ComputedAttribute(_events, 1)

    def computeDuration(self, event):
        """
        Given an event computes the duration as an integer multiple of our
        sub_view ie if we're on the day vew returns the number of hours the
        event will last
        """
        start = DT2dt(event.start)
        end = DT2dt(event.end)
        delta = end - start
        # print  '----------->', toSeconds(self.resolution), self.resolution
        # _robert_ prevent division by 0
        return round(toSeconds(delta) / (toSeconds(self.resolution) or 1))
