# coding: utf-8
from .autopath import do_autopath
do_autopath()
import weakref

from tiramisu import BoolOption, IntOption, StrOption, IPOption, NetmaskOption, \
                     SymLinkOption, OptionDescription, DynOptionDescription, submulti, \
                     Config, GroupConfig, MetaConfig, Params, ParamOption
from tiramisu.storage import list_sessions


def teardown_function(function):
    assert list_sessions() == [], 'session list is not empty when leaving "{}"'.format(function.__name__)


IS_DEREFABLE = True


def funcname(*args, **kwargs):
    return value


def test_deref_storage():
    b = BoolOption('b', '')
    o = OptionDescription('od', '', [b])
    c = Config(o)
    w = weakref.ref(c._config_bag.context.cfgimpl_get_values()._p_)
    del(c)
    assert w() is None


def test_deref_value():
    b = BoolOption('b', '')
    o = OptionDescription('od', '', [b])
    c = Config(o)
    w = weakref.ref(c._config_bag.context.cfgimpl_get_values())
    del(c)
    assert w() is None


def test_deref_setting():
    b = BoolOption('b', '')
    o = OptionDescription('od', '', [b])
    c = Config(o)
    w = weakref.ref(c._config_bag.context.cfgimpl_get_settings())
    del(c)
    assert w() is None


def test_deref_config():
    b = BoolOption('b', '')
    o = OptionDescription('od', '', [b])
    c = Config(o)
    w = weakref.ref(c)
    del(c)
    assert w() is None


def test_deref_option():
    global IS_DEREFABLE
    b = BoolOption('b', '')
    o = OptionDescription('od', '', [b])
    w = weakref.ref(b)
    del(b)
    try:
        assert w() is not None
    except AssertionError:
        IS_DEREFABLE = False
        return
    del(o)
    assert w() is None


def test_deref_optiondescription():
    if not IS_DEREFABLE:
        return
    b = BoolOption('b', '')
    o = OptionDescription('od', '', [b])
    w = weakref.ref(o)
    del(b)
    assert w() is not None
    del(o)
    assert w() is None


def test_deref_option_cache():
    if not IS_DEREFABLE:
        return
    b = BoolOption('b', '')
    o = OptionDescription('od', '', [b])
    o._build_cache()
    w = weakref.ref(b)
    del(b)
    assert w() is not None
    del(o)
    assert w() is None


def test_deref_optiondescription_cache():
    if not IS_DEREFABLE:
        return
    b = BoolOption('b', '')
    o = OptionDescription('od', '', [b])
    o._build_cache()
    w = weakref.ref(o)
    del(b)
    assert w() is not None
    del(o)
    assert w() is None


def test_deref_option_config():
    if not IS_DEREFABLE:
        return
    b = BoolOption('b', '')
    o = OptionDescription('od', '', [b])
    c = Config(o)
    w = weakref.ref(b)
    del(b)
    assert w() is not None
    del(o)
    assert w() is not None
    del(c)
    assert w() is None


def test_deref_optiondescription_config():
    if not IS_DEREFABLE:
        return
    b = BoolOption('b', '')
    o = OptionDescription('od', '', [b])
    c = Config(o)
    w = weakref.ref(o)
    del(b)
    assert w() is not None
    del(o)
    assert w() is not None
    del(c)
    assert w() is None


#def test_deref_groupconfig():
#    if not IS_DEREFABLE:
#        return
#    i1 = IntOption('i1', '')
#    od1 = OptionDescription('od1', '', [i1])
#    od2 = OptionDescription('od2', '', [od1])
#    conf1 = Config(od2, 'conf1')
#    conf2 = Config(od2, 'conf2')
#    meta = GroupConfig([conf1, conf2])
#    w = weakref.ref(conf1)
#    del(conf1)
#    assert w() is not None
#    del(meta)
#    assert w() is None


#def test_deref_metaconfig():
#    if not IS_DEREFABLE:
#        return
#    i1 = IntOption('i1', '')
#    od1 = OptionDescription('od1', '', [i1])
#    od2 = OptionDescription('od2', '', [od1])
#    conf1 = Config(od2, 'conf1')
#    conf2 = Config(od2, 'conf2')
#    meta = MetaConfig([conf1, conf2])
#    w = weakref.ref(conf1)
#    del(conf1)
#    assert w() is not None
#    del(meta)
#    assert w() is None


def test_deref_consistency():
    if not IS_DEREFABLE:
        return
    a = IPOption('a', '')
    b = NetmaskOption('b', '')
    od = OptionDescription('od', '', [a, b])
    b.impl_add_consistency('ip_netmask', a)
    cfg = Config(od)
    w = weakref.ref(a)
    x = weakref.ref(b)
    y = weakref.ref(od)
    z = weakref.ref(cfg)
    assert w() is not None
    assert x() is not None
    assert y() is not None
    assert z() is not None
    del(a)
    del(b)
    assert w() is not None
    assert x() is not None
    assert y() is not None
    assert z() is not None
    del(od)
    assert w() is not None
    assert x() is not None
    assert y() is not None
    assert z() is not None
    del(cfg)
    assert y() is None
    assert z() is None
    #assert w() is None
    #assert x() is None


def test_deref_validator():
    if not IS_DEREFABLE:
        return
    a = StrOption('a', '', default='yes')
    b = StrOption('b', '', validator=funcname, validator_params=Params((ParamOption(a),)), default='val')
    od = OptionDescription('root', '', [a, b])
    cfg = Config(od)
    w = weakref.ref(a)
    x = weakref.ref(b)
    y = weakref.ref(od)
    z = weakref.ref(cfg)
    assert w() is not None
    assert x() is not None
    assert w() is not None
    assert x() is not None
    del(a)
    del(b)
    assert w() is not None
    assert x() is not None
    assert w() is not None
    assert x() is not None
    del(od)
    assert w() is not None
    assert x() is not None
    assert w() is not None
    assert x() is not None
    del(cfg)
    assert y() is None
    assert z() is None
    #assert w() is None
    #assert x() is None


def test_deref_callback():
    if not IS_DEREFABLE:
        return
    a = StrOption('a', "", 'val')
    b = StrOption('b', "", callback=funcname, callback_params=Params((ParamOption(a),)))
    od = OptionDescription('root', '', [a, b])
    cfg = Config(od)
    w = weakref.ref(a)
    x = weakref.ref(b)
    y = weakref.ref(od)
    z = weakref.ref(cfg)
    assert w() is not None
    assert x() is not None
    assert w() is not None
    assert x() is not None
    del(a)
    del(b)
    assert w() is not None
    assert x() is not None
    assert w() is not None
    assert x() is not None
    del(od)
    assert w() is not None
    assert x() is not None
    assert w() is not None
    assert x() is not None
    del(cfg)
    assert y() is None
    assert z() is None
    #assert w() is None
    #assert x() is None


def test_deref_symlink():
    if not IS_DEREFABLE:
        return
    a = BoolOption("a", "", default=False)
    b = SymLinkOption("b", a)
    od = OptionDescription('root', '', [a, b])
    cfg = Config(od)
    w = weakref.ref(a)
    x = weakref.ref(b)
    y = weakref.ref(od)
    z = weakref.ref(cfg)
    assert w() is not None
    assert x() is not None
    assert w() is not None
    assert x() is not None
    del(a)
    del(b)
    assert w() is not None
    assert x() is not None
    assert w() is not None
    assert x() is not None
    del(od)
    assert w() is not None
    assert x() is not None
    assert w() is not None
    assert x() is not None
    del(cfg)
    #assert w() is None
    #assert x() is None
    assert y() is None
    assert z() is None


def test_deref_dyn():
    if not IS_DEREFABLE:
        return
    a = StrOption('a', '', ['val1', 'val2'], multi=True)
    b = StrOption('b', '')
    dod = DynOptionDescription('dod', '', [b], callback=funcname, callback_params=Params((ParamOption(a),)))
    od = OptionDescription('od', '', [dod, a])
    cfg = Config(od)
    w = weakref.ref(a)
    x = weakref.ref(b)
    y = weakref.ref(od)
    z = weakref.ref(cfg)
    assert w() is not None
    assert x() is not None
    assert w() is not None
    assert x() is not None
    del(a)
    del(b)
    assert w() is not None
    assert x() is not None
    assert w() is not None
    assert x() is not None
    del(od)
    del(dod)
    assert w() is not None
    assert x() is not None
    assert w() is not None
    assert x() is not None
    del(cfg)
    #assert w() is None
    #assert x() is None
    assert y() is None
    assert z() is None