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

from AccessControl import Unauthorized
from BeautifulSoup import BeautifulSoup
from HTMLParser import HTMLParser
from lxml.html.clean import Cleaner
from plone import api
from plone.restapi.deserializer import boolean_value
from plone.restapi.interfaces import ISerializeToJson
from plone.restapi.interfaces import ISerializeToJsonSummary
from plonemeeting.restapi.config import IN_NAME_OF_UNAUTHORIZED
from Products.CMFCore.permissions import ManagePortal
from Products.CMFCore.utils import _checkPermission
from Products.CMFPlone.utils import safe_unicode
from Products.PloneMeeting.utils import convert2xhtml
from zExceptions import BadRequest
from zope.component import queryMultiAdapter
from zope.globalrequest import getRequest


IN_NAME_OF_USER_NOT_FOUND = 'The in_name_of user "%s" was not found!'


def check_in_name_of(instance, data):
    """ """
    in_name_of = data.get("in_name_of", None)
    if in_name_of:
        if not bool(may_access_config_endpoints(instance.cfg)):
            raise Unauthorized(IN_NAME_OF_UNAUTHORIZED % in_name_of)
        user = api.user.get(in_name_of)
        if not user:
            raise BadRequest(IN_NAME_OF_USER_NOT_FOUND % in_name_of)
    return in_name_of


def get_serializer(obj, extra_include_name=None, serializer=None):
    """ """
    request = getRequest()
    interface = ISerializeToJsonSummary
    if get_param("fullobjects", extra_include_name=extra_include_name, serializer=serializer):
        interface = ISerializeToJson
    serializer = queryMultiAdapter((obj, request), interface)
    if extra_include_name:
        serializer._extra_include_name = extra_include_name
    return serializer


def get_param(value, default=False, extra_include_name=None, serializer=None):
    """If current serialized element is an extra_include,
       infos in request.form are relative to extra_include,
       else information are directly available.
       For extra_include, a parameter is passed like :
       ?extra_include=extra_include_name:parameter_name:value so
       ?extra_include_category_include_all=false."""
    request = getRequest()
    # extra_include_name is stored on serializer or passed as parameter when serializer
    # still not initialized, this is the case for parameter "fullobjects" as from this
    # will depend the interface to use to get the serializer
    extra_include_name = serializer and \
        getattr(serializer, "_extra_include_name", extra_include_name)
    if extra_include_name:
        # change param value
        value = "extra_include_{0}_{1}".format(extra_include_name, value)

    param = request.form.get(value, None)

    # param was not found in request.form
    if param is None:
        param = default
    elif default in (True, False):
        param = boolean_value(param)
    # if default is a list, then make sure we return a list
    elif isinstance(default, (tuple, list)) and not isinstance(param, (tuple, list)):
        param = [param]
    return param


def clean_html(value):
    """ """
    if clean_html and value:
        # we need a surrounding <p></p> or the content is not generated by appy.pod
        if not value.startswith(u'<p>') or not value.endswith(u'</p>'):
            value = u'<p>%s</p>' % value
        soup = BeautifulSoup(safe_unicode(value))
        soup_contents = soup.renderContents()
        if not isinstance(soup_contents, unicode):
            soup_contents = safe_unicode(soup_contents)
        # clean HTML with HTMLParser, it will remove special entities like &#xa0;
        soup_contents = HTMLParser().unescape(soup_contents)
        # clean HTML with lxml Cleaner
        cleaner = Cleaner()
        soup_contents = cleaner.clean_html(soup_contents)
        # clean_html surrounds the cleaned HTML with <div>...</div>... removes it!
        if soup_contents.startswith(u'<div>') and soup_contents.endswith(u'</div>'):
            soup_contents = soup_contents[5:-6]
        if not soup_contents == value:
            value = soup_contents
    return value


def handle_html(obj, data):
    """ """
    return convert2xhtml(obj,
                         data,
                         image_src_to_data=True,
                         anonymize=True,
                         use_appy_pod_preprocessor=True)


def may_access_config_endpoints(cfg=None):
    '''
      This will be used to protect access to some config endpoints or
      functionnalities like "in_name_of".
    '''
    res = False
    tool = api.portal.get_tool('portal_plonemeeting')
    if (cfg is not None and tool.isManager(cfg)) or \
       tool.userIsAmong(['meetingmanagers']) or \
       _checkPermission(ManagePortal, tool):
        res = True
    return res


def filter_data(filters, data):
    """Apply given p_filters on elemnts of data (list of results).
       p_filters is like portal_type|MeetingItemSample or query_state|itemcreated,
       the first part of the filter may be an element's method or a string attribute."""
    res = []
    for elt in data:
        append_elt = True
        for filter_def in filters:
            filter_name, filter_value = filter_def.split('|')
            filter_fct = getattr(elt, filter_name)
            if callable(filter_fct):
                if filter_fct() != filter_value:
                    append_elt = False
                    break
            else:
                if filter_fct != filter_value:
                    append_elt = False
                    break
        if append_elt:
            res.append(elt)
    return res
