# -*- coding: utf-8 -*-
## GroupUserFolder
## Copyright (C)2006 Ingeniweb

## 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; see the file COPYING. If not, write to the
## Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
"""

"""
__version__ = "$Revision:  $"
# $Source:  $
# $Id: Installation.py 30098 2006-09-08 12:35:01Z encolpe $
__docformat__ = 'restructuredtext'


from cStringIO import StringIO
import string
from Products.CMFCore.utils import getToolByName
from Products.CMFCore.TypesTool import ContentFactoryMetadata
from Products.CMFCore.DirectoryView import addDirectoryViews
from Products.CMFPlone.migrations.migration_util import safeEditProperty

class Installation:
    def __init__(self, root):
        self.root=root
        self.out=StringIO()
        self.typesTool = getToolByName(self.root, 'portal_types')
        self.skinsTool = getToolByName(self.root, 'portal_skins')
        self.portal_properties = getToolByName(self.root, 'portal_properties')
        self.navigation_properties = self.portal_properties.navigation_properties
        self.form_properties = self.portal_properties.form_properties

    def report(self):
        self.out.write('Installation completed.\n')
        return self.out.getvalue()

    def setupTools(self, product_name, tools):
        addTool = self.root.manage_addProduct[product_name].manage_addTool
        for tool, title in tools:
            found = 0
            for obj in self.root.objectValues():
                if obj.meta_type == tool:
                    found = 1
            if not found:
                addTool(tool, None)

            found = 0
            root=self.root
            for obj in root.objectValues():
                if obj.meta_type == tool:
                    obj.title=title
                    self.out.write("Added '%s' tool.\n" % (tool,))
                    found = 1
            if not found:
                self.out.write("Couldn't add '%s' tool.\n" % (tool,))

    def installSubSkin(self, skinFolder):
        """ Install a subskin, i.e. a folder/directoryview.
        """
        for skin in self.skinsTool.getSkinSelections():
            path = self.skinsTool.getSkinPath(skin)
            path = map( string.strip, string.split( path,',' ) )
            if not skinFolder in path:
                try:
                    path.insert( path.index( 'custom')+1, skinFolder )
                except ValueError:
                    path.append(skinFolder)
                path = string.join( path, ', ' )
                self.skinsTool.addSkinSelection( skin, path )
                self.out.write('Subskin successfully installed into %s.\n' % skin)
            else:
                self.out.write('*** Subskin was already installed into %s.\n' % skin)

    def setupCustomModelsSkin(self, skin_name):
        """ Install custom skin folder
        """
        try:
            self.skinsTool.manage_addProduct['OFSP'].manage_addFolder(skin_name + 'CustomModels')
        except:
            self.out.write('*** Skin %sCustomModels already existed in portal_skins.\n' % skin_name)
        self.installSubSkin('%sCustomModels' % skin_name)

    def setupTypesandSkins(self, fti_list, skin_name, install_globals):
        """
        setup of types and skins
        """

        # Former types deletion (added by PJG)
        for f in fti_list:
            if f['id'] in self.typesTool.objectIds():
                self.out.write('*** Object "%s" already existed in the types tool => deleting\n' % (f['id']))
                self.typesTool._delObject(f['id'])

        # Type re-creation
        for f in fti_list:
            # Plone1 : if cmfformcontroller is not available and plone1_action key is defined,
            # use this key instead of the regular 'action' key.
            if (not self.hasFormController()) and f.has_key('plone1_action'):
                f['action'] = f['plone1_action']

            # Regular FTI processing
            cfm = apply(ContentFactoryMetadata, (), f)
            self.typesTool._setObject(f['id'], cfm)
            self.out.write('Type "%s" registered with the types tool\n' % (f['id']))

        # Install de chaque nouvelle subskin/layer
        try:
            addDirectoryViews(self.skinsTool, 'skins', install_globals)
            self.out.write( "Added directory views to portal_skins.\n" )
        except:
            self.out.write( '*** Unable to add directory views to portal_skins.\n')

        # Param de chaque nouvelle subskin/layer
        self.installSubSkin(skin_name)

    def isPlone2(self,):
        """
        isPlone2(self,) => return true if we're using Plone2 ! :-)
        """
        return self.hasFormController()

    def hasFormController(self,):
        """
        hasFormController(self,) => Return 1 if CMFFC is available
        """
        if 'portal_form_controller' in self.root.objectIds():
            return 1
        else:
            return None

    def addFormValidators(self, mapping):
        """
        Adds the form validators.
        DON'T ADD ANYTHING IF CMFFORMCONTROLLER IS INSTALLED
        """
        # Plone2 management
        if self.hasFormController():
            return
        for (key, value) in mapping:
            safeEditProperty(self.form_properties, key, value)

    def addNavigationTransitions(self, transitions):
        """
        Adds Navigation Transitions in portal properties
        """
        # Plone2 management
        if self.hasFormController():
            return
        for (key, value) in transitions:
            safeEditProperty(self.navigation_properties, key, value)

    def setPermissions(self, perms_list):
        """
        setPermissions(self) => Set standard permissions / roles
        """
        # As a default behavior, newly-created permissions are granted to owner and manager.
        # To change this, just comment this code and grab back the code commented below to
        # make it suit your needs.
        for perm in perms_list:
            self.root.manage_permission(
                perm,
                ('Manager', 'Owner'),
                acquire = 1
                )
        self.out.write("Reseted default permissions\n")

    def installMessageCatalog(self, plone, prodglobals, domain, poPrefix):
        """Sets up the a message catalog for this product
        according to the available languages in both:
        - .pot files in the "i18n" folder of this product
        - MessageCatalog available for this domain
        Typical use, create below this function:
        def installCatalog(self):
            installMessageCatalog(self, Products.MyProduct, 'mydomain', 'potfile_')
            return
        This assumes that you set the domain 'mydomain' in 'translation_service'
        and the .../Products/YourProduct/i18n/potfile_en.po (...) contain your messages.

        @param plone: the plone site
        @type plone: a 'Plone site' object
        @param prodglobals: see PloneSkinRegistrar.__init__
        @param domain: the domain nick in Plone 'translation_service'
        @type domain: string or None for the default domain
            (you shouldn't use the default domain)
        @param poPrefix: .po files to use start with that prefix.
            i.e. use 'foo_' to install words from 'foo_fr.po', 'foo_en.po' (...)
        @type poPrefix: string
        """

        installInfo = (
            "!! I18N INSTALLATION CANCELED !!\n"
            "It seems that your Plone instance does not have the i18n features installed correctly.\n"
            "You should have a 'translation_service' object in your Plone root.\n"
            "This object should have the '%(domain)s' domain registered and associated\n"
            "with an **existing** MessageCatalog object.\n"
            "Fix all this first and come back here." % locals())
        #
        # Find Plone i18n resources
        #
        try:
            ts = getattr(plone, 'translation_service')
        except AttributeError, e:
            return installInfo
        found = 0
        for nick, path in ts.getDomainInfo():
            if nick == domain:
                found = 1
                break
        if not found:
            return installInfo
        try:
            mc = ts.restrictedTraverse(path)
        except (AttributeError, KeyError), e:
            return installInfo
        self.out.write("Installing I18N messages into '%s'\n" % '/'.join(mc.getPhysicalPath()))
        enabledLangs = [nick for nick, lang in mc.get_languages_tuple()]
        self.out.write("This MessageCatalog has %s languages enabled.\n" %  ", ".join(enabledLangs))
        #
        # Find .po files
        #
        i18nPath = os.path.join(prodglobals['__path__'][0], 'i18n')
        poPtn = os.path.join(i18nPath, poPrefix + '*.po')
        poFiles = glob.glob(poPtn)
        rxFindLanguage = re.compile(poPrefix +r'(.*)\.po')
        poRsrc = {}
        for file in poFiles:
            k = rxFindLanguage.findall(file)[0]
            poRsrc[k] = file
        self.out.write("This Product provides messages for %s languages.\n" % ", ".join(poRsrc.keys()))
        for lang in enabledLangs:
            if poRsrc.has_key(lang):
                self.out.write("Adding support for language %s.\n" % lang)
                fh = open(poRsrc[lang])
                mc.manage_import(lang, fh.read())
                fh.close()
        self.out.write("Done !")
