# -*- coding: utf-8 -*-

from Acquisition import aq_base
from plone.app.contentlisting import IS_PLONE5
from plone.app.contentlisting.interfaces import IContentListing
from plone.app.contentlisting.interfaces import IContentListingObject
from plone.app.layout.navigation.root import getNavigationRoot
from plone.i18n.normalizer.interfaces import IIDNormalizer
from plone.registry.interfaces import IRegistry
from Products.CMFCore.utils import getToolByName
from Products.MimetypesRegistry.MimeTypeItem import guess_icon_path
from zope.component import getUtility
from zope.component import queryUtility
from zope.interface import implementer

import os


if IS_PLONE5:
    from Products.CMFPlone.interfaces import INavigationSchema


@implementer(IContentListing)
class ContentListing(object):
    """An IContentListing implementation based on sequences of objects."""

    def __init__(self, sequence):
        self._basesequence = sequence

    def __getitem__(self, index):
        """`x.__getitem__(index)` <==> `x[index]`
        """
        return IContentListingObject(self._basesequence[index])

    def __len__(self):
        """Length of the resultset is equal to the length of the underlying
        sequence.
        """
        return len(self._basesequence)

    @property
    def actual_result_count(self):
        bs = self._basesequence
        return getattr(bs, 'actual_result_count', len(bs))

    def __iter__(self):
        """Let the sequence be iterable and whenever we look at an object, it
        should be a ContentListingObject.
        """
        for obj in self._basesequence:
            yield IContentListingObject(obj)

    def __contains__(self, item):
        """`x.__contains__(item)` <==> `item in x`"""
        # It would be good if we could check this without waking all objects
        for i in self:
            if i == item:
                return True
        return False

    def __lt__(self, other):
        """`x.__lt__(other)` <==> `x < other`"""
        raise NotImplementedError

    def __le__(self, other):
        """`x.__le__(other)` <==> `x <= other`"""
        raise NotImplementedError

    def __eq__(self, other):
        """`x.__eq__(other)` <==> `x == other`"""
        raise NotImplementedError

    def __ne__(self, other):
        """`x.__ne__(other)` <==> `x != other`"""
        raise NotImplementedError

    def __gt__(self, other):
        """`x.__gt__(other)` <==> `x > other`"""
        raise NotImplementedError

    def __ge__(self, other):
        """`x.__ge__(other)` <==> `x >= other`"""
        raise NotImplementedError

    def __add__(self, other):
        """`x.__add__(other)` <==> `x + other`"""
        raise NotImplementedError

    def __mul__(self, n):
        """`x.__mul__(n)` <==> `x * n`"""
        raise NotImplementedError

    def __rmul__(self, n):
        """`x.__rmul__(n)` <==> `n * x`"""
        raise NotImplementedError

    def __getslice__(self, i, j):
        """`x.__getslice__(i, j)` <==> `x[i:j]`
        Use of negative indices is not supported.
        Deprecated since Python 2.0 but still a part of `UserList`.
        """
        return IContentListing(self._basesequence[i:j])


class BaseContentListingObject(object):
    """A baseclass for the different types of contentlistingobjects.

    To avoid duplication of the stuff that is not implementation-specific.
    """

    def __eq__(self, other):
        """For comparing two contentlistingobject"""
        other = IContentListingObject(other)
        return self.uuid() == other.uuid()

    def ContentTypeClass(self):
        # A normalised type name that identifies the object in listings.
        # Used for CSS styling.
        return 'contenttype-' + queryUtility(IIDNormalizer).normalize(
            self.PortalType(),
        )

    def ReviewStateClass(self):
        # A normalised review state string for CSS styling use in listings.
        return 'state-' + queryUtility(IIDNormalizer).normalize(
            self.review_state(),
        )



    if IS_PLONE5:
        def appendViewAction(self):
            # Decide whether to produce a string /view to append to links in
            # results listings.
            registry = getUtility(IRegistry)
            types = registry.get('plone.types_use_view_action_in_listings', [])
            if self.portal_type in types:
                return '/view'
            return ''

        def isVisibleInNav(self):
            # True, if this item should be visible in navigation trees.
            exclude_from_nav_attr = getattr(self, 'exclude_from_nav', None)
            if exclude_from_nav_attr is not None and (
                    self.exclude_from_nav()
                    if callable(self.exclude_from_nav)
                    else self.exclude_from_nav
            ):
                return False
            registry = getUtility(IRegistry)
            navigation_settings = registry.forInterface(
                INavigationSchema,
                prefix='plone',
            )
            if self.portal_type not in navigation_settings.displayed_types:
                return False
            return True

    else:

        def appendViewAction(self):
            # Decide whether to produce a string /view to append to links in
            # results listings.
            try:
                ttool = getToolByName(self.getDataOrigin(), 'portal_properties')
                types = ttool.site_properties.typesUseViewActionInListings
            except AttributeError:
                return ''
            if self.portal_type in types:
                return "/view"
            return ''

        def isVisibleInNav(self):
            # True, if this item should be visible in navigation trees.
            exclude_from_nav_attr = getattr(self, 'exclude_from_nav', None)
            if exclude_from_nav_attr is not None and (
                    self.exclude_from_nav()
                    if callable(self.exclude_from_nav)
                    else self.exclude_from_nav
            ):
                return False
            portal_properties = getToolByName(self.getDataOrigin(), 'portal_properties')
            navtree_properties = getattr(portal_properties, 'navtree_properties')
            if self.portal_type in list(navtree_properties.metaTypesNotToList):
                return False
            if self.id in list(navtree_properties.idsNotToList):
                return False
            return True

    def MimeTypeIcon(self):
        mimeicon = None
        navroot = getNavigationRoot(self._brain)
        contenttype = aq_base(
            getattr(self._brain, 'mime_type', None),
        )
        if contenttype:
            mtt = getToolByName(
                self._brain,
                'mimetypes_registry',
            )
            ctype = mtt.lookup(contenttype)
            mimeicon = os.path.join(
                navroot,
                guess_icon_path(ctype[0]),
            )

        return mimeicon
