# coding: utf-8
import autopath
from copy import copy
from tiramisu import setting
setting.expires_time = 1
from tiramisu.option import IPOption, OptionDescription, BoolOption, IntOption, StrOption
from tiramisu.config import Config
from tiramisu.error import PropertiesOptionError, RequirementError
from py.test import raises


def test_requires():
    a = BoolOption('activate_service', '', True)
    b = IPOption('ip_address_service', '',
                 requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
    od = OptionDescription('service', '', [a, b])
    c = Config(od)
    c.read_write()
    c.ip_address_service
    c.activate_service = False
    props = []
    try:
        c.ip_address_service
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']
    c.activate_service = True
    c.ip_address_service


def test_requires_with_requires():
    a = BoolOption('activate_service', '', True)
    b = IPOption('ip_address_service', '',
                 requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
    od = OptionDescription('service', '', [a, b])
    c = Config(od)
    c.read_write()
    c.cfgimpl_get_settings()[b].append('test')
    c.ip_address_service
    c.activate_service = False
    props = []
    try:
        c.ip_address_service
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']
    c.activate_service = True
    c.ip_address_service


def test_requires_invalid():
    a = BoolOption('activate_service', '', True)
    raises(ValueError, "IPOption('ip_address_service', '', requires='string')")
    raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False, 'action': 'disabled', 'unknown': True}])")
    raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False}])")
    raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'action': 'disabled'}])")
    raises(ValueError, "IPOption('ip_address_service', '', requires=[{'expected': False, 'action': 'disabled'}])")
    raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False, 'action': 'disabled', 'inverse': 'string'}])")
    raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False, 'action': 'disabled', 'transitive': 'string'}])")
    raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False, 'action': 'disabled', 'same_action': 'string'}])")
    raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': 'string', 'expected': False, 'action': 'disabled'}])")
    raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': 'string', 'action': 'disabled'}])")


def test_requires_same_action():
    a = BoolOption('activate_service', '', True)
    b = BoolOption('activate_service_web', '', True,
                   requires=[{'option': a, 'expected': False, 'action': 'new'}])

    d = IPOption('ip_address_service_web', '',
                 requires=[{'option': b, 'expected': False,
                            'action': 'disabled', 'inverse': False,
                            'transitive': True, 'same_action': False}])
    od = OptionDescription('service', '', [a, b, d])
    c = Config(od)
    c.read_write()
    c.cfgimpl_get_settings().append('new')
    c.activate_service
    c.activate_service_web
    c.ip_address_service_web
    c.activate_service = False
    #
    props = []
    try:
        c.activate_service_web
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['new']
    #
    props = []
    try:
        c.ip_address_service_web
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']


def test_multiple_requires():
    a = StrOption('activate_service', '')
    b = IPOption('ip_address_service', '',
                 requires=[{'option': a, 'expected': 'yes', 'action': 'disabled'},
                           {'option': a, 'expected': 'ok', 'action': 'disabled'}])
    od = OptionDescription('service', '', [a, b])
    c = Config(od)
    c.read_write()
    c.ip_address_service
    c.activate_service = 'yes'
    props = []
    try:
        c.ip_address_service
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']

    c.activate_service = 'ok'
    props = []
    try:
        c.ip_address_service
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']

    c.activate_service = 'no'
    c.ip_address_service


def test_multiple_requires_cumulative():
    a = StrOption('activate_service', '')
    b = IPOption('ip_address_service', '',
                 requires=[{'option': a, 'expected': 'yes', 'action': 'disabled'},
                           {'option': a, 'expected': 'yes', 'action': 'hidden'}])
    od = OptionDescription('service', '', [a, b])
    c = Config(od)
    c.read_write()
    c.ip_address_service
    c.activate_service = 'yes'
    props = []
    try:
        c.ip_address_service
    except PropertiesOptionError as err:
        props = err.proptype
    assert set(props) == set(['hidden', 'disabled'])

    c.activate_service = 'ok'
    c.ip_address_service

    c.activate_service = 'no'
    c.ip_address_service


def test_multiple_requires_cumulative_inverse():
    a = StrOption('activate_service', '')
    b = IPOption('ip_address_service', '',
                 requires=[{'option': a, 'expected': 'yes', 'action': 'disabled', 'inverse': True},
                           {'option': a, 'expected': 'yes', 'action': 'hidden', 'inverse': True}])
    od = OptionDescription('service', '', [a, b])
    c = Config(od)
    c.read_write()
    props = []
    try:
        c.ip_address_service
    except PropertiesOptionError as err:
        props = err.proptype
    assert set(props) == set(['hidden', 'disabled'])
    c.activate_service = 'yes'
    c.ip_address_service

    c.activate_service = 'ok'
    props = []
    try:
        c.ip_address_service
    except PropertiesOptionError as err:
        props = err.proptype
    assert set(props) == set(['hidden', 'disabled'])

    c.activate_service = 'no'
    props = []
    try:
        c.ip_address_service
    except PropertiesOptionError as err:
        props = err.proptype
    assert set(props) == set(['hidden', 'disabled'])


def test_multiple_requires_inverse():
    a = StrOption('activate_service', '')
    b = IPOption('ip_address_service', '',
                 requires=[{'option': a, 'expected': 'yes', 'action': 'disabled', 'inverse': True},
                           {'option': a, 'expected': 'ok', 'action': 'disabled', 'inverse': True}])
    od = OptionDescription('service', '', [a, b])
    c = Config(od)
    c.read_write()
    props = []
    try:
        c.ip_address_service
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']

    c.activate_service = 'yes'
    c.ip_address_service

    c.activate_service = 'ok'
    c.ip_address_service

    c.activate_service = 'no'
    props = []
    try:
        c.ip_address_service
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']


def test_requires_transitive():
    a = BoolOption('activate_service', '', True)
    b = BoolOption('activate_service_web', '', True,
                   requires=[{'option': a, 'expected': False, 'action': 'disabled'}])

    d = IPOption('ip_address_service_web', '',
                 requires=[{'option': b, 'expected': False, 'action': 'disabled'}])
    od = OptionDescription('service', '', [a, b, d])
    c = Config(od)
    c.read_write()
    c.activate_service
    c.activate_service_web
    c.ip_address_service_web
    c.activate_service = False
    #
    props = []
    try:
        c.activate_service_web
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']
    #
    props = []
    try:
        c.ip_address_service_web
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']


def test_requires_transitive_owner():
    a = BoolOption('activate_service', '', True)
    b = BoolOption('activate_service_web', '', True,
                   requires=[{'option': a, 'expected': False, 'action': 'disabled'}])

    d = IPOption('ip_address_service_web', '',
                 requires=[{'option': b, 'expected': False, 'action': 'disabled'}])
    od = OptionDescription('service', '', [a, b, d])
    c = Config(od)
    c.read_write()
    c.activate_service
    c.activate_service_web
    c.ip_address_service_web
    #no more default value
    c.ip_address_service_web = '1.1.1.1'
    c.activate_service = False
    props = []
    try:
        c.ip_address_service_web
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']


def test_requires_transitive_bis():
    a = BoolOption('activate_service', '', True)
    abis = BoolOption('activate_service_bis', '', True)
    b = BoolOption('activate_service_web', '', True,
                   requires=[{'option': a, 'expected': True, 'action': 'disabled', 'inverse': True}])

    d = IPOption('ip_address_service_web', '',
                 requires=[{'option': b, 'expected': True, 'action': 'disabled', 'inverse': True}])
    od = OptionDescription('service', '', [a, abis, b, d])
    c = Config(od)
    c.read_write()
    #
    c.activate_service_web
    c.ip_address_service_web
    c.activate_service = False
    #
    props = []
    try:
        c.activate_service_web
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']
    #
    props = []
    try:
        c.ip_address_service_web
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']


def test_requires_transitive_hidden_disabled():
    a = BoolOption('activate_service', '', True)
    b = BoolOption('activate_service_web', '', True,
                   requires=[{'option': a, 'expected': False, 'action': 'hidden'}])
    d = IPOption('ip_address_service_web', '',
                 requires=[{'option': b, 'expected': False, 'action': 'disabled'}])
    od = OptionDescription('service', '', [a, b, d])
    c = Config(od)
    c.read_write()
    c.activate_service
    c.activate_service_web
    c.ip_address_service_web
    c.activate_service = False
    #
    props = []
    try:
        c.activate_service_web
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['hidden']
    raises(RequirementError, 'c.ip_address_service_web')


def test_requires_not_transitive():
    a = BoolOption('activate_service', '', True)
    b = BoolOption('activate_service_web', '', True,
                   requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
    d = IPOption('ip_address_service_web', '',
                 requires=[{'option': b, 'expected': False,
                            'action': 'disabled', 'transitive': False}])
    od = OptionDescription('service', '', [a, b, d])
    c = Config(od)
    c.read_write()
    c.activate_service
    c.activate_service_web
    c.ip_address_service_web
    c.activate_service = False
    #
    props = []
    try:
        c.activate_service_web
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']
    #
    c.ip_address_service_web


def test_requires_None():
    a = BoolOption('activate_service', '')
    b = IPOption('ip_address_service', '',
                 requires=[{'option': a, 'expected': None, 'action': 'disabled'}])
    od = OptionDescription('service', '', [a, b])
    c = Config(od)
    c.read_write()
    props = []
    try:
        c.ip_address_service
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']
    c.activate_service = False
    c.ip_address_service


def test_requires_multi_disabled():
    a = BoolOption('activate_service', '')
    b = IntOption('num_service', '')
    c = IPOption('ip_address_service', '',
                 requires=[{'option': a, 'expected': True, 'action': 'disabled'},
                           {'option': b, 'expected': 1, 'action': 'disabled'}])
    od = OptionDescription('service', '', [a, b, c])
    c = Config(od)
    c.read_write()

    c.ip_address_service

    c.activate_service = True
    props = []
    try:
        c.ip_address_service
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']

    c.activate_service = False
    c.ip_address_service

    c.num_service = 1
    props = []
    try:
        c.ip_address_service
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']

    c.activate_service = True
    props = []
    try:
        c.ip_address_service
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']


def test_requires_multi_disabled_inverse():
    a = BoolOption('activate_service', '')
    b = IntOption('num_service', '')
    c = IPOption('ip_address_service', '',
                 requires=[{'option': a, 'expected': True,
                            'action': 'disabled', 'inverse': True},
                           {'option': b, 'expected': 1,
                            'action': 'disabled', 'inverse': True}])
    od = OptionDescription('service', '', [a, b, c])
    c = Config(od)
    c.read_write()

    props = []
    try:
        c.ip_address_service
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']

    c.activate_service = True
    props = []
    try:
        c.ip_address_service
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']

    c.activate_service = False
    props = []
    try:
        c.ip_address_service
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']

    c.num_service = 1
    props = []
    try:
        c.ip_address_service
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']

    c.activate_service = True
    c.ip_address_service


def test_requires_multi_disabled_2():
    a = BoolOption('a', '')
    b = BoolOption('b', '')
    c = BoolOption('c', '')
    d = BoolOption('d', '')
    e = BoolOption('e', '')
    f = BoolOption('f', '')
    g = BoolOption('g', '')
    h = BoolOption('h', '')
    i = BoolOption('i', '')
    j = BoolOption('j', '')
    k = BoolOption('k', '')
    l = BoolOption('l', '')
    m = BoolOption('m', '')
    list_bools = [a, b, c, d, e, f, g, h, i, j, k, l, m]
    requires = []
    for boo in list_bools:
        requires.append({'option': boo, 'expected': True, 'action': 'disabled'})
    z = IPOption('z', '', requires=requires)
    y = copy(list_bools)
    y.append(z)
    od = OptionDescription('service', '', y)
    cfg = Config(od)
    cfg.read_write()

    cfg.z
    for boo in list_bools:
        setattr(cfg, boo._name, True)
        props = []
        try:
            cfg.z
        except PropertiesOptionError as err:
            props = err.proptype
        assert props == ['disabled']
    for boo in list_bools:
        setattr(cfg, boo._name, False)
        if boo == m:
            cfg.z
        else:
            props = []
            try:
                cfg.z
            except PropertiesOptionError as err:
                props = err.proptype
            assert props == ['disabled']


def test_requires_multi_disabled_inverse_2():
    a = BoolOption('a', '')
    b = BoolOption('b', '')
    c = BoolOption('c', '')
    d = BoolOption('d', '')
    e = BoolOption('e', '')
    f = BoolOption('f', '')
    g = BoolOption('g', '')
    h = BoolOption('h', '')
    i = BoolOption('i', '')
    j = BoolOption('j', '')
    k = BoolOption('k', '')
    l = BoolOption('l', '')
    m = BoolOption('m', '')
    list_bools = [a, b, c, d, e, f, g, h, i, j, k, l, m]
    requires = []
    for boo in list_bools:
        requires.append({'option': boo, 'expected': True, 'action': 'disabled',
                         'inverse': True})
    z = IPOption('z', '', requires=requires)
    y = copy(list_bools)
    y.append(z)
    od = OptionDescription('service', '', y)
    cfg = Config(od)
    cfg.read_write()

    props = []
    try:
        cfg.z
    except PropertiesOptionError as err:
        props = err.proptype
    assert props == ['disabled']
    for boo in list_bools:
        setattr(cfg, boo._name, True)
        if boo == m:
            cfg.z
        else:
            props = []
            try:
                cfg.z
            except PropertiesOptionError as err:
                props = err.proptype
            assert props == ['disabled']
    for boo in list_bools:
        setattr(cfg, boo._name, False)
        props = []
        try:
            cfg.z
        except PropertiesOptionError as err:
            props = err.proptype
        assert props == ['disabled']


def test_requires_requirement_append():
    a = BoolOption('activate_service', '', True)
    b = IPOption('ip_address_service', '',
                 requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
    od = OptionDescription('service', '', [a, b])
    c = Config(od)
    c.read_write()
    str(c.cfgimpl_get_settings())
    str(c.cfgimpl_get_settings()[b])
    raises(ValueError, 'c.cfgimpl_get_settings()[b].append("disabled")')
    c.activate_service = False
    # disabled is now set, test to remove disabled before store in storage
    c.cfgimpl_get_settings()[b].append("test")


def test_requires_different_inverse():
    a = BoolOption('activate_service', '', True)
    raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': True, 'action': 'disabled', 'inverse': True}, {'option': a, 'expected': True, 'action': 'disabled', 'inverse': False}])")


def test_requires_recursive_path():
    a = BoolOption('activate_service', '', True)
    b = IPOption('ip_address_service', '',
                 requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
    od1 = OptionDescription('service', '', [a, b], requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
    od = OptionDescription('base', '', [od1])
    c = Config(od)
    c.read_write()
    raises(RequirementError, 'c.service.a')


def test_get_properties_with_None_path():
    a = BoolOption('activate_service', '', True)
    b = IPOption('ip_address_service', '',
                 requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
    od1 = OptionDescription('service', '', [a, b], requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
    od = OptionDescription('base', '', [od1])
    c = Config(od)
    c.read_write()
    raises(ValueError, "c.cfgimpl_get_settings()._getproperties(a)")


def test_set_item():
    a = BoolOption('activate_service', '', True)
    b = IPOption('ip_address_service', '')
    od1 = OptionDescription('service', '', [a, b])
    od = OptionDescription('base', '', [od1])
    c = Config(od)
    c.read_write()
    raises(ValueError, 'c.cfgimpl_get_settings()[a] = ("test",)')


def test_properties_conflict():
    a = BoolOption('activate_service', '', True)
    raises(ValueError, "IPOption('ip_address_service', '', properties=('disabled',), requires=[{'option': a, 'expected': False, 'action': 'disabled'}])")
    raises(ValueError, "od1 = OptionDescription('service', '', [a], properties=('disabled',), requires=[{'option': a, 'expected': False, 'action': 'disabled'}])")