# coding: utf-8
from py.test import raises

from .autopath import do_autopath
do_autopath()

from tiramisu.setting import owners
from tiramisu import ChoiceOption, StrOption, OptionDescription, Config
from tiramisu.error import ConfigError
from tiramisu import undefined, Params, ParamValue, ParamOption
from tiramisu.api import TIRAMISU_VERSION
from tiramisu.storage import list_sessions


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


def return_val(val):
    return val


def return_list():
    return ['val1', 'val2']


def return_calc_list(val):
    return [val]


def return_error(*args, **kwargs):
    raise Exception('test')


def test_choiceoption():
    choice = ChoiceOption('choice', '', values=('val1', 'val2'))
    odesc = OptionDescription('od', '', [choice])
    cfg = Config(odesc)
    cfg.property.read_write()
    owner = cfg.owner.get()
    assert cfg.option('choice').owner.get() == owners.default
    assert cfg.option('choice').owner.isdefault()
    #
    cfg.option('choice').value.set('val1')
    assert cfg.option('choice').owner.get() == owner
    assert not cfg.option('choice').owner.isdefault()
    #
    cfg.option('choice').value.reset()
    assert cfg.option('choice').owner.get() == owners.default
    assert cfg.option('choice').owner.isdefault()
    #
    raises(ValueError, "cfg.option('choice').value.set('no')")
    assert cfg.option('choice').owner.get() == owners.default
    assert cfg.option('choice').owner.isdefault()
    #
    assert cfg.option('choice').value.list() == ('val1', 'val2')


def test_choiceoption_function():
    choice = ChoiceOption('choice', '', values=return_list)
    odesc = OptionDescription('od', '', [choice])
    cfg = Config(odesc)
    cfg.property.read_write()
    owner = cfg.owner.get()
    assert cfg.option('choice').owner.isdefault()
    #
    cfg.option('choice').value.set('val1')
    assert cfg.option('choice').owner.get() == owner
    #
    cfg.option('choice').value.reset()
    assert cfg.option('choice').owner.isdefault()
    #
    raises(ValueError, "cfg.option('choice').value.set('no')")
    assert cfg.option('choice').owner.isdefault()
    #
    assert cfg.option('choice').value.list() == ['val1', 'val2']


def test_choiceoption_function_error():
    choice = ChoiceOption('choice', '', values=return_error)
    odesc = OptionDescription('od', '', [choice])
    cfg = Config(odesc)
    cfg.property.read_write()
    raises(ConfigError, "cfg.option('choice').value.set('val1')")


def test_choiceoption_function_error_args():
    choice = ChoiceOption('choice', '', values=return_error, values_params=Params((ParamValue('val1'),)))
    odesc = OptionDescription('od', '', [choice])
    cfg = Config(odesc)
    cfg.property.read_write()
    raises(ConfigError, "cfg.option('choice').value.set('val1')")


def test_choiceoption_function_error_kwargs():
    choice = ChoiceOption('choice', '', values=return_error, values_params=Params(kwargs={'kwargs': ParamValue('val1')}))
    odesc = OptionDescription('od', '', [choice])
    cfg = Config(odesc)
    cfg.property.read_write()
    raises(ConfigError, "cfg.option('choice').value.set('val1')")


def test_choiceoption_calc_function():
    choice = ChoiceOption('choice', "", values=return_calc_list, values_params=Params((ParamValue('val1'),)))
    odesc = OptionDescription('od', '', [choice])
    cfg = Config(odesc)
    cfg.property.read_write()
    owner = cfg.owner.get()
    assert cfg.option('choice').owner.isdefault()
    #
    cfg.option('choice').value.set('val1')
    assert cfg.option('choice').owner.get() == owner
    #
    cfg.option('choice').value.reset()
    assert cfg.option('choice').owner.isdefault()
    #
    raises(ValueError, "cfg.option('choice').value.set('no')")
    assert cfg.option('choice').owner.isdefault()


def test_choiceoption_calc_opt_function():
    str_ = StrOption('str', '', 'val1')
    choice = ChoiceOption('choice',
                          "",
                          values=return_calc_list,
                          values_params=Params((ParamOption(str_),)))
    odesc = OptionDescription('od', '', [str_, choice])
    cfg = Config(odesc)
    cfg.property.read_write()
    owner = cfg.owner.get()
    assert cfg.option('choice').owner.isdefault()
    #
    cfg.option('choice').value.set('val1')
    assert cfg.option('choice').owner.get() == owner
    #
    cfg.option('choice').value.reset()
    assert cfg.option('choice').owner.isdefault()
    #
    raises(ValueError, "cfg.option('choice').value.set('no')")
    assert cfg.option('choice').owner.isdefault()


def test_choiceoption_calc_opt_function_propertyerror():
    str_ = StrOption('str', '', 'val1', properties=('disabled',))
    choice = ChoiceOption('choice',
                          "",
                          values=return_calc_list,
                          values_params=Params((ParamOption(str_),)))
    odesc = OptionDescription('od', '', [str_, choice])
    cfg = Config(odesc)
    cfg.property.read_write()
    if TIRAMISU_VERSION == 2:
        raises(ValueError, "cfg.option('choice').value.set('no')")
    else:
        raises(ConfigError, "cfg.option('choice').value.set('no')")


def test_choiceoption_calc_opt_multi_function():
    str_ = StrOption('str', '', ['val1'], multi=True)
    choice = ChoiceOption('choice',
                          "",
                          default_multi='val2',
                          values=return_val,
                          values_params=Params((ParamOption(str_),)),
                          multi=True)
    ch2 = ChoiceOption('ch2',
                       "",
                       default=['val2'],
                       values=return_val,
                       values_params=Params((ParamOption(str_),)),
                       multi=True)
    odesc = OptionDescription('od', '', [str_, choice, ch2])
    cfg = Config(odesc)
    cfg.property.read_write()
    owner = cfg.owner.get()
    assert cfg.option('choice').owner.isdefault()
    assert cfg.option('choice').value.get() == []
    #
    cfg.option('choice').value.set(['val1'])
    assert cfg.option('choice').owner.get() == owner
    #
    raises(ValueError, "cfg.option('choice').value.set([undefined])")
    #
    cfg.option('choice').value.set(['val1'])
    assert cfg.option('choice').owner.get() == owner
    #
    cfg.option('choice').value.reset()
    assert cfg.option('choice').owner.isdefault()
    #
    raises(ValueError, "cfg.option('choice').value.set('no')")
    assert cfg.option('choice').owner.isdefault()
    #
    raises(ValueError, "cfg.option('ch2').value.get()")


def test_choiceoption_calc_opt_multi_function_kwargs():
    str_ = StrOption('str', '', ['val1'], multi=True)
    choice = ChoiceOption('choice',
                          "",
                          default_multi='val2',
                          values=return_val,
                          values_params=Params(kwargs={'val': ParamOption(str_)}),
                          multi=True)
    ch2 = ChoiceOption('ch2',
                       "",
                       default=['val2'],
                       values=return_val,
                       values_params=Params(kwargs={'val': ParamOption(str_)}),
                       multi=True)
    odesc = OptionDescription('od', '', [str_, choice, ch2])
    cfg = Config(odesc)
    cfg.property.read_write()
    owner = cfg.owner.get()
    assert cfg.option('choice').owner.isdefault()
    assert cfg.option('choice').value.get() == []
    #
    cfg.option('choice').value.set(['val1'])
    assert cfg.option('choice').owner.get() == owner
    #
    raises(ValueError, "cfg.option('choice').value.set([undefined])")
    #
    cfg.option('choice').value.set(['val1'])
    assert cfg.option('choice').owner.get() == owner
    #
    cfg.option('choice').value.reset()
    assert cfg.option('choice').owner.isdefault()
    #
    raises(ValueError, "cfg.option('choice').value.set('no')")
    assert cfg.option('choice').owner.isdefault()
    #
    raises(ValueError, "cfg.option('ch2').value.get()")


def test_choiceoption_calc_invalid():
    str_ = StrOption('str', '', ['val1'], multi=True)
    str_
    raises(ValueError,
           "choice = ChoiceOption('choice', '', default_multi='val2', values=[1, 2, 3], \
                                  values_params=Params((ParamOption(str_),)), multi=True)")


def test_choiceoption_calc_not_list():
    str_ = StrOption('str', '', 'val1')
    choice = ChoiceOption('choice',
                          "",
                          default_multi='val2',
                          values=return_val,
                          values_params=Params((ParamOption(str_),)),
                          multi=True)
    odesc = OptionDescription('od', '', [str_, choice])
    cfg = Config(odesc)
    cfg.property.read_write()
    raises(ConfigError, "cfg.option('choice').value.set(['val1'])")