# coding: utf-8
from .autopath import do_autopath
do_autopath()
from py.test import raises


from tiramisu.api import TIRAMISU_VERSION
from tiramisu.setting import groups, owners
from tiramisu import StrOption, IntOption, OptionDescription, submulti, MasterSlaves, Config, \
                     MetaConfig, undefined, Params, ParamOption
from tiramisu.error import SlaveError



def return_val(val=None):
    if val is None:
        return 'val'
    else:
        return val


def return_list(value=None):
    return ['val', 'val']


def return_list2(value=None):
    return [['val', 'val']]


def test_unknown_multi():
    raises(ValueError, "StrOption('multi', '', multi='unknown')")


def test_submulti():
    multi = StrOption('multi', '', multi=submulti)
    if TIRAMISU_VERSION == 2:
        default_multi = 'yes'
    else:
        default_multi = ['yes']
    multi2 = StrOption('multi2', '', default_multi=default_multi, multi=submulti)
    multi3 = StrOption('multi3', '', default=[['yes']], multi=submulti)
    od = OptionDescription('od', '', [multi, multi2, multi3])
    api = Config(od)
    assert api.option('multi').owner.get() == owners.default
    assert api.option('multi').value.get() == []
    assert api.option('multi').owner.get() == owners.default
    assert api.option('multi').owner.get() == owners.default
    assert api.option('multi3').value.get() == [['yes']]
    assert api.option('multi').owner.get() == owners.default


def test_submulti_default_multi_not_list():
    raises(ValueError, "StrOption('multi2', '', default_multi='yes', multi=submulti)")


def test_append_submulti():
    multi = StrOption('multi', '', multi=submulti)
    if TIRAMISU_VERSION == 2:
        default_multi = 'yes'
    else:
        default_multi = ['yes']
    multi2 = StrOption('multi2', '', default_multi=default_multi, multi=submulti)
    multi3 = StrOption('multi3', '', default=[['yes']], multi=submulti)
    od = OptionDescription('od', '', [multi, multi2, multi3])
    api = Config(od)
    owner = api.owner.get()
    assert api.option('multi').value.get() == []
    assert api.option('multi').owner.get() == owners.default
    api.option('multi').value.set([undefined])
    assert api.option('multi').owner.get() == owner
    assert api.option('multi').value.get() == [[]]
    api.option('multi').value.set([undefined, ['no']])
    assert api.option('multi').value.get() == [[], ['no']]
    #
    assert api.option('multi2').value.get() == []
    assert api.option('multi2').owner.get() == owners.default
    api.option('multi2').value.set([undefined])
    assert api.option('multi2').owner.get() == owner
    assert api.option('multi2').value.get() == [['yes']]
    api.option('multi2').value.set([undefined, ['no']])
    assert api.option('multi2').value.get() == [['yes'], ['no']]
    #
    assert api.option('multi3').value.get() == [['yes']]
    assert api.option('multi3').owner.get() == owners.default
    api.option('multi3').value.set([undefined, undefined])
    assert api.option('multi3').owner.get() == owner
    assert api.option('multi3').value.get() == [['yes'], []]
    api.option('multi3').value.set([undefined, undefined, ['no']])
    assert api.option('multi3').value.get() == [['yes'], [], ['no']]


def test_append_unvalide_submulti():
    multi = StrOption('multi', '', multi=submulti)
    if TIRAMISU_VERSION == 2:
        default_multi = 'yes'
    else:
        default_multi = ['yes']
    multi2 = StrOption('multi2', '', default_multi=default_multi, multi=submulti)
    multi3 = StrOption('multi3', '', default=[['yes']], multi=submulti)
    od = OptionDescription('od', '', [multi, multi2, multi3])
    api = Config(od)
    assert api.option('multi').value.get() == []
    assert api.option('multi').owner.get() == owners.default
    raises(ValueError, "api.option('multi').value.set([[1]])")
    assert api.option('multi').value.get() == []
    assert api.option('multi').owner.get() == owners.default
    #
    assert api.option('multi2').value.get() == []
    raises(ValueError, "api.option('multi2').value.set(['no'])")
    assert api.option('multi').owner.get() == owners.default
    assert api.option('multi2').value.get() == []
    #
    assert api.option('multi3').value.get() == [['yes']]
    assert api.option('multi3').owner.get() == owners.default
    raises(ValueError, "api.option('multi3').value.set([[1]])")
    assert api.option('multi3').value.get() == [['yes']]
    assert api.option('multi3').owner.get() == owners.default


def test_pop_submulti():
    multi = StrOption('multi', '', multi=submulti)
    if TIRAMISU_VERSION == 2:
        default_multi = 'yes'
    else:
        default_multi = ['yes']
    multi2 = StrOption('multi2', '', default_multi=default_multi, multi=submulti)
    multi3 = StrOption('multi3', '', default=[['yes']], multi=submulti)
    od = OptionDescription('od', '', [multi, multi2, multi3])
    api = Config(od)
    owner = api.owner.get()
    assert api.option('multi').value.get() == []
    assert api.option('multi3').owner.get() == owners.default
    api.option('multi').value.set([['no', 'yes'], ['peharps']])
    assert api.option('multi').owner.get() == owner
    assert api.option('multi').value.get() == [['no', 'yes'], ['peharps']]
    #
    assert api.option('multi3').value.get() == [['yes']]
    assert api.option('multi3').owner.get() == owners.default
    api.option('multi3').value.set([])
    assert api.option('multi').owner.get() == owner
    assert api.option('multi3').value.get() == []
    api.option('multi3').value.reset()
    assert api.option('multi3').owner.get() == owners.default
    api.option('multi3').value.set([[]])
    assert api.option('multi3').owner.get() == owner
    assert api.option('multi3').value.get() == [[]]


def test_callback_submulti_str():
    multi = StrOption('multi', '', multi=submulti, callback=return_val)
    od = OptionDescription('od', '', [multi])
    api = Config(od)
    api.property.read_write()
    owner = api.owner.get()
    assert api.option('multi').owner.get() == owners.default
    assert api.option('multi').value.get() == [['val']]
    api.option('multi').value.set([['val'], undefined])
    assert api.option('multi').owner.get() == owner
    assert api.option('multi').value.get() == [['val'], ['val']]
    api.option('multi').value.reset()
    assert api.option('multi').owner.get() == owners.default


def test_callback_submulti_list():
    multi = StrOption('multi', '', multi=submulti, callback=return_list)
    od = OptionDescription('od', '', [multi])
    api = Config(od)
    api.property.read_write()
    owner = api.owner.get()
    assert api.option('multi').value.get() == [['val', 'val']]
    assert api.option('multi').owner.get() == owners.default
    api.option('multi').value.set([['val', 'val'], undefined])
    assert api.option('multi').owner.get() == owner
    assert api.option('multi').value.get() == [['val', 'val'], ['val', 'val']]
    api.option('multi').value.set([['val', 'val'], undefined, undefined])
    assert api.option('multi').value.get() == [['val', 'val'], ['val', 'val'], ['val', 'val']]
    api.option('multi').value.reset()
    assert api.option('multi').owner.get() == owners.default


def test_callback_submulti_list_list():
    multi = StrOption('multi', '', multi=submulti, callback=return_list2)
    od = OptionDescription('od', '', [multi])
    api = Config(od)
    api.property.read_write()
    owner = api.owner.get()
    assert api.option('multi').value.get() == [['val', 'val']]
    assert api.option('multi').owner.get() == owners.default
    api.option('multi').value.set([['val', 'val'], undefined])
    assert api.option('multi').owner.get() == owner
    assert api.option('multi').value.get() == [['val', 'val'], []]
    api.option('multi').value.reset()
    assert api.option('multi').owner.get() == owners.default


def test_groups_with_master_submulti():
    ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
    netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=submulti)
    interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
    #interface1.impl_set_group_type(groups.master)
    assert interface1.impl_get_group_type() == groups.master


def test_groups_with_master_in_config_submulti():
    ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
    netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=submulti)
    interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
    od = OptionDescription('root', '', [interface1])
    Config(od)
    assert interface1.impl_get_group_type() == groups.master


def test_values_with_master_and_slaves_submulti():
    ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
    netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=submulti)
    interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
    #interface1.impl_set_group_type(groups.master)
    maconfig = OptionDescription('toto', '', [interface1])
    api = Config(maconfig)
    api.property.read_write()
    owner = api.owner.get()
    assert interface1.impl_get_group_type() == groups.master
    assert api.option('ip_admin_eth0.ip_admin_eth0').owner.get() == owners.default
    api.option('ip_admin_eth0.ip_admin_eth0').value.set(["192.168.230.145"])
    assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == ["192.168.230.145"]
    assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == []
    assert api.option('ip_admin_eth0.ip_admin_eth0').owner.get() == owner
    assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).owner.get() == owners.default
    api.option('ip_admin_eth0.ip_admin_eth0').value.set(["192.168.230.145", "192.168.230.147"])
    assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == []
    assert api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == []
    api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set(['255.255.255.0'])
    assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == ['255.255.255.0']
    assert api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == []
    raises(ValueError, "api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set('255.255.255.0')")
    raises(ValueError, "api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set([['255.255.255.0']])")


def test_reset_values_with_master_and_slaves_submulti():
    ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
    netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=submulti)
    interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
    #interface1.impl_set_group_type(groups.master)
    maconfig = OptionDescription('toto', '', [interface1])
    api = Config(maconfig)
    api.property.read_write()
    owner = api.owner.get()
    assert interface1.impl_get_group_type() == groups.master
    assert api.option('ip_admin_eth0.ip_admin_eth0').owner.get() == owners.default
    api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.230.145'])
    assert api.option('ip_admin_eth0.ip_admin_eth0').owner.get() == owner
    assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).owner.get() == owners.default
    api.option('ip_admin_eth0.ip_admin_eth0').value.reset()
    assert api.option('ip_admin_eth0.ip_admin_eth0').owner.get() == owners.default
    assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == []
    #
    api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.230.145'])
    api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set(['255.255.255.0'])
    assert api.option('ip_admin_eth0.ip_admin_eth0').owner.get() == owner
    assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).owner.get() == owner
    api.option('ip_admin_eth0.ip_admin_eth0').value.reset()
    assert api.option('ip_admin_eth0.ip_admin_eth0').owner.get() == owners.default
    assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == []


def test_values_with_master_and_slaves_slave_submulti():
    ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
    netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=submulti)
    interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
    #interface1.impl_set_group_type(groups.master)
    maconfig = OptionDescription('toto', '', [interface1])
    api = Config(maconfig)
    api.property.read_write()
    raises(SlaveError, "api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set(['255.255.255.0'])")
    api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.230.145'])
    api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set(['255.255.255.0'])
    api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set(['255.255.255.0', '255.255.255.0'])
    api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.reset()
    api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set(['255.255.255.0'])
    api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.230.145', '192.168.230.145'])
    assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == ['255.255.255.0']
    assert api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == []
    api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set(['255.255.255.0'])


def test_values_with_master_and_slaves_master_submulti():
    ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
    netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=submulti)
    interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
    #interface1.impl_set_group_type(groups.master)
    maconfig = OptionDescription('toto', '', [interface1])
    api = Config(maconfig)
    api.property.read_write()
    api.option('ip_admin_eth0.ip_admin_eth0').value.set(["192.168.230.145"])
    api.option('ip_admin_eth0.ip_admin_eth0').value.set(["192.168.230.145", "192.168.230.145"])
    api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set(['255.255.255.0'])
    api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.set(['255.255.255.0'])
    assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == ['255.255.255.0']
    assert api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == ['255.255.255.0']
    api.option('ip_admin_eth0.ip_admin_eth0').value.pop(1)
    assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == ["192.168.230.145"]
    assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == ['255.255.255.0']
    api.option('ip_admin_eth0.ip_admin_eth0').value.reset()
    assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == []


def test_values_with_master_owner_submulti():
    ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
    netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=submulti)
    interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
    #interface1.impl_set_group_type(groups.master)
    maconfig = OptionDescription('toto', '', [interface1])
    api = Config(maconfig)
    api.property.read_write()
    owner = api.owner.get()
    assert api.option('ip_admin_eth0.ip_admin_eth0').owner.get() == owners.default
    api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.230.145'])
    assert api.option('ip_admin_eth0.ip_admin_eth0').owner.get() == owner
    assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).owner.get() == owners.default
    api.option('ip_admin_eth0.ip_admin_eth0').value.reset()
    assert api.option('ip_admin_eth0.ip_admin_eth0').owner.get() == owners.default


def test_values_with_master_disabled_submulti():
    ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
    netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=submulti)
    interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
    maconfig = OptionDescription('toto', '', [interface1])
    api = Config(maconfig)
    api.property.read_write()
    api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.230.145'])
    api.option('ip_admin_eth0.ip_admin_eth0').value.pop(0)
    api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.230.145'])
    api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set(['192.168.230.145'])
    api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.reset()
    api.option('ip_admin_eth0.netmask_admin_eth0').property.add('disabled')
    api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.230.145', '192.168.230.145'])
    api.option('ip_admin_eth0.ip_admin_eth0').value.pop(1)
    api.option('ip_admin_eth0.ip_admin_eth0').value.pop(0)

    #delete with value in disabled var
    api.unrestraint.option('ip_admin_eth0.netmask_admin_eth0').property.pop('disabled')
    api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.230.145'])
    api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set(['192.168.230.145'])
    api.unrestraint.option('ip_admin_eth0.netmask_admin_eth0').property.add('disabled')
    api.option('ip_admin_eth0.ip_admin_eth0').value.pop(0)


def test__master_is_submulti():
    ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=submulti)
    netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
    interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
    #interface1.impl_set_group_type(groups.master)
    maconfig = OptionDescription('toto', '', [interface1])
    api = Config(maconfig)
    api.property.read_write()
    owner = api.owner.get()
    assert interface1.impl_get_group_type() == groups.master
    assert api.option('ip_admin_eth0.ip_admin_eth0').owner.isdefault()
    api.option('ip_admin_eth0.ip_admin_eth0').value.set([["192.168.230.145"]])
    assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == [["192.168.230.145"]]
    assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == None
    assert api.option('ip_admin_eth0.ip_admin_eth0').owner.get() == owner
    assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).owner.isdefault()
    api.option('ip_admin_eth0.ip_admin_eth0').value.set([["192.168.230.145"], ["192.168.230.147"]])
    assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == None
    assert api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == None
    api.option('ip_admin_eth0.ip_admin_eth0').value.set([["192.168.230.145", '192.168.1.1'], ["192.168.230.147"]])
    assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == [["192.168.230.145", '192.168.1.1'], ["192.168.230.147"]]
    raises(ValueError, "api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.1', '192.168.1.1'])")


def test_callback_submulti():
    multi = StrOption('multi', '', multi=submulti)
    multi2 = StrOption('multi2', '', multi=submulti, callback=return_val, callback_params=Params(ParamOption(multi)))
    od = OptionDescription('multi', '', [multi, multi2])
    api = Config(od)
    api.property.read_write()
    owner = api.owner.get()
    assert api.option('multi').owner.get() == owners.default
    assert api.option('multi').value.get() == []
    assert api.option('multi2').value.get() == []
    api.option('multi').value.set([['val']])
    assert api.option('multi').owner.get() == owner
    assert api.option('multi2').owner.get() == owners.default
    assert api.option('multi').value.get() == [['val']]
    assert api.option('multi2').value.get() == [['val']]


def test_submulti_unique():
    i = IntOption('int', '', multi=submulti, unique=True)
    o = OptionDescription('od', '', [i])
    api = Config(o)
    assert api.option('int').value.get() == []
    api.option('int').value.set([[0]])
    assert api.option('int').value.get() == [[0]]
    raises(ValueError, "api.option('int').value.set([[0, 0]])")
    api.option('int').value.set([[0], [0]])
    raises(ValueError, "api.option('int').value.set([[1, 0, 2, 3, 4, 5, 6, 0, 7], [0]])")
    api.option('int').value.set([[0, 4, 5, 6], [0]])


def test_submulti_unknown_unique():
    raises(ValueError, "IntOption('int', '', multi=submulti, unique='str')")


def test_unique_not_multi():
    raises(ValueError, "IntOption('int', '', unique=True)")


def test_multi_submulti_meta():
    multi = StrOption('multi', '', multi=submulti)
    od = OptionDescription('od', '', [multi])
    conf1 = Config(od, session_id='conf1')
    conf1.property.read_write()
    conf2 = Config(od, session_id='conf2')
    conf2.property.read_write()
    meta = MetaConfig([conf1, conf2])
    meta.property.read_write()
    meta.option('multi').value.set([['val']])
    assert meta.option('multi').value.get() == [['val']]
    meta.config('conf1').option('multi').value.set([['val', None]])
    assert conf1.option('multi').value.get() == [['val', None]]
    assert meta.config('conf1').option('multi').value.get() == [['val', None]]
    assert meta.option('multi').value.get() == [['val']]


def test_multi_submulti_meta_no_cache():
    multi = StrOption('multi', '', multi=submulti)
    multi = StrOption('multi', '', multi=submulti)
    od = OptionDescription('od', '', [multi])
    conf1 = Config(od, session_id='conf1')
    conf1.property.read_write()
    conf2 = Config(od, session_id='conf2')
    conf1.property.read_write()
    meta = MetaConfig([conf1, conf2])
    meta.property.read_write()
    meta.property.pop('cache')
    meta.option('multi').value.set([['val']])
    assert meta.option('multi').value.get() == [['val']]
    meta.config('conf1').option('multi').value.set([['val', None]])
    assert conf1.option('multi').value.get() == [['val', None]]
    assert meta.config('conf1').option('multi').value.get() == [['val', None]]
    assert meta.option('multi').value.get() == [['val']]