# -*- coding: utf-8 -*-

"""theses tests are much more to test that config, option description, vs...
**it's there** and answers via attribute access"""
from py.test import raises
import weakref

from .autopath import do_autopath
do_autopath()

from tiramisu.config import Config, SubConfig
from tiramisu.i18n import _
from tiramisu import Config, IntOption, FloatOption, StrOption, ChoiceOption, \
    BoolOption, UnicodeOption, OptionDescription, getapi, undefined
from tiramisu.error import ConflictError, ConfigError, PropertiesOptionError, APIError


def make_description():
    gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
    gcdummy = BoolOption('dummy', 'dummy', default=False)
    objspaceoption = ChoiceOption('objspace', 'Object space',
                                  ('std', 'thunk'), 'std')
    booloption = BoolOption('bool', 'Test boolean option', default=True)
    intoption = IntOption('int', 'Test int option', default=0)
    floatoption = FloatOption('float', 'Test float option', default=2.3)
    stroption = StrOption('str', 'Test string option', default="abc", properties=('mandatory', ))
    boolop = BoolOption('boolop', 'Test boolean option op', default=True, properties=('hidden',))
    wantref_option = BoolOption('wantref', 'Test requires', default=False)
    wantframework_option = BoolOption('wantframework', 'Test requires',
                                      default=False)

    gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
    descr = OptionDescription('tiram', '', [gcgroup, booloption, objspaceoption,
                                            wantref_option, stroption,
                                            wantframework_option,
                                            intoption, boolop])
    return descr


def test_base_config():
    """making a :class:`tiramisu.config.Config()` object
    and a :class:`tiramisu.option.OptionDescription()` object
    """
    gcdummy = BoolOption('dummy', 'dummy', default=False)
    descr = OptionDescription('tiramisu', '', [gcdummy])
    cfg = Config(descr)
    api = getapi(cfg)
    assert api.option('dummy').value.get() is False
    #dmo = cfg.unwrap_from_path('dummy')
    #assert dmo.impl_getname() == 'dummy'


def test_base_config_name():
    gcdummy = BoolOption('dummy', 'dummy', default=False)
    descr = OptionDescription('tiramisu', '', [gcdummy])
    cfg = Config(descr, session_id='cfg')
    cfg.impl_getname() == 'cfg'
    raises(ValueError, "Config(descr, session_id='unvalid name')")


def test_not_config():
    assert raises(TypeError, "Config('str')")


#def test_base_path():
#    gcdummy = BoolOption('dummy', 'dummy', default=False)
#    descr = OptionDescription('tiramisu', '', [gcdummy])
#    cfg = Config(descr)
#    assert cfg._impl_path is None
#    base = OptionDescription('config', '', [descr])
#    cfg = Config(base)
#    assert cfg._impl_path is None
#    assert cfg.getattr('tiramisu', None, validate_properties=False)._impl_path == 'tiramisu'
#    nbase = OptionDescription('baseconfig', '', [base])
#    cfg = Config(nbase)
#    assert cfg._impl_path is None
#    assert cfg.getattr('config', None, validate_properties=False)._impl_path == 'config'
#    assert cfg.getattr('config.tiramisu', None, validate_properties=False)._impl_path == 'config.tiramisu'


def test_base_config_force_permissive():
    descr = make_description()
    config = Config(descr)
    api = getapi(config)
    api.property.read_write()
    api.permissive.set(frozenset(['hidden']))
    raises(PropertiesOptionError, "api.option('boolop').value.get()")
    assert api.forcepermissive.option('boolop').value.get() is True


def test_base_config_in_a_tree():
    "how options are organized into a tree, see :ref:`tree`"
    descr = make_description()
    config = Config(descr)
    api = getapi(config)
    #
    api.option('bool').value.set(False)
    #
    assert api.option('gc.name').value.get() == 'ref'
    api.option('gc.name').value.set('framework')
    assert api.option('gc.name').value.get() == 'framework'
    #
    assert api.option('objspace').value.get() == 'std'
    api.option('objspace').value.set('thunk')
    assert api.option('objspace').value.get() == 'thunk'
    #
    assert api.option('gc.float').value.get() == 2.3
    api.option('gc.float').value.set(3.4)
    assert api.option('gc.float').value.get() == 3.4
    #
    assert api.option('int').value.get() == 0
    api.option('int').value.set(123)
    assert api.option('int').value.get() == 123
    #
    assert api.option('wantref').value.get() is False
    api.option('wantref').value.set(True)
    assert api.option('wantref').value.get() is True
    #
    assert api.option('str').value.get() == 'abc'
    api.option('str').value.set('def')
    assert api.option('str').value.get() == 'def'
    #
    raises(AttributeError, "api.option('gc.foo').value.get()")
    ##
    config = Config(descr)
    api = getapi(config)
    assert api.option('bool').value.get() is True
    assert api.option('gc.name').value.get() == 'ref'
    assert api.option('wantframework').value.get() is False


#def test_cfgimpl_get_home_by_path():
#    " :meth:`tiramisu.config.SubConfig.cfgimpl_get_home_by_path()` to retrieve a path"
#    descr = make_description()
#    config = Config(descr)
#    api = getapi(config)
#    api.option('bool').value.set(False)
#    assert config.cfgimpl_get_home_by_path('gc.dummy', None)[1] == 'dummy'
#    assert config.cfgimpl_get_home_by_path('dummy', None)[1] == 'dummy'


def test_not_valid_properties():
    raises(TypeError, "stroption = StrOption('str', 'Test string option', default='abc', properties=['mandatory',])")


def test_information_config():
    descr = make_description()
    config = Config(descr)
    api = getapi(config)
    string = 'some informations'
    #
    api.information.set('info', string)
    assert api.information.get('info') == string
    #
    raises(ValueError, "api.information.get('noinfo')")
    assert api.information.get('noinfo', 'default') == 'default'
    api.information.reset('info')
    raises(ValueError, "api.information.get('info')")
    raises(ValueError, "api.information.reset('noinfo')")


def test_config_impl_get_path_by_opt():
    descr = make_description()
    config = Config(descr)
    api = getapi(config)
    dummy = api.option('gc.dummy').option.get()
    boo = api.option('bool').option.get()
    unknown = IntOption('test', '')
    unknown
    assert config.cfgimpl_get_description().impl_get_path_by_opt(boo) == 'bool'
    assert config.cfgimpl_get_description().impl_get_path_by_opt(dummy) == 'gc.dummy'
    #raises(AttributeError, "config.cfgimpl_get_description().impl_get_path_by_opt(unknown)")


#def test_config_impl_get_path_by_opt_od():
#    descr = make_description()
#    config = Config(descr)
#    api = getapi(config)
#    dummy = api.option.get('gc.dummy')
#    dummy
#    raises(ConfigError, "config.getattr('gc', None).cfgimpl_get_description().impl_get_path_by_opt(dummy)")
#
#
#def test_config_impl_get_opt_by_path():
#    descr = make_description()
#    config = Config(descr)
#    api = getapi(config)
#    dummy = api.option.get('gc.dummy')
#    boo = api.option.get('bool')
#    assert config.cfgimpl_get_description().impl_get_opt_by_path('bool') == boo
#    assert config.cfgimpl_get_description().impl_get_opt_by_path('gc.dummy') == dummy
#    raises(AttributeError, "config.cfgimpl_get_description().impl_get_opt_by_path('gc.unknown')")
#    raises(ConfigError, "config.getattr('gc', None).cfgimpl_get_description().impl_get_opt_by_path('gc.unknown')")


#def test_information_display():
#    g1 = IntOption('g1', '', 1)
#    g2 = StrOption('g2', '', 'héhé')
#    g3 = UnicodeOption('g3', '', u'héhé')
#    g4 = BoolOption('g4', '', True)
#    g5 = StrOption('g5', '')
#    d1 = OptionDescription('od', '', [g1, g2, g3, g4, g5])
#    root = OptionDescription('root', '', [d1])
#    config = Config(root)
#    assert str(config.od) == """g1 = 1
#g2 = héhé
#g3 = héhé
#g4 = True
#g5 = None"""
#    assert str(config) == '[od]'


def to_tuple(val):
    ret = []
    for v in val:
        t = []
        for w in v:
            if isinstance(w, list):
                t.append(tuple(w))
            else:
                t.append(w)
        ret.append(tuple(t))
    return tuple(ret)


def test_get_modified_values():
    g1 = IntOption('g1', '', 1)
    g2 = StrOption('g2', '', 'héhé')
    g3 = UnicodeOption('g3', '', u'héhé')
    g4 = BoolOption('g4', '', True)
    g5 = StrOption('g5', '')
    g6 = StrOption('g6', '', multi=True)
    d1 = OptionDescription('od', '', [g1, g2, g3, g4, g5, g6])
    root = OptionDescription('root', '', [d1])
    config = Config(root)
    api = getapi(config)
    assert to_tuple(api.value.exportation()) == ((), (), (), ())
    api.option('od.g5').value.set('yes')
    assert to_tuple(api.value.exportation()) == (('od.g5',), (None,), ('yes',), ('user',))
    api.option('od.g4').value.set(True)
    assert to_tuple(api.value.exportation()) == (('od.g5', 'od.g4'), (None, None), ('yes', True), ('user', 'user'))
    api.option('od.g4').value.reset()
    assert to_tuple(api.value.exportation()) == (('od.g5',), (None,), ('yes',), ('user',))
    api.option('od.g6').value.set([undefined])
    assert to_tuple(api.value.exportation()) == (('od.g5', 'od.g6'), (None, None), ('yes', (None,)), ('user', 'user'))
    api.option('od.g6').value.set([])
    assert to_tuple(api.value.exportation()) == (('od.g5', 'od.g6'), (None, None), ('yes', tuple()), ('user', 'user'))
    api.option('od.g6').value.set(['3'])
    assert to_tuple(api.value.exportation()) == (('od.g5', 'od.g6'), (None, None), ('yes', ('3',)), ('user', 'user'))
    api.option('od.g6').value.set([])
    assert to_tuple(api.value.exportation()) == (('od.g5', 'od.g6'), (None, None), ('yes', tuple()), ('user', 'user'))


def test_get_modified_values_not_modif():
    g1 = StrOption('g1', '', multi=True)
    d1 = OptionDescription('od', '', [g1])
    root = OptionDescription('root', '', [d1])
    config = Config(root)
    api = getapi(config)
    assert api.option('od.g1').value.get() == []
    value = api.option('od.g1').value.get()
    value.append('val')
    assert api.option('od.g1').value.get() == []


#def test_has_value():
#    g1 = IntOption('g1', '', 1)
#    g2 = StrOption('g2', '', 'héhé')
#    g3 = UnicodeOption('g3', '', u'héhé')
#    g4 = BoolOption('g4', '', True)
#    g5 = StrOption('g5', '')
#    d1 = OptionDescription('od', '', [g1, g2, g3, g4, g5])
#    root = OptionDescription('root', '', [d1])
#    config = Config(root)
#    api = getapi(config)
#    assert not g5 in config.cfgimpl_get_values()
#    api.option('od.g5').value.set('yes')
#    assert g5 in config.cfgimpl_get_values()


#def test_values_not_setitem():
#    g1 = IntOption('g1', '', 1)
#    g2 = StrOption('g2', '', 'héhé')
#    g3 = UnicodeOption('g3', '', u'héhé')
#    g4 = BoolOption('g4', '', True)
#    g5 = StrOption('g5', '')
#    d1 = OptionDescription('od', '', [g1, g2, g3, g4, g5])
#    root = OptionDescription('root', '', [d1])
#    config = Config(root)
#    config
#    raises(ConfigError, "config.cfgimpl_get_values()[g1] = 2")


def test_duplicated_option():
    g1 = IntOption('g1', '', 1)
    g1
    #in same OptionDescription
    raises(ConflictError, "d1 = OptionDescription('od', '', [g1, g1])")


def test_duplicated_option_diff_od():
    g1 = IntOption('g1', '', 1)
    d1 = OptionDescription('od1', '', [g1])
    #in different OptionDescription
    d2 = OptionDescription('od2', '', [g1, d1])
    d2
    raises(ConflictError, 'Config(d2)')


def test_cannot_assign_value_to_option_description():
    descr = make_description()
    cfg = Config(descr)
    api = getapi(cfg)
    api
    raises(APIError, "api.option('gc').value.set(3)")


def test_config_multi():
    i1 = IntOption('test1', '', multi=True)
    i2 = IntOption('test2', '', multi=True, default_multi=1)
    i3 = IntOption('test3', '', default=[2], multi=True, default_multi=1)
    od = OptionDescription('test', '', [i1, i2, i3])
    config = Config(od)
    api = getapi(config)
    assert api.option('test1').value.get() == []
    assert api.option('test2').value.get() == []
    api.option('test2').value.set([undefined])
    assert api.option('test2').value.get() == [1]
    assert api.option('test3').value.get() == [2]
    api.option('test3').value.set([undefined, undefined])
    assert api.option('test3').value.get() == [2, 1]


def test_no_validation():
    i1 = IntOption('test1', '')
    od = OptionDescription('test', '', [i1])
    cfg = Config(od)
    api = getapi(cfg)
    api.property.read_write()
    api.option('test1').value.set(1)
    raises(ValueError, "api.option('test1').value.set('yes')")
    assert api.option('test1').value.get() == 1
    api.property.pop('validator')
    api.option('test1').value.set('yes')
    assert api.option('test1').value.get() == 'yes'
    api.property.add('validator')
    raises(ValueError, "api.option('test1').value.get()")
    api.option('test1').value.reset()
    assert api.option('test1').value.get() is None


#def test_delete_config_with_subconfig():
#    test = IntOption('test', '')
#    multi = IntOption('multi', '', multi=True)
#    od = OptionDescription('od', '', [test, multi])
#    odroot = OptionDescription('odroot', '', [od])
#    cfg = Config(odroot)
#    api = getapi(cfg)
#    sub = cfg.od
#    val = cfg.cfgimpl_get_values()
#    setting = cfg.cfgimpl_get_settings()
#    assert api.option('od.test').value.get() is None
#    assert api.option('od.multi').value.get() == []
#    api.config.make_dict()
#    del(api)
#    del(cfg)
#    raises(ConfigError, 'val[test]')
#    raises(ConfigError, 'val[multi]')
#    raises(ConfigError, 'setting[test]')
#    raises(ConfigError, 'sub.make_dict()')


def test_subconfig():
    i = IntOption('i', '')
    o = OptionDescription('val', '', [i])
    o2 = OptionDescription('val', '', [o])
    c = Config(o2)
    c
    raises(TypeError, "SubConfig(i, weakref.ref(c))")


#def test_config_weakref():
#    o = OptionDescription('val', '', [])
#    o2 = OptionDescription('val', '', [o])
#    c = Config(o2)
#    SubConfig(o, weakref.ref(c))
#    raises(ValueError, "SubConfig(o, c)")
#    s = SubConfig(o, weakref.ref(c))
#    assert s._cfgimpl_get_context() == c
#    del(c)
#    raises(ConfigError, "s._cfgimpl_get_context()")


#def test_config_str():
#    gcdummy = BoolOption('dummy', 'dummy', default=False)
#    gcdummy1 = BoolOption('dummy1', 'dummy', default=False, properties=('disabled',))
#    o = OptionDescription('o', '', [gcdummy, gcdummy1])
#    descr = OptionDescription('tiramisu', '', [o])
#    cfg = Config(descr)
#    api = getapi(cfg)
#    api.property.read_only()
#    str(cfg)
#    str(cfg.o)


#def test_config_od_function():
#    gcdummy = BoolOption('dummy', 'dummy', default=False)
#    gcdummy1 = BoolOption('dummy1', 'dummy', default=False, properties=('disabled',))
#    o = OptionDescription('o', '', [gcdummy, gcdummy1])
#    descr = OptionDescription('tiramisu', '', [o])
#    cfg = Config(descr)
#    try:
#        print(cfg.impl_get_opt_by_path())
#    except AttributeError as err:
#        assert str(err) == _('unknown Option {0} in OptionDescription {1}'
#                             '').format('impl_get_opt_by_path', descr.impl_getname())


def test_config_subconfig():
    i1 = IntOption('i1', '')
    i2 = IntOption('i2', '', default=1)
    i3 = IntOption('i3', '')
    i4 = IntOption('i4', '', default=2)
    od1 = OptionDescription('od1', '', [i1, i2, i3, i4])
    od2 = OptionDescription('od2', '', [od1])
    conf1 = Config(od2, session_id='conf1')
    api = getapi(conf1)
    raises(ConfigError, "conf2 = Config(od1, session_id='conf2')")