import datetime
import random
import time
from copy import deepcopy
try:
    from hashlib import md5
except ImportError:
    from md5 import md5
from random import randint
 
from Acquisition import aq_inner
from Products.ATContentTypes.interface.image import IATImage
from Products.ATContentTypes.interface.news import IATNewsItem
from Products.BlingPortlet import BlingPortletMessageFactory as _
from Products.BlingPortlet.interfaces import IBlingPortlet, IBlingImage, IBlingSlideshowPortlet, IBlingable, IBlingSlideshowView, IBlingView
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from plone.app.form.widgets.uberselectionwidget import UberSelectionWidget
from plone.app.portlets.portlets import base
from plone.browserlayer.utils import registered_layers
from zope.component import getMultiAdapter, getUtility, queryUtility
from zope.formlib import form
from zope.interface import implements
 
class BaseAssignment(base.Assignment):
    implements(IBlingPortlet)
 
    name = u''
    source = None
    base_title = u'Base Bling Portlet'
    def __init__(self, name, source, scale, links):
        self.name = name
        self.source = source
        self.links = links
        self.scale = scale
 
    @property
    def title(self):
        return self.name or self.base_title
 
class Assignment(BaseAssignment):
    base_title = u'Bling Portlet'
    def __init__(self, name=u'', source=None, scale=u'thumb', links=True, change=True, view=u'default'):
        BaseAssignment.__init__(self, name, source, scale, links)
        self.change = change
        self.view = view
 
class SlideshowAssignment(BaseAssignment):
    base_title = u'Bling Slideshow'
    implements(IBlingSlideshowPortlet)
 
    def __init__(self, name=u'', source=None, scale=u'thumb', links=True, interval=7000, ordering=u'Sequential', repeat=True, desc_limit=16, view=u'default'):
        BaseAssignment.__init__(self, name, source, scale, links)
        self.interval = interval
        self.ordering = ordering
        self.repeat = repeat
        self.desc_limit = desc_limit
        self.view = view
 
class BaseRenderer(base.Renderer):
    # only find adaptable objects which are accessible to all
    base_query = { 'object_provides' : (IATNewsItem.__identifier__,
                                        IATImage.__identifier__,
                                        IBlingable.__identifier__),
                   'allowedRolesAndUsers' : ('Anonymous',),
    }
 
    def __init__(self, *args):
        base.Renderer.__init__(self, *args)
 
        context = aq_inner(self.context)
        portal_state = getMultiAdapter((context, self.request), name=u'plone_portal_state')
        self.portal_url = portal_state.portal_url()
        self.portal_root = portal_state.navigation_root_path()
 
        plone_tools = getMultiAdapter((context, self.request), name=u'plone_tools')
        self.catalog = plone_tools.catalog()
 
    def title(self):
        return self.data.name
 
    def render(self):
        # we have to pass self because the way we define _template doesn't invoke Zope 2 compatibility magic
        return self._template(self)
 
    def links(self): 
        return self.data.links 
 
    def scale(self): 
        return self.data.scale 
 
    @property
    def _template(self):
        view = queryUtility(self.template_iface, name=self.data.view)
        if view is not None and (view.layer in registered_layers() or view.layer is None):
            template = view.template
        else:
            template = getUtility(self.template_iface, name=u"default").template
        return template
 
 
class Renderer(BaseRenderer):
 
    template_iface = IBlingView
 
    def getResultsIndex(self, resultsLength):
        if self.data.change == u'Random':
            return randint(0,resultsLength-1)
        elif self.data.change == u'Each second':
            return int(time.time()) % resultsLength
        elif self.data.change == u'Each minute':
            return int(time.time()) / 60 % resultsLength
        elif self.data.change == u'Each hour':
            return int(time.time()) / 3600 % resultsLength
        elif self.data.change == u'Each day':
            return int(time.time()) / 86400 % resultsLength
        elif self.data.change == u'Each week':
            return int(time.time()) / 604800 % resultsLength
        elif self.data.change == u'Each month':
            now = datetime.datetime.now()
            return (now.month + now.year*12) % resultsLength
        elif self.data.change == u'Each year':
            now = datetime.datetime.now()
            return now.year % resultsLength
        return 0
 
    def getdata(self):
        query = deepcopy(self.base_query)
        query['path'] = { 'query': self.portal_root + self.data.source, 'depth': 1 }
        results = self.catalog.unrestrictedSearchResults(query)
        if not len(results):
            return None
 
        return IBlingImage(results[self.getResultsIndex(len(results))].getObject(), None)
 
class SlideshowRenderer(BaseRenderer):
 
    template_iface = IBlingSlideshowView
 
    def portlethash(self):
        concat_txt = "%s\n%s" % (self.manager.__name__, self.data.__name__)
        return md5(concat_txt).hexdigest()
 
    def interval(self):
        return self.data.interval
 
    def ordering(self):
        return self.data.ordering
 
    def repeat(self):
        return self.data.repeat
 
    def desc_limit(self):
        return self.data.desc_limit
 
    def getdata(self):
        query = deepcopy(self.base_query)
        query['path'] = { 'query': self.portal_root + self.data.source, 'depth': 1 }
 
        if self.data.ordering == u'Sequential':
            query['sort_on'] = 'getObjPositionInParent'
            query['sort_order'] = 'ascending'
 
        results = self.catalog.unrestrictedSearchResults(query)
        filtered_results = [IBlingImage(r.getObject(), None) for r in results if r is not None]
 
        if self.data.ordering == u'Random':
            random.shuffle(filtered_results)
 
        return filtered_results
 
class AddForm(base.AddForm):
    form_fields = form.Fields(IBlingPortlet)
    form_fields['source'].custom_widget = UberSelectionWidget
    label = _(u"Add Bling Portlet")
    description = _(u"This portlet displays bling.")
 
    def create(self, data):
        return Assignment(**data)
 
class SlideshowAddForm(base.AddForm):
    form_fields = form.Fields(IBlingSlideshowPortlet)
    form_fields['source'].custom_widget = UberSelectionWidget
    label = _(u"Add Bling Slideshow Portlet")
    description = _(u"This portlet displays animated bling.")
 
    def create(self, data):
        return SlideshowAssignment(**data)
 
 
class EditForm(base.EditForm):
    form_fields = form.Fields(IBlingPortlet)
    form_fields['source'].custom_widget = UberSelectionWidget
    label = _(u"Edit Bling Portlet")
    description = _(u"This portlet displays bling.")    
 
class SlideshowEditForm(base.EditForm):
    form_fields = form.Fields(IBlingSlideshowPortlet)
    form_fields['source'].custom_widget = UberSelectionWidget
    label = _(u"Edit Bling Slideshow Portlet")
    description = _(u"This portlet displays animated bling.")