from xml.etree.ElementTree import tostring, fromstring

import pymasep as pm
from pymasep.common.exception import CreationException


def test_init(mock_environment):
    expected_name = 'Object1'

    obj = pm.common.Object(environment=mock_environment, name=expected_name,
                           template=mock_environment.game.templates['DefaultObjectTemplate'])

    assert isinstance(obj, pm.common.BaseObject)
    assert isinstance(obj, pm.common.Object)
    assert obj.environment == mock_environment
    assert obj.name == expected_name
    assert obj.object_state is not None
    assert isinstance(obj.object_state, pm.common.ObjectState)
    assert obj.object_state.get_fullname() == expected_name + '.state'


def test_to_xml_transformed(mock_environment):
    expected_xml_str = '<Object name="object1" state="run">' \
                       '<ObjectState name="state" state="run">' \
                       '<Characteristic name="Step0" state="run"><int>0</int></Characteristic>' \
                       '</ObjectState>' \
                       '</Object>'
    obj = pm.common.Object(environment=mock_environment, name='object1',
                           template=mock_environment.game.templates['EmptyObjectTemplate'])
    charac = pm.common.Characteristic(environment=mock_environment, name='Step0',
                                      template=mock_environment.game.templates['CharacInt'])
    charac.value = 0
    obj.object_state.add_characteristic(charac)

    xml_str_result = tostring(obj.to_xml(), encoding='unicode')

    assert xml_str_result == expected_xml_str


def test_to_xml_transformed_init(mock_environment):
    expected_xml_str = '<Object name="object1" state="init">' \
                       '<ObjectState name="state" state="init">' \
                       '<Characteristic name="Step0" state="init"><int /></Characteristic>' \
                       '</ObjectState>' \
                       '</Object>'
    obj = pm.common.Object(environment=mock_environment,
                           name='object1',
                           template=mock_environment.game.templates['EmptyObjectTemplate'])
    charac = pm.common.Characteristic(environment=mock_environment, name='Step0',
                                      template=mock_environment.game.templates['CharacInt'])
    charac.state = 'init'
    obj.object_state.add_characteristic(charac)

    xml_str_result = tostring(obj.to_xml(), encoding='unicode')

    assert xml_str_result == expected_xml_str


def test_from_xml_creation(mock_environment):
    object_xml_str = '<Object name="object1">' \
                     '<ObjectState name="state">' \
                     '<Characteristic name="Step0"><int>0</int></Characteristic>' \
                     '</ObjectState>' \
                     '</Object>'
    xml_node = fromstring(object_xml_str)
    obj = mock_environment.create_base_object(name='', xml_node=xml_node)

    obj.from_xml(environment=mock_environment, xml_node=xml_node)

    assert obj.name == 'object1'
    assert isinstance(obj.object_state, pm.common.ObjectState)
    assert isinstance(obj.object_state.characteristics['Step0'], pm.common.Characteristic)
    assert obj.state == 'run'


def test_from_xml_with_template_only_creation(mock_environment):
    object_xml_str = '<Object name="object1" template="DefaultObjectTemplate"/>'
    xml_node = fromstring(object_xml_str)
    obj = mock_environment.create_base_object(xml_node=xml_node)

    try:
        obj.from_xml(environment=mock_environment, xml_node=xml_node)
    except CreationException as e:
        assert str(e) == 'SubElement must be present if no initializer not present'
    else:
        assert False


def test_from_xml_with_template_initializer_creation(mock_environment):
    object_xml_str = '<Object name="object1" template="DefaultObjectTemplate" initializer="objectinitializer"/>'
    xml_node = fromstring(object_xml_str)
    obj = mock_environment.create_base_object(xml_node=xml_node)

    obj.from_xml(environment=mock_environment, xml_node=xml_node)

    assert obj.state == 'run'
    assert isinstance(obj.object_state, pm.common.ObjectState)
    assert len(obj.object_state.characteristics) == 2
    assert obj.object_state.characteristics['CharacInt'].value == 1
    assert obj.object_state.characteristics['CharacStr'].value == 'OneValue'


def test_from_xml_with_template_initializer_charac_creation(mock_environment):
    object_xml_str = '<Object name="object1" template="DefaultObjectTemplate" initializer="objectinitializer">' \
                     '<ObjectState name="state">' \
                     '<Characteristic name="Step0"><int>1</int></Characteristic>' \
                     '</ObjectState>' \
                     '</Object>'
    xml_node = fromstring(object_xml_str)
    obj = mock_environment.create_base_object(xml_node=xml_node)

    obj.from_xml(environment=mock_environment, xml_node=xml_node)

    assert obj.state == 'run'
    assert isinstance(obj.object_state, pm.common.ObjectState)
    assert isinstance(obj.object_state.characteristics['CharacInt'], pm.common.Characteristic)
    assert isinstance(obj.object_state.characteristics['CharacStr'], pm.common.Characteristic)
    assert isinstance(obj.object_state.characteristics['Step0'], pm.common.Characteristic)
    assert obj.object_state.characteristics['Step0'].value == 1


def test_from_xml_with_template_and_charac_missing_some_initializer(mock_environment):
    object_xml_str = '<Object name="object1" template="DefaultObjectTemplate">' \
                     '<ObjectState name="state">' \
                     '<Characteristic name="Step0"><int>1</int></Characteristic>' \
                     '</ObjectState>' \
                     '</Object>'
    xml_node = fromstring(object_xml_str)
    obj = mock_environment.create_base_object(xml_node=xml_node)

    try:
        obj.from_xml(environment=mock_environment, xml_node=xml_node)
    except CreationException as e:
        assert str(e) == 'Missing initializer for CharacInt characteristic'
    else:
        assert False


def test_from_xml_init_initializer_interface(mock_environment):
    object_xml_str = '<Object name="object1" state="init" initializer="objectinitializerinterface">' \
                     '<ObjectState name="state" state="init">' \
                     '<Characteristic name="CharacInt" state="run"><int>10</int></Characteristic>' \
                     '<Characteristic name="CharacStr" state="init"><str /></Characteristic>' \
                     '<Characteristic name="Step0" state="run"><int>1</int></Characteristic>' \
                     '</ObjectState>' \
                     '</Object>'
    xml_node = fromstring(object_xml_str)
    obj = mock_environment.create_base_object(xml_node=xml_node)

    obj.from_xml(environment=mock_environment, xml_node=xml_node)

    assert obj.state == 'init'
    assert obj.initializer == mock_environment.game.initializers['objectinitializerinterface']
    assert obj.object_state.characteristics['CharacInt'].value == 10
    assert obj.object_state.characteristics['CharacInt'].value_type == int
    assert obj.object_state.characteristics['CharacStr'].value is None
    assert obj.object_state.characteristics['CharacStr'].value_type == str
    assert obj.object_state.characteristics['Step0'].value == 1
    assert obj.object_state.characteristics['Step0'].value_type == int


def test_from_xml_state_obj_state_run_should_run(mock_environment):
    object_xml_str = '<Object name="object1" state="run">' \
                     '<ObjectState name="state" state="run">' \
                     '<Characteristic name="Step0" state="run"><int>0</int></Characteristic>' \
                     '</ObjectState>' \
                     '</Object>'
    xml_node = fromstring(object_xml_str)
    obj = mock_environment.create_base_object(name='', xml_node=xml_node)

    obj.from_xml(environment=mock_environment, xml_node=xml_node)

    assert obj.state == 'run'


def test_state_obj_state_init_should_be_init(mock_environment):
    object_xml_str = '<Object name="object1" state="init">' \
                     '<ObjectState name="state" state="init" initializer="DummyInitializer"/>' \
                     '</Object>'
    xml_node = fromstring(object_xml_str)
    obj = mock_environment.create_base_object(name='', xml_node=xml_node)

    obj.from_xml(environment=mock_environment, xml_node=xml_node)

    assert obj.state == 'init'


def test_id_str(mock_environment):
    object_xml_str = '<Object name="object1" state="run">' \
                     '<ObjectState name="state" state="run">' \
                     '<Characteristic name="Step0" state="run"><int>0</int></Characteristic>' \
                     '</ObjectState>' \
                     '</Object>'
    xml_node = fromstring(object_xml_str)
    obj = mock_environment.create_base_object(name='', xml_node=xml_node)

    obj.from_xml(environment=mock_environment, xml_node=xml_node)

    id_str = obj.id_str()

    assert id_str == 'object1stateStep00'
