##############################################################################
#
# Copyright (c) 2005 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Plone control panel tool node adapters.

$Id$
"""

from plone.base.interfaces import IControlPanel
from Products.CMFCore.interfaces import IActionProvider
from Products.CMFCore.utils import getToolByName
from Products.GenericSetup.utils import exportObjects
from Products.GenericSetup.utils import importObjects
from Products.GenericSetup.utils import XMLAdapterBase
from zope.i18nmessageid import Message


class ControlPanelXMLAdapter(XMLAdapterBase):
    """
    XML im- and exporter for Plone control panel.  Most of this
    code is taken from the actions handler in CMFCore.
    """

    __used_for__ = IControlPanel

    _LOGGER_ID = "controlpanel"

    name = "controlpanel"

    def _exportNode(self):
        """
        Export the object as a DOM node.
        """
        node = self._getObjectNode("object")
        node.appendChild(self._extractConfiglets())
        self._logger.info("Control panel exported.")
        return node

    def _importNode(self, node):
        """
        Import the object from the DOM node.
        """
        self._initProvider(node)
        self._logger.info("Control panel imported.")

    def _initProvider(self, node):
        if self.environ.shouldPurge():
            actions = self.context.listActions()
            for action in actions:
                self.context.unregisterConfiglet(action.getId())

        self._initConfiglets(node)

    def _extractConfiglets(self):
        fragment = self._doc.createDocumentFragment()

        provider = self.context
        if not IActionProvider.providedBy(provider):
            return fragment

        actions = provider.listActions()

        if actions and isinstance(actions[0], dict):
            return fragment

        if actions:
            actions = list(actions)
            actions.sort(key=lambda action: action.getMapping()["id"])

        for ai in actions:
            mapping = ai.getMapping()
            child = self._doc.createElement("configlet")
            child.setAttribute("action_id", mapping["id"])
            child.setAttribute("category", mapping["category"])
            child.setAttribute("condition_expr", mapping["condition"])
            child.setAttribute("title", mapping["title"])
            child.setAttribute("url_expr", mapping["action"])
            child.setAttribute("visible", str(mapping["visible"]))
            child.setAttribute("appId", ai.getAppId())
            child.setAttribute("icon_expr", mapping["icon_expr"])
            for permission in mapping["permissions"]:
                sub = self._doc.createElement("permission")
                sub.appendChild(self._doc.createTextNode(permission))
                child.appendChild(sub)
            fragment.appendChild(child)
        return fragment

    def _initConfiglets(self, node):
        controlpanel = self.context
        default_domain = "plone"
        if node.nodeName == "object":
            domain = str(node.getAttribute("i18n:domain"))
            if domain:
                default_domain = domain
        for child in node.childNodes:
            if child.nodeName != "configlet":
                continue

            domain = str(child.getAttribute("i18n:domain"))
            if not domain:
                domain = default_domain

            action_id = str(child.getAttribute("action_id"))
            # Remove previous action with same id and category.
            controlpanel.unregisterConfiglet(action_id)
            remove = str(child.getAttribute("remove"))
            if remove.lower() == "true":
                continue

            title = Message(str(child.getAttribute("title")), domain=domain)
            url_expr = str(child.getAttribute("url_expr"))
            condition_expr = str(child.getAttribute("condition_expr"))
            icon_expr = str(child.getAttribute("icon_expr"))
            category = str(child.getAttribute("category"))
            visible = str(child.getAttribute("visible"))
            appId = str(child.getAttribute("appId"))
            if visible.lower() == "true":
                visible = 1
            else:
                visible = 0

            permission = ""
            for permNode in child.childNodes:
                if permNode.nodeName == "permission":
                    for textNode in permNode.childNodes:
                        if (
                            textNode.nodeName != "#text"
                            or not textNode.nodeValue.strip()
                        ):
                            continue
                        permission = str(textNode.nodeValue)
                        break  # only one permission is allowed
                    if permission:
                        break

            controlpanel.registerConfiglet(
                id=action_id,
                name=title,
                action=url_expr,
                appId=appId,
                condition=condition_expr,
                category=category,
                permission=permission,
                visible=visible,
                icon_expr=icon_expr,
            )


def importControlPanel(context):
    """Import Plone control panel."""
    site = context.getSite()
    tool = getToolByName(site, "portal_controlpanel", None)
    if tool is None:
        return

    importObjects(tool, "", context)


def exportControlPanel(context):
    """Export actions tool."""
    site = context.getSite()
    tool = getToolByName(site, "portal_controlpanel", None)
    if tool is None:
        return

    exportObjects(tool, "", context)
