from xml.etree.ElementTree import tostring, fromstring

import pymasep as pm


def test_init(mock_environment):
    state = pm.common.State(environment=mock_environment, name='state',
                            template=mock_environment.game.templates['DefaultStateTemplate'])
    assert isinstance(state, pm.common.BaseObject)
    assert isinstance(state, pm.common.State)
    assert state.agents == set()
    assert state.objects == dict()


def test_init_template_with_objects(mock_environment):
    state = pm.common.State(environment=mock_environment, name='State',
                            template=mock_environment.game.templates['SystemStateTemplate'])

    assert 'State.system' in state.objects


def test_add_object_is_agent(mock_environment):
    state = pm.common.State(environment=mock_environment, name='state',
                            template=mock_environment.game.templates['DefaultStateTemplate'])
    ag = pm.common.Agent(environment=mock_environment, name='agent1',
                         template=mock_environment.game.templates['DefaultAgentTemplate'])

    state.add_object(ag)

    assert state.agents == {ag}
    assert state.objects == {ag.get_fullname(): ag}


def test_add_object(mock_environment):
    state = pm.common.State(environment=mock_environment, name='state',
                            template=mock_environment.game.templates['DefaultStateTemplate'])
    obj = pm.common.Object(environment=mock_environment, name='agent1',
                           template=mock_environment.game.templates['DefaultObjectTemplate'])

    state.add_object(obj)

    assert state.agents == set()
    assert state.objects == {obj.get_fullname(): obj}
    assert obj.parent == state


def test_to_xml_transformed(mock_environment):
    expected_xml_str = '<State name="State" state="init" is_final="False" env_step="0">' \
                       '<Object name="system" state="run">' \
                       '<ObjectState name="state" state="run">' \
                       '<Characteristic name="AgentOrder" state="run">' \
                       '<CircularHeadList>' \
                       '<data><list><item><str>State.agent1</str></item></list></data>' \
                       '<head_idx>0</head_idx>' \
                       '</CircularHeadList>' \
                       '</Characteristic>' \
                       '</ObjectState>' \
                       '</Object>' \
                       '<Object name="object1" state="run">' \
                       '<ObjectState name="state" state="run">' \
                       '<Characteristic name="Step0" state="run"><int>0</int></Characteristic>' \
                       '<Characteristic name="StrCharac" state="run"><str>OneValue</str></Characteristic>' \
                       '</ObjectState>' \
                       '</Object>' \
                       '<Agent name="agent1" state="init" initializer="objectinitializerinterface" ' \
                       'controller="test.unit.mocks.controller_mock.ControllerMock">' \
                       '<ObjectState name="state" state="init">' \
                       '<Characteristic name="CharacInt" state="run"><int>1</int></Characteristic>' \
                       '<Characteristic name="CharacStr" state="init"><str /></Characteristic>' \
                       '</ObjectState>' \
                       '</Agent>' \
                       '</State>'
    state = mock_environment.game.init_state(mock_environment)

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

    assert xml_str_result == expected_xml_str


def test_from_xml(mock_environment):
    state_xml_str = '<State name="State" env_step="1">' \
                    '<Agent name="agent1" controller="test.unit.mocks.controller_mock.ControllerMock">' \
                    '<ObjectState name="state">' \
                    '<Characteristic name="Step0"><int>1</int></Characteristic>' \
                    '</ObjectState>' \
                    '</Agent>' \
                    '<Object name="object1">' \
                    '<ObjectState name="state">' \
                    '<Characteristic name="Step0"><int>0</int></Characteristic>' \
                    '</ObjectState>' \
                    '</Object>' \
                    '</State>'
    xml_node = fromstring(state_xml_str)

    state = mock_environment.create_base_object(name='', xml_node=xml_node)

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

    assert state.name == 'State'
    assert state.step == 1
    assert len(state.objects) == 2
    assert isinstance(state.objects['State.object1'], pm.common.Object)
    assert isinstance(state.objects['State.agent1'], pm.common.Agent)
    assert state.objects['State.agent1'] in state.agents


def test_from_xml_with_subclass_template(mock_environment):
    state_xml_str = '<State name="State" template="SystemStateTemplate" />'
    xml_node = fromstring(state_xml_str)
    state = mock_environment.create_base_object(name='', xml_node=xml_node)

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

    assert state.name == 'State'
    assert len(state.objects) == 1
    assert isinstance(state.objects['State.system'], pm.common.Object)


def test_from_xml_state_one_object_init_should_init(mock_environment):
    state_xml_str = '<State name="State">' \
                    '<Agent name="agent1" state="init" controller="test.unit.mocks.controller_mock.ControllerMock">' \
                    '<ObjectState name="state" state="init"/>' \
                    '</Agent>' \
                    '<Object name="object1" state="run">' \
                    '<ObjectState name="state" state="run">' \
                    '<Characteristic name="Step0" state="run"><int>0</int></Characteristic>' \
                    '</ObjectState>' \
                    '</Object>' \
                    '</State>'
    xml_node = fromstring(state_xml_str)
    state = mock_environment.create_base_object(name='', xml_node=xml_node)

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

    assert state.state == 'init'


def test_from_xml_state_all_object_run_should_run(mock_environment):
    state_xml_str = '<State name="State">' \
                    '<Agent name="agent1" state="run" controller="test.unit.mocks.controller_mock.ControllerMock">' \
                    '<ObjectState name="state" state="run">' \
                    '<Characteristic name="Step0" state="run"><int>0</int></Characteristic>' \
                    '</ObjectState>' \
                    '</Agent>' \
                    '<Object name="object1" state="run">' \
                    '<ObjectState name="state" state="run">' \
                    '<Characteristic name="Step0" state="run"><int>0</int></Characteristic>' \
                    '</ObjectState>' \
                    '</Object>' \
                    '</State>'
    xml_node = fromstring(state_xml_str)
    state = mock_environment.create_base_object(name='', xml_node=xml_node)

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

    assert state.state == 'run'


def test_id_str(mock_environment):
    state_xml_str = '<State name="State">' \
                    '<Agent name="agent1" controller="test.unit.mocks.controller_mock.ControllerMock">' \
                    '<ObjectState name="state">' \
                    '<Characteristic name="Step0"><int>0</int></Characteristic>' \
                    '</ObjectState>' \
                    '</Agent>' \
                    '<Object name="object1">' \
                    '<ObjectState name="state">' \
                    '<Characteristic name="Step0"><int>0</int></Characteristic>' \
                    '</ObjectState>' \
                    '</Object>' \
                    '</State>'
    xml_node = fromstring(state_xml_str)
    state = mock_environment.create_base_object(name='', xml_node=xml_node)
    state.from_xml(environment=mock_environment, xml_node=xml_node)

    id_str = state.id_str()

    assert id_str == 'Stateagent1stateStep00object1stateStep00'


def test__eq___true(mock_environment):
    state_xml_str1 = '<State name="State">' \
                     '<Agent name="agent1" controller="test.unit.mocks.controller_mock.ControllerMock">' \
                     '<ObjectState name="state">' \
                     '<Characteristic name="Step0"><int>1</int></Characteristic>' \
                     '</ObjectState>' \
                     '</Agent>' \
                     '<Object name="object1">' \
                     '<ObjectState name="state">' \
                     '<Characteristic name="Step0"><int>0</int></Characteristic>' \
                     '</ObjectState>' \
                     '</Object>' \
                     '</State>'
    state_xml_str2 = '<State name="State">' \
                     '<Agent name="agent1" controller="test.unit.mocks.controller_mock.ControllerMock">' \
                     '<ObjectState name="state">' \
                     '<Characteristic name="Step0"><int>1</int></Characteristic>' \
                     '</ObjectState>' \
                     '</Agent>' \
                     '<Object name="object1">' \
                     '<ObjectState name="state">' \
                     '<Characteristic name="Step0"><int>0</int></Characteristic>' \
                     '</ObjectState>' \
                     '</Object>' \
                     '</State>'
    xml_node1 = fromstring(state_xml_str1)
    state1 = mock_environment.create_base_object(name='', xml_node=xml_node1)
    state1.from_xml(environment=mock_environment, xml_node=xml_node1)

    xml_node2 = fromstring(state_xml_str2)
    state2 = mock_environment.create_base_object(name='', xml_node=xml_node2)
    state2.from_xml(environment=mock_environment, xml_node=xml_node2)

    assert state1 is not state2
    assert state1 == state2


def test__eq___false(mock_environment):
    state_xml_str1 = '<State name="State">' \
                     '<Agent name="agent1" controller="test.unit.mocks.controller_mock.ControllerMock">' \
                     '<ObjectState name="state">' \
                     '<Characteristic name="Step0"><int>1</int></Characteristic>' \
                     '</ObjectState>' \
                     '</Agent>' \
                     '<Object name="object1">' \
                     '<ObjectState name="state">' \
                     '<Characteristic name="Step0"><int>0</int></Characteristic>' \
                     '</ObjectState>' \
                     '</Object>' \
                     '</State>'
    state_xml_str2 = '<State name="State">' \
                     '<Agent name="agent1" controller="test.unit.mocks.controller_mock.ControllerMock">' \
                     '<ObjectState name="state">' \
                     '<Characteristic name="Step0"><int>1</int></Characteristic>' \
                     '</ObjectState>' \
                     '</Agent>' \
                     '<Object name="object1">' \
                     '<ObjectState name="state">' \
                     '<Characteristic name="Step0"><int>1</int></Characteristic>' \
                     '</ObjectState>' \
                     '</Object>' \
                     '</State>'
    xml_node1 = fromstring(state_xml_str1)
    state1 = mock_environment.create_base_object(name='', xml_node=xml_node1)
    state1.from_xml(environment=mock_environment, xml_node=xml_node1)

    xml_node2 = fromstring(state_xml_str2)
    state2 = mock_environment.create_base_object(name='', xml_node=xml_node2)
    state2.from_xml(environment=mock_environment, xml_node=xml_node2)

    assert state1 is not state2
    assert state1 != state2
