class EventView(BrowserView):
    """ Event View """

    implements(IEventView)

    def __init__(self, context, request):
        self.context = context
        self.request = request
        self.database = IEventDatabaseProvider(context)
        self.portal_state = getMultiAdapter(
            (self.context, self.request),
            name=u'plone_portal_state'
            )
        self.navigation_root = self.portal_state.navigation_root()
        self.db_org_id = getattr(aq_base(self.navigation_root), 'dbOrgId', 0)
        self.params = param_utils.getQueryParams(request)
        self.eid = self.params['eid']

    def getEvent(self):
        """ find an event by eid """

        return self.database.getEvent(self.eid)

    def getEventDates(self):
        """
            Return a display list of dates.
        """

        return getEventDateRep(self.database.getEventDates(self.eid))

    def displayTime(self, event):
        """ start/end time for display; None if all-day """

        begins = event['begins']
        ends = event['ends']

        if begins == ends:
            if begins == '12:00 AM':
                return None
            return begins
        if ends == '12:00 AM':
            return begins
        return u"%s–%s" % (begins, ends)

    def needOrg(self, oid):
        """ do we need to show organizational details? """

        # Yes, unless oid of event matches that from nav root
        return self.db_org_id != oid

    def getOrg(self, oid):
        """ return a dict for the organization """

        return self.database.getOrgData(oid)

    def getParams(self):
        """ get the useful params as a dict """

        return self.params
class EventEditForm(form.SchemaForm):
    """ Define Form handling
    """

    schema = IEventEditForm
    ignoreContext = False

    # attributes we'll get from the database view
    database_attributes = (
        'eid',
        'title',
        'description',
        'location',
        'eventUrl',
        'eventContact',
        'eventEmail',
        'eventPhone',
        'begins',
        'ends',
        )

    def __init__(self, context, request):
        assert(INavigationRoot.providedBy(context))
        super(EventEditForm, self).__init__(context, request)
        self.database = IEventDatabaseProvider(context)
        # get eid from 'eid' or 'form.widgets.eid'
        self.eid = int(
            request.form.get('eid',
                request.form.get('form.widgets.eid', '0').replace(',', '')
                )
            )
        self.pdtcal = parsedatetime.Calendar()
        request['disable_border'] = 1
        request['disable_plone.rightcolumn'] = 1

    def updateWidgets(self):
        super(EventEditForm, self).updateWidgets()
        self.widgets['eid'].mode = z3c.form.interfaces.HIDDEN_MODE

    def updateActions(self):
            super(EventEditForm, self).updateActions()

            delete_action = self.actions.get('handleDelete')
            if delete_action:
                delete_action.onclick = u"return confirm('Delete this event?')"

    def getContent(self):
        """
        fill and return a content object
        """

        def strToDate(s):
            yr, mo, day = s.split('-')
            return date(int(yr), int(mo), int(day))

        def findRecurs(dates):
            last_delta = None
            starts = [d.start for d in dates]
            prev = strToDate(starts[0])
            for start in starts[1:]:
                dt = strToDate(start)
                delta = dt - prev
                if last_delta and delta != last_delta:
                    return None
                prev = dt
                last_delta = delta
            if delta.days == 1:
                recurs = "daily"
            elif delta.days == 7:
                recurs = "weekly"
            elif delta.days == 7:
                recurs = "biweekly"
            else:
                return None

            # we need to return an object with start, end, recurs
            # attributes
            obj = Recurrence()
            obj.start = starts[0]
            obj.end = starts[-1]
            obj.recurs = recurs
            return obj

        obj = EventContext()
        obj._database = self.database

        eid = self.eid
        if eid:
            event_data = self.database.getEvent(eid)
            for key in EventEditForm.database_attributes:
                value = event_data.get(key)
                setattr(obj, key, value)
            for key in ('public', 'free', 'community'):
                setattr(obj, key, event_data[key] == "Y")

            cats = [c.gcid for c in self.database.getEventCats(eid)]
            my_cats = [c.gcid for c in self.database.getOrgCats()]
            org_cats = []
            major_cats = []
            for gcid in cats:
                if gcid in my_cats:
                    org_cats.append(gcid)
                else:
                    major_cats.append(gcid)
            obj.majorCats = major_cats
            obj.orgCats = org_cats

            dates = self.database.getEventDates(eid)

            # check to see if this is an old-style date list
            # that happens to recur regularly
            if len(dates) > 1:
                recurs = findRecurs(dates)
                if recurs:
                    # we can normalize it to start, end, recurs
                    dates = [recurs]

            if len(dates) == 1:
                # simple scheduling
                obj.start = strToDate(dates[0].start)
                obj.end = strToDate(dates[0].end)
                obj.recurs = dates[0].recurs
            else:
                # we are irregularly scheduled
                obj.start = date.today()
                obj.end = date.today()
                obj.recurs = 'irregular'
                if len(dates):
                    wkdates = []
                    for d in dates:
                        yr, mo, dy = d.start.split('-')
                        wkdates.append("/".join((mo, dy, yr[2:])))
                    obj.dates = ", ".join(wkdates)
        else:
            obj.start = date.today()
            obj.end = date.today()
            portal_state = getMultiAdapter(
                (self.context, self.request), name=u'plone_portal_state')
            navigation_root = portal_state.navigation_root()
            obj.majorCats = getattr(navigation_root, 'defaultMajorCats', [])

        return obj

    def _getWriter(self):
        """
            return a database writer
        """

        portal_state = getMultiAdapter(
            (self.context, self.request),
            name=u'plone_portal_state'
            )
        navigation_root = portal_state.navigation_root()
        return IEventDatabaseWriteProvider(navigation_root)

    @button.buttonAndHandler(u'Save Event')
    def handleApply(self, action):
        data, errors = self.extractData()
        if errors:
            self.status = self.formErrorsMessage
            return

        # get write access to the database
        writer = self._getWriter()
        form = self.request.form
        portal_state = getMultiAdapter(
            (self.context, self.request),
            name=u'plone_portal_state'
            )
        member = portal_state.member()

        eid = data['eid']

        event_data = {}
        for key in EventEditForm.database_attributes:
            if key != 'eid':
                if key == 'begins':
                    # ##:## time from struct_time
                    event_data['startTime'] = struct_time2str(form['begins_time'])
                elif key == 'ends':
                    event_data['endTime'] = struct_time2str(form['ends_time'])
                else:
                    event_data[key] = data.get(key)
        for key in ('public', 'free', 'community'):
            event_data[key] = data.get(key) and "Y" or "N"

        if eid:
            writer.updateEvent(eid, member, **event_data)
            writer.deleteEventCats(eid)
            writer.deleteEventDates(eid)
        else:
            eid = writer.eventInsert(member, **event_data)

        writer.evCatsInsert(eid, list(data['orgCats'].union(data['majorCats'])))

        if data['recurs'] == 'irregular':
            # irregular scheduling; save a list of dates
            writer.evDatesInsert(
                eid,
                [(dt, dt, u"daily") for dt in form['date_list']]
                )
        else:
            # regular scheduling
            writer.evDatesInsert(eid, ((data['start'], data['end'], data['recurs']), ))

        messages = IStatusMessage(self.request)
        messages.add(u"Event saved", type=u"info")

        self.request.response.redirect("@@caledit")

    @button.buttonAndHandler(u"Delete Event",
        name="handleDelete",
        condition=lambda form: form.eid != 0)
    def handleDelete(self, action):
        """
            Delete this event.
        """

        eid = self.eid
        assert(eid != 0)

        writer = self._getWriter()
        writer.deleteEventCats(eid)
        writer.deleteEventDates(eid)
        writer.deleteEvent(eid)

        messages = IStatusMessage(self.request)
        messages.add(u"Event deleted", type=u"info")

        self.request.response.redirect("caledit")

    @button.buttonAndHandler(u"Cancel Edits")
    def handleCancel(self, action):
        """User cancelled. Redirect back to the front page.
        """

        self.request.response.redirect("caledit")