import autopath
import warnings
from py.test import raises

from tiramisu.config import Config
from tiramisu.option import StrOption, OptionDescription
from tiramisu.setting import groups
from tiramisu.error import ValueWarning
from tiramisu.i18n import _


def return_true(value, param=None):
    if value == 'val' and param in [None, 'yes']:
        return True


def return_false(value, param=None):
    if value == 'val' and param in [None, 'yes']:
        raise ValueError('error')


def return_val(value, param=None):
    return 'val'


def return_if_val(value):
    if value != 'val':
        raise ValueError('error')


#FIXME il y a une validation sur default_multi ?

def test_validator():
    opt1 = StrOption('opt1', '', validator=return_true, default='val')
    raises(ValueError, "StrOption('opt2', '', validator=return_false, default='val')")
    opt2 = StrOption('opt2', '', validator=return_false)
    root = OptionDescription('root', '', [opt1, opt2])
    cfg = Config(root)
    assert cfg.opt1 == 'val'
    raises(ValueError, "cfg.opt2 = 'val'")


def test_validator_params():
    opt1 = StrOption('opt1', '', validator=return_true, validator_params={'': ('yes',)}, default='val')
    raises(ValueError, "StrOption('opt2', '', validator=return_false, validator_params={'': ('yes',)}, default='val')")
    opt2 = StrOption('opt2', '', validator=return_false, validator_params={'': ('yes',)})
    root = OptionDescription('root', '', [opt1, opt2])
    cfg = Config(root)
    assert cfg.opt1 == 'val'
    raises(ValueError, "cfg.opt2 = 'val'")


def test_validator_params_key():
    opt1 = StrOption('opt1', '', validator=return_true, validator_params={'param': ('yes',)}, default='val')
    raises(TypeError, "StrOption('opt2', '', validator=return_true, validator_params={'param_unknown': ('yes',)}, default='val')")
    root = OptionDescription('root', '', [opt1])
    cfg = Config(root)
    assert cfg.opt1 == 'val'


def test_validator_params_option():
    opt0 = StrOption('opt0', '', default='val')
    raises(ValueError, "opt1 = StrOption('opt1', '', validator=return_true, validator_params={'': ((opt0, False),)}, default='val')")


def test_validator_multi():
    opt1 = StrOption('opt1', '', validator=return_if_val, multi=True)
    root = OptionDescription('root', '', [opt1])
    cfg = Config(root)
    assert cfg.opt1 == []
    cfg.opt1.append('val')
    assert cfg.opt1 == ['val']
    raises(ValueError, "cfg.opt1.append('val1')")
    raises(ValueError, "cfg.opt1 = ['val', 'val1']")


def test_validator_warning():
    opt1 = StrOption('opt1', '', validator=return_true, default='val', warnings_only=True)
    opt2 = StrOption('opt2', '', validator=return_false, warnings_only=True)
    opt3 = StrOption('opt3', '', validator=return_if_val, multi=True, warnings_only=True)
    root = OptionDescription('root', '', [opt1, opt2, opt3])
    cfg = Config(root)
    assert cfg.opt1 == 'val'
    warnings.simplefilter("always", ValueWarning)
    with warnings.catch_warnings(record=True) as w:
        cfg.opt1 = 'val'
    assert w == []
    #
    with warnings.catch_warnings(record=True) as w:
        cfg.opt2 = 'val'
    assert len(w) == 1
    assert w[0].message.opt == opt2
    assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('opt2', 'error')
    #
    with warnings.catch_warnings(record=True) as w:
        cfg.opt3.append('val')
    assert w == []
    #
    with warnings.catch_warnings(record=True) as w:
        cfg.opt3.append('val1')
    assert len(w) == 1
    assert w[0].message.opt == opt3
    assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('opt3', 'error')
    raises(ValueError, "cfg.opt2 = 1")
    #
    with warnings.catch_warnings(record=True) as w:
        cfg.opt2 = 'val'
        cfg.opt3.append('val')
    assert len(w) == 2
    assert w[0].message.opt == opt2
    assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('opt2', 'error')
    assert w[1].message.opt == opt3
    assert str(w[1].message) == _("warning on the value of the option {0}: {1}").format('opt3', 'error')


def test_validator_warning_master_slave():
    ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True, validator=return_false, warnings_only=True)
    netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-reseau", multi=True, validator=return_if_val, warnings_only=True)
    interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
    interface1.impl_set_group_type(groups.master)
    assert interface1.impl_get_group_type() == groups.master
    root = OptionDescription('root', '', [interface1])
    cfg = Config(root)
    warnings.simplefilter("always", ValueWarning)
    with warnings.catch_warnings(record=True) as w:
        cfg.ip_admin_eth0.ip_admin_eth0.append(None)
    assert w == []
    #
    with warnings.catch_warnings(record=True) as w:
        cfg.ip_admin_eth0.netmask_admin_eth0 = ['val1']
    assert len(w) == 1
    assert w[0].message.opt == netmask_admin_eth0
    assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('netmask_admin_eth0', 'error')
    #
    with warnings.catch_warnings(record=True) as w:
        cfg.ip_admin_eth0.ip_admin_eth0 = ['val']
    assert len(w) == 1
    assert w[0].message.opt == ip_admin_eth0
    assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('ip_admin_eth0', 'error')
    #
    with warnings.catch_warnings(record=True) as w:
        cfg.ip_admin_eth0.ip_admin_eth0 = ['val', 'val1', 'val1']
    assert len(w) == 1
    assert w[0].message.opt == ip_admin_eth0
    assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('ip_admin_eth0', 'error')
    #
    with warnings.catch_warnings(record=True) as w:
        cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val', 'val1']
    assert len(w) == 1
    assert w[0].message.opt == ip_admin_eth0
    assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('ip_admin_eth0', 'error')
    #
    warnings.resetwarnings()
    with warnings.catch_warnings(record=True) as w:
        cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val1', 'val']
    assert len(w) == 1
    assert w[0].message.opt == ip_admin_eth0
    assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('ip_admin_eth0', 'error')