# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2002-2009 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
##############################################################################

from Testing.ZopeTestCase.PortalTestCase import PortalTestCase
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from Products.ERP5Type.tests.SecurityTestCase import SecurityTestCase
from Products.Formulator.XMLToForm import XMLToForm
from Products.Formulator.FormToXML import formToXML
from Products.Formulator.TALESField import TALESMethod
import transaction
import unittest
from lxml import etree
from Products.ERP5Type.tests.backportUnittest import expectedFailure

class TestProxyField(ERP5TypeTestCase):
  """
  Check proxy field
  """

  def getTitle(self):
    return "TestProxyField"

  def changeSkin(self, skin_name):
    """
      Change current Skin
    """
    request = self.app.REQUEST
    self.getPortal().portal_skins.changeSkin(skin_name)
    request.set('portal_skin', skin_name)

  def beforeTearDown(self):
    """Remove objects created in tests."""
    # Remove forms
    custom_folder = self.getSkinsTool().custom
    custom_folder.manage_delObjects(custom_folder.objectIds())

    # Remove skin folders
    if 'erp5_geek' in self.getSkinsTool().objectIds():
      self.getSkinsTool().manage_delObjects(['erp5_geek'])
      ps = self.getSkinsTool()
      for skin_name, selection in ps.getSkinPaths():
        new_selection = []
        selection = selection.split(',')
        for skin_id in selection:
          if skin_id != 'erp5_geek':
            new_selection.append(skin_id)
        ps.manage_skinLayers(skinpath=tuple(new_selection),
                             skinname=skin_name, add_skin=1)

    if 'customized_geek' in self.getSkinsTool().objectIds():
      self.getSkinsTool().manage_delObjects(['customized_geek'])
      ps = self.getSkinsTool()
      for skin_name, selection in ps.getSkinPaths():
        new_selection = []
        selection = selection.split(',')
        for skin_id in selection:
          if skin_id != 'customized_geek':
            new_selection.append(skin_id)
        ps.manage_skinLayers(skinpath=tuple(new_selection),
                             skinname=skin_name, add_skin=1)
    transaction.commit()

  def testEmptySurchargedFieldLibrary(self):
    """
    This test checks that it is not required to duplicate all fields in a custom
    field library
    """
    portal_skins = self.getSkinsTool()
    my_title_value = 'Generic Title'
    # Create an empty field library
    portal_skins.manage_addProduct['OFSP'].manage_addFolder('customized_geek')
    skin_folder = portal_skins._getOb('customized_geek')
    skin_folder.manage_addProduct['ERP5Form'].addERP5Form(
        'Base_viewGeekFieldLibrary',
        'View')
    form = skin_folder._getOb('Base_viewGeekFieldLibrary', None)

    # Create the default field library with a template field
    portal_skins.manage_addProduct['OFSP'].manage_addFolder('erp5_geek')
    skin_folder = portal_skins._getOb('erp5_geek')
    skin_folder.manage_addProduct['ERP5Form'].addERP5Form(
        'Base_viewGeekFieldLibrary',
        'View')
    form = skin_folder._getOb('Base_viewGeekFieldLibrary', None)
    form.manage_addField('my_title', my_title_value, 'StringField')

    # Custom field library has to have an higher priority
    selection = portal_skins.getSkinPath('View')
    selection = selection.split(',')
    selection.append('customized_geek')
    selection.append('erp5_geek')
    portal_skins.manage_skinLayers(skinpath=tuple(selection),
                                skinname='View', add_skin=1)
    portal_skins.getPortalObject().changeSkin(None)

    skin_folder = portal_skins._getOb('custom')
    skin_folder.manage_addProduct['ERP5Form'].addERP5Form('Base_viewGeek',
                                                          'View')
    form = skin_folder._getOb('Base_viewGeek', None)
    form.manage_addField('my_title', 'Title', 'ProxyField')
    field = form._getOb('my_title')
    field.manage_edit_xmlrpc(dict(
      form_id='Base_viewGeekFieldLibrary', field_id='my_title'))

    self.assertEquals(my_title_value, field.get_value('title'))

    # Reveal a bug, causes infinite loop when ProxyField.getTemplateField
    # returns the proxyfield itself.
    # This is caused by the acquisition context
    self.assertRaises(KeyError, self.portal.portal_skins.custom.Base_viewGeek.\
        my_title.Base_viewGeekFieldLibrary.my_title.get_value, 'ANYTHING_WHICH_RAISES_KEY_ERROR')

  def testPathOfTemplateField(self):
    """
    This test checks if it is possible to specify the skin folder of a form
    """
    portal_skins = self.getSkinsTool()
    portal_skins.manage_addProduct['OFSP'].manage_addFolder('customized_geek')
    skin_folder = portal_skins._getOb('customized_geek')
    skin_folder.manage_addProduct['ERP5Form'].addERP5Form(
        'Base_viewGeekFieldLibrary',
        'View')
    form = skin_folder._getOb('Base_viewGeekFieldLibrary', None)
    form.manage_addField('my_title', 'Customized Title', 'StringField')

    portal_skins.manage_addProduct['OFSP'].manage_addFolder('erp5_geek')
    skin_folder = portal_skins._getOb('erp5_geek')
    skin_folder.manage_addProduct['ERP5Form'].addERP5Form(
        'Base_viewGeekFieldLibrary',
        'View')
    form = skin_folder._getOb('Base_viewGeekFieldLibrary', None)
    form.manage_addField('my_title', 'Generic Title', 'StringField')

    # Custom field library has to have an higher priority
    selection = portal_skins.getSkinPath('View')
    selection = selection.split(',')
    selection.append('customized_geek')
    selection.append('erp5_geek')
    portal_skins.manage_skinLayers(skinpath=tuple(selection),
                                skinname='View', add_skin=1)
    portal_skins.getPortalObject().changeSkin(None)

    skin_folder = portal_skins._getOb('custom')
    skin_folder.manage_addProduct['ERP5Form'].addERP5Form('Base_viewGeek',
                                                          'View')
    form = skin_folder._getOb('Base_viewGeek', None)
    form.manage_addField('my_title', 'Title', 'ProxyField')
    field = getattr(form, 'my_title')
    # Explicitely enter skin folder of the template field's form
    field.manage_edit_xmlrpc(dict(
      form_id='erp5_geek/Base_viewGeekFieldLibrary', field_id='my_title'))

    self.assertEquals('Generic Title', field.get_value('title'))

  @expectedFailure
  def testSkinSelectionTemplateField(self):
    """
    Check that proxy field values are generated from the current skin selection
    """
    portal_skins = self.getSkinsTool()
    portal_skins.manage_addProduct['OFSP'].manage_addFolder('customized_geek')
    skin_folder = portal_skins._getOb('customized_geek')
    skin_folder.manage_addProduct['ERP5Form'].addERP5Form(
        'Base_viewGeekFieldLibrary',
        'View')
    form = skin_folder._getOb('Base_viewGeekFieldLibrary', None)
    form.manage_addField('my_title', 'Customized Title', 'StringField')

    portal_skins.manage_addProduct['OFSP'].manage_addFolder('erp5_geek')
    skin_folder = portal_skins._getOb('erp5_geek')
    skin_folder.manage_addProduct['ERP5Form'].addERP5Form(
        'Base_viewGeekFieldLibrary',
        'View')
    form = skin_folder._getOb('Base_viewGeekFieldLibrary', None)
    form.manage_addField('my_title', 'Generic Title', 'StringField')

    selection = portal_skins.getSkinPath('View')
    selection = selection.split(',')
    selection.append('customized_geek')
    selection.append('erp5_geek')
    portal_skins.addSkinSelection('CustomizedView', ','.join(selection))

    selection = portal_skins.getSkinPath('View')
    selection = selection.split(',')
    selection.append('erp5_geek')
    selection.append('customized_geek')
    portal_skins.addSkinSelection('GenericView', ','.join(selection))

    # XXX KeyError is raised if skin selection View is not modified.
    # This part has to be removed has soon as this bug is fixed
    selection = portal_skins.getSkinPath('View')
    portal_skins.manage_skinLayers(skinpath=tuple(selection),
                                skinname='View')

    portal_skins.getPortalObject().changeSkin(None)

    skin_folder = portal_skins._getOb('custom')
    skin_folder.manage_addProduct['ERP5Form'].addERP5Form('Base_viewGeek',
                                                          'View')
    form = skin_folder._getOb('Base_viewGeek', None)
    form.manage_addField('my_title', 'Title', 'ProxyField')
    field = getattr(form, 'my_title')
    field.manage_edit_xmlrpc(dict(
      form_id='Base_viewGeekFieldLibrary', field_id='my_title'))
    transaction.commit()

    self.assertEquals(None, field.get_value('title'))
    self.changeSkin('GenericView')
    self.assertEquals('Generic Title', field.get_value('title'))
    self.changeSkin('CustomizedView')
    self.assertEquals('Customized Title', field.get_value('title'))

  def testEmptySurchargedFieldLibrary_acquisition(self):
    """
    This test checks that it is not required to duplicate all fields in a custom
    field library, and field is well return in portal acquisition context
    """
    portal_skins = self.getSkinsTool()
    my_title_value = 'Generic Title'
    # Create an empty field library
    portal_skins.manage_addProduct['OFSP'].manage_addFolder('customized_geek')
    skin_folder = portal_skins._getOb('customized_geek')
    skin_folder.manage_addProduct['ERP5Form'].addERP5Form(
        'Base_viewGeekFieldLibrary',
        'View')
    form = skin_folder._getOb('Base_viewGeekFieldLibrary', None)

    # Create the default field library with a template field
    portal_skins.manage_addProduct['OFSP'].manage_addFolder('erp5_geek')
    skin_folder = portal_skins._getOb('erp5_geek')
    skin_folder.manage_addProduct['ERP5Form'].addERP5Form(
        'Base_viewGeekFieldLibrary',
        'View')
    form = skin_folder._getOb('Base_viewGeekFieldLibrary', None)
    form.manage_addField('my_title', my_title_value, 'StringField')

    # Custom field library has to have an higher priority
    selection = portal_skins.getSkinPath('View')
    selection = selection.split(',')
    selection.append('customized_geek')
    selection.append('erp5_geek')
    portal_skins.manage_skinLayers(skinpath=tuple(selection),
                                skinname='View', add_skin=1)
    portal_skins.getPortalObject().changeSkin(None)

    skin_folder = portal_skins._getOb('custom')
    skin_folder.manage_addProduct['ERP5Form'].addERP5Form('Base_viewGeek',
                                                          'View')
    form = skin_folder._getOb('Base_viewGeek', None)
    form.manage_addField('my_title', 'Title', 'ProxyField')
    field = form._getOb('my_title')
    field.manage_edit_xmlrpc(dict(
      form_id='Base_viewGeekFieldLibrary', field_id='my_title'))

    # Check that acquisition wrapper fits
    # restricted environment requirements.
    # If object returned is not wrapped in portal context,
    # current user is not Found in current context
    # then Unauthorized Exception is raised.
    python_script_id = "ERP5Site_testAccessProxyFieldProperty"
    python_script_parameter = "proxy_field"
    python_script_body = """
print proxy_field.getRecursiveTemplateField().meta_type
return printed
"""
    skin_folder.manage_addProduct['PythonScripts'].manage_addPythonScript(
                                                id=python_script_id)
    python_script_object = skin_folder._getOb(python_script_id)
    python_script_object.ZPythonScript_edit(python_script_parameter,
                                            python_script_body)
    python_script_object(field)

  def test_serializeProxyField(self):
    """Test formToXML and XMLToForm with proxyfields.
    """
    portal_skins = self.getSkinsTool()
    # Create the default field library with a template field
    portal_skins.manage_addProduct['OFSP'].manage_addFolder('erp5_geek')
    skin_folder = portal_skins._getOb('erp5_geek')
    skin_folder.manage_addProduct['ERP5Form'].addERP5Form(
        'Base_viewGeekFieldLibrary',
        'View')
    form = skin_folder._getOb('Base_viewGeekFieldLibrary', None)
    form.manage_addField('my_title', 'My Geek Title', 'StringField')

    # Custom field library has to have an higher priority
    selection = portal_skins.getSkinPath('View')
    selection = selection.split(',')
    selection.append('erp5_geek')
    portal_skins.manage_skinLayers(skinpath=tuple(selection),
                                skinname='View', add_skin=1)
    portal_skins.getPortalObject().changeSkin(None)

    skin_folder = portal_skins._getOb('custom')
    skin_folder.manage_addProduct['ERP5Form'].addERP5Form('Base_viewGeek',
                                                          'View')
    form = skin_folder._getOb('Base_viewGeek', None)
    form.manage_addField('my_title', 'Title', 'ProxyField')
    field = form._getOb('my_title')
    field.manage_edit_xmlrpc(dict(
      form_id='Base_viewGeekFieldLibrary', field_id='my_title'))
    my_title = 'My Custom Proxy Title'
    field.manage_edit_surcharged_xmlrpc({'title': my_title})

    # Test xml serialisation of form.
    xml_string = formToXML(form)
    xml_tree = etree.fromstring(xml_string)
    field_node = xml_tree.find('groups/group/fields/field')
    self.assertEquals(field_node.find('type').text, 'ProxyField')
    self.assertTrue(field_node.find('delegated_list/title') is not None)

    skin_folder.manage_addProduct['ERP5Form'].addERP5Form('Base_viewSuperGeek',
                                                          'View')
    form = skin_folder._getOb('Base_viewSuperGeek')
    # Test objectification of XML
    XMLToForm(xml_string, form)
    self.assertTrue(form.my_title.get_value('title'), my_title)

  def test_proxifyParallelListField(self):
    """ParallelListField has its own get_value method and the method does
    different from the original one. This test checks if ProxyField can
    behave the same as ParallelListField.
    """
    # Setup
    if getattr(self.portal.portal_categories, 'colour', None) is None:
      self.portal.portal_categories.newContent('colour')
    if getattr(self.portal.portal_categories, 'size', None) is None:
      self.portal.portal_categories.newContent('size')

    portal_skins = self.getSkinsTool()
    # Create skin folder
    portal_skins.manage_addProduct['OFSP'].manage_addFolder('erp5_geek')
    skin_folder = portal_skins._getOb('erp5_geek')

    skin_folder.manage_addProduct['ERP5Form'].addERP5Form('Base_viewGeek1',
                                                          'View')
    skin_folder.manage_addProduct['ERP5Form'].addERP5Form('Base_viewGeek2',
                                                          'View')

    form_1 = skin_folder.Base_viewGeek1
    # Add a parallel list field
    form_1.manage_addField('my_field', '', 'ParallelListField')
    form_1.my_field.manage_tales_xmlrpc(
      dict(default="python:['colour/blue']",
           items="python: [['Blue', 'colour/blue'], ['Red', 'colour/red'], ['Large', 'size/large'], ['Small', 'size/small']]"))
    form_1.my_field.manage_edit_xmlrpc(
      dict(hash_script_id="Base_getMultiListFieldPropertyDictList"))

    form_2 = skin_folder.Base_viewGeek2
    # Add a proxy field which has the same configuration as above field.
    form_2.manage_addField('my_field', '', 'ProxyField')
    form_2.my_field.manage_edit_xmlrpc(dict(form_id='Base_viewFieldLibrary',
                                            field_id='my_parallel_list_field'))
    form_2.my_field._surcharged_edit(
      dict(hash_script_id="Base_getMultiListFieldPropertyDictList"),
      ['hash_script_id'])
    form_2.my_field._surcharged_tales(
      dict(default=TALESMethod("python:['colour/blue']"),
           items=TALESMethod("python: [['Blue', 'colour/blue'], ['Red', 'colour/red'], ['Large', 'size/large'], ['Small', 'size/small']]")),
      ['default', 'items', 'hash_script_id'])

    # Compare
    # XXX Remove new lines. An extra new line is inserted by unknown reason.
    form_1_html = form_1.my_field.render(REQUEST=self.app.REQUEST).replace('\n', '')
    form_2_html = form_2.my_field.render(REQUEST=self.app.REQUEST).replace('\n', '')
    self.assertEqual(form_1_html, form_2_html)
