"""
This tool is used as a way to customize PageTemplates directly in ZMI. The
templates are usually registered from skel or as NaayaPageTemplates.
This is useful when some templates must be customized in different Naaya Sites.

It also provides a way to keep track of the changes made and their differences
using diff tools.

"""

from os.path import join

from Globals import InitializeClass
from OFS.Folder import Folder
from AccessControl import ClassSecurityInfo
from AccessControl.Permissions import view_management_screens
from Products.PageTemplates.PageTemplateFile import PageTemplateFile

from Products.NaayaCore.constants import *
from Products.NaayaCore.LayoutTool.Template import manage_addTemplateForm, manage_addTemplate, Template

template_cache = {}

def manage_addFormsTool(self, REQUEST=None):
    """
    Class that implements the tool.
    """
    ob = FormsTool(ID_FORMSTOOL, TITLE_FORMSTOOL)
    self._setObject(ID_FORMSTOOL, ob)
    self._getOb(ID_FORMSTOOL).loadDefaultData()
    if REQUEST:
        return self.manage_main(self, REQUEST, update_menu=1)

class FormsTool(Folder):
    """
    Class that implements a container for forms.
    """

    meta_type = METATYPE_FORMSTOOL
    icon = 'misc_/NaayaCore/FormsTool.gif'

    manage_options = (
        {'label':'All forms', 'action':'manage_overview'},
        Folder.manage_options[0],
        Folder.manage_options[1],
        Folder.manage_options[4],
    ) + Folder.manage_options[7:]

    meta_types = (
        {'name': METATYPE_TEMPLATE, 'action': 'manage_addTemplateForm', 'permission': PERMISSION_ADD_NAAYACORE_TOOL},
    )
    all_meta_types = meta_types

    manage_addTemplateForm = manage_addTemplateForm
    manage_addTemplate = manage_addTemplate

    security = ClassSecurityInfo()

    def __init__(self, id, title):
        """
        Initialize variables.
        """
        self.id = id
        self.title = title

    security.declarePrivate('loadDefaultData')
    def loadDefaultData(self):
        """ """

    security.declareProtected(view_management_screens, 'listDefaultForms')
    def listDefaultForms(self):
        """
        generator that yields all default forms
        """
        # get forms from skel folders
        for skel_handler in reversed(self.get_all_skel_handlers()):
            if skel_handler.root.forms is None:
                continue

            skel_path = skel_handler.skel_path
            for form in skel_handler.root.forms.forms:
                path = join(skel_path, 'forms', '%s.zpt' % form.id)
                yield {'id': form.id, 'title': form.title, 'path': path}

        # get forms from pluggable items
        pluggable_content = self.get_pluggable_content()

        for meta_type, pluggable_item in pluggable_content.iteritems():
            for form_id in pluggable_item['forms']:
                module_name = pluggable_item['module']
                title = '%s %s' % (module_name, form_id)
                path = join(pluggable_item['package_path'], 'zpt', '%s.zpt' % form_id)
                yield {'id': form_id, 'title': title, 'path': path}

        # forms of type NaayaPageTemplateFile
        for form_id, tmpl in naaya_templates.iteritems():
            yield {'id': form_id, 'title': form_id, 'form_ob': tmpl}

    security.declareProtected(view_management_screens, 'registered_form_ids')
    def registered_form_ids(self):
        return sorted(set(form['id'] for form in self.listDefaultForms()))

    def getDefaultForm(self, form_id):
        for form in self.listDefaultForms():
            if form['id'] == form_id:
                if 'form_ob' in form:
                    return form['form_ob']._text
                else:
                    return self.futRead(form['path'], 'r')
        else:
            raise KeyError('Not found form named "%s"' % form_id)

    def _default_form(self, form_id):
        """ get the non-customized form """
        for form in self.listDefaultForms():
            if form['id'] == form_id:
                if 'form_ob' in form:
                    t = form['form_ob']
                else:
                    file_path = form['path']
                    if file_path in template_cache:
                        t = template_cache[file_path]
                    else:
                        t = PageTemplateFile(file_path)
                        template_cache[file_path] = t

                return t.__of__(self)
        raise KeyError('Not found form named "%s"' % form_id)

    def getForm(self, form_id):
        """
        Fetches a Naaya form

        First looks in the portal_forms folder (in case the form has been
        customized). If not, then it looks for default templates in packages.
        """
        if form_id in self.objectIds():
            return self._getOb(form_id)
        else:
            return self._default_form(form_id)

    def __getitem__(self, form_id):
        """
        Makes it possible to access portal forms by key
        and therefore by `path:` traversal in zpt.

        """
        return self.getForm(form_id)

    def getContent(self, p_context={}, p_page=None):
        """
        Renders the given form and return the result.
        @param p_context: extra parameters for the ZPT
        @type p_context: dictionary
        @param p_page: the id of the ZPT
        @type p_page: string
        """

        p_context['skin_files_path'] = self.getLayoutTool().getSkinFilesPath()
        form = self.getForm(p_page)
        return form.pt_render(extra_context=p_context)

    _diff = PageTemplateFile('zpt/diff', globals())
    security.declareProtected(view_management_screens, 'show_diff')
    def show_diff(self, REQUEST):
        """ show the differences between the default and customized form """
        from Products.naayaUpdater.utils import html_diff
        form_id = REQUEST.get('form_id', '')
        form_customized = self._getOb(form_id)
        form_default = self._default_form(form_id)
        diff = html_diff(form_default._text, form_customized._text)
        return self._diff(diff=diff)

    security.declareProtected(view_management_screens, 'manage_customizeForm')
    def manage_customizeForm(self, form_id, REQUEST=None):
        """ Copy the form from disk to zodb """
        for form in self.listDefaultForms():
            if form['id'] == form_id:
                if 'form_ob' in form:
                    body = form['form_ob']._text
                else:
                    body = self.futRead(form['path'], 'r')
                break
        else:
            raise KeyError('Not found form named "%s"' % form_id)

        ob = Template(id=form['id'],
                      title=form['title'],
                      text=body,
                      content_type='text/html')
        ob._naaya_original_text = body
        self._setObject(form['id'], ob)

        if REQUEST is not None:
            return REQUEST.RESPONSE.redirect('%s/%s/manage_workspace' %
                (self.absolute_url(), form['id']))

    manage_overview = PageTemplateFile('zpt/manage_overview', globals())
    manage_customize = PageTemplateFile('zpt/manage_customize', globals())

InitializeClass(FormsTool)

naaya_templates = {}
def register_naaya_template(tmpl, form_id):
    naaya_templates[form_id] = tmpl
