import os
import tempfile
import shutil
import unittest
from waeup.ikoba import tests
from waeup.ikoba.interfaces import IDataCenterConfig, IPayPalConfig
from zope.component import getUtility, queryUtility, getGlobalSiteManager
from zope.configuration.exceptions import ConfigurationError
from zope.configuration.xmlconfig import file as zcfile
from zope.configuration.xmlconfig import string as zcstring


def get_zcml_conf(xml_code):
    """Get a working ZCML configuration file with `xml_code` embedded.

    The returned ZCML declares an ikoba namespace for local ZCML
    extensions and includes the `waeup.ikoba.meta` declarations before
    embedding `xml_code`.

    The returned string can be 'executed' with `string` or `file` from
    `zope.configuration.xmlconfig.
    """
    config = (
        '<configure '
        '   xmlns="http://namespaces.zope.org/zope"'
        '   xmlns:ikoba="http://namespaces.waeup.org/ikoba"'
        '   i18n_domain="waeup.ikoba"'
        '   package="waeup.ikoba.tests"'
        '>'
        '<include package="waeup.ikoba" file="meta.zcml" />'
        ''
        '%s'
        ''
        '</configure>'
        ) % xml_code
    return config


class ZCMLTests(unittest.TestCase):

    def setUp(self):
        self.workdir = tempfile.mkdtemp()

    def tearDown(self):
        shutil.rmtree(self.workdir)
        # unregister any remaining utils registered during tests
        gsm = getGlobalSiteManager()
        for iface in (IDataCenterConfig, IPayPalConfig):
            conf = queryUtility(iface)
            if conf is None:
                continue
            gsm.unregisterUtility(conf, iface)

    def create_fake_paypal_configs(self):
        # create two regular files in workdir
        self.conf1_path = os.path.join(self.workdir, 'paypal1.conf')
        self.conf2_path = os.path.join(self.workdir, 'paypal2.conf')
        open(self.conf1_path, 'w').write('[rest-client]\n')
        open(self.conf2_path, 'w').write('[rest-client]\n')

    def test_datacenter_config_directive(self):
        # the 'datacenter' directive can be used in ZCML
        assert queryUtility(IDataCenterConfig) is None
        zcfile("sample-datacenter.zcml", tests)  # 'execute' the ZCML
        result = getUtility(IDataCenterConfig)
        assert result == {'path': u'/some/path'}

    def test_datacenter_config_singleton(self):
        # we can define only one datacenter config
        config = get_zcml_conf(
            '<ikoba:datacenter path="/some/path" />'
            '<ikoba:datacenter path="/other/path" />'
            )
        assert queryUtility(IDataCenterConfig) is None
        self.assertRaises(
            ConfigurationError, zcstring, config)

    def test_paypal_config_directive(self):
        # the 'paypalconf' ZCML directive works
        assert queryUtility(IPayPalConfig) is None
        self.create_fake_paypal_configs()
        config = get_zcml_conf(
            '<ikoba:paypalconf path="%s" />' % self.conf1_path
            )
        zcstring(config)  # execute ZCML
        result = getUtility(IPayPalConfig)
        assert result == {
            'path': self.conf1_path,
            'client_id': None,
            'client_secret': None,
            'mode': 'sandbox'
            }

    def test_paypal_config_singleton(self):
        # we can define only one paypal config
        assert queryUtility(IPayPalConfig) is None
        self.create_fake_paypal_configs()
        config = get_zcml_conf(
            '<ikoba:paypalconf path="%s" />'
            '<ikoba:paypalconf path="%s" />'
            ) % (self.conf1_path, self.conf2_path)
        assert queryUtility(IPayPalConfig) is None
        self.assertRaises(
            ConfigurationError, zcstring, config)

    def test_paypal_config_no_such_file(self):
        # a set paypal config file must exist
        config = get_zcml_conf(
            '<ikoba:paypalconf path="/not/eXiStInG/path" />')
        self.assertRaises(
            ConfigurationError, zcstring, config)

    def test_paypal_config_not_a_regular_file(self):
        # a paypal config file must be a regular file
        dirpath = os.path.join(self.workdir, 'mydir')
        os.mkdir(dirpath)
        config = get_zcml_conf(
            '<ikoba:paypalconf path="%s" />' % dirpath)
        self.assertRaises(
            ConfigurationError, zcstring, config)
