from pymasep.common.math import GridTools


def test_direction_grid_neighbor_manhattan_all_test():
    pos1 = (10, 10)

    pos2 = (10, 11)
    assert GridTools.direction_grid_neighbor(pos1, pos2) == 'S'
    pos2 = (11, 10)
    assert GridTools.direction_grid_neighbor(pos1, pos2) == 'E'
    pos2 = (10, 9)
    assert GridTools.direction_grid_neighbor(pos1, pos2) == 'N'
    pos2 = (9, 10)
    assert GridTools.direction_grid_neighbor(pos1, pos2) == 'W'
    pos2 = (11, 11)
    assert GridTools.direction_grid_neighbor(pos1, pos2) is None
    pos2 = (9, 9)
    assert GridTools.direction_grid_neighbor(pos1, pos2) is None
    pos2 = (11, 9)
    assert GridTools.direction_grid_neighbor(pos1, pos2) is None
    pos2 = (9, 11)
    assert GridTools.direction_grid_neighbor(pos1, pos2) is None
    pos2 = (10, 10)
    assert GridTools.direction_grid_neighbor(pos1, pos2) is None


def test_direction_grid_neighbor_euclidian_all_test():
    pos1 = (10, 10)

    pos2 = (10, 11)
    assert GridTools.direction_grid_neighbor(pos1, pos2, dist_type='euclidian') == 'S'
    pos2 = (11, 10)
    assert GridTools.direction_grid_neighbor(pos1, pos2, dist_type='euclidian') == 'E'
    pos2 = (10, 9)
    assert GridTools.direction_grid_neighbor(pos1, pos2, dist_type='euclidian') == 'N'
    pos2 = (9, 10)
    assert GridTools.direction_grid_neighbor(pos1, pos2, dist_type='euclidian') == 'W'
    pos2 = (11, 11)
    assert GridTools.direction_grid_neighbor(pos1, pos2, dist_type='euclidian') == 'SE'
    pos2 = (9, 9)
    assert GridTools.direction_grid_neighbor(pos1, pos2, dist_type='euclidian') == 'NW'
    pos2 = (11, 9)
    assert GridTools.direction_grid_neighbor(pos1, pos2, dist_type='euclidian') == 'NE'
    pos2 = (9, 11)
    assert GridTools.direction_grid_neighbor(pos1, pos2, dist_type='euclidian') == 'SW'
    pos2 = (10, 10)
    assert GridTools.direction_grid_neighbor(pos1, pos2, dist_type='euclidian') is None
    pos2 = (12, 12)
    assert GridTools.direction_grid_neighbor(pos1, pos2, dist_type='euclidian') is None


def test_is_connected_neighbor():
    data_map = [[0x9, 0x1, 0x1, 0x5, 0xA, 0x2],
                [0x8, 0x0, 0x0, 0x0, 0x3, 0x3],
                [0x8, 0x0, 0x0, 0x4, 0x9, 0x1],
                [0xA, 0x2, 0x2, 0x4, 0x8, 0x2]]
    # Ok South
    assert GridTools.is_connected_neighbor(data_map, (0, 0), (0, 1)) is True
    # Ok East
    assert GridTools.is_connected_neighbor(data_map, (0, 0), (1, 0)) is True
    # Ok West
    assert GridTools.is_connected_neighbor(data_map, (1, 1), (0, 1)) is True
    # Ok North
    assert GridTools.is_connected_neighbor(data_map, (1, 1), (1, 0)) is True
    # Blocked East
    assert GridTools.is_connected_neighbor(data_map, (3, 2), (4, 2)) is False
    # Blocked West
    assert GridTools.is_connected_neighbor(data_map, (4, 2), (3, 2)) is False
    # Blocked North
    assert GridTools.is_connected_neighbor(data_map, (0, 0), (-1, 0)) is False
    # Blocked South
    assert GridTools.is_connected_neighbor(data_map, (0, 3), (0, 4)) is False


def test_is_connected_by_direction():
    data_map = [[0x9, 0x1, 0x1, 0x5, 0xA, 0x2],
                [0x8, 0x0, 0x0, 0x0, 0x3, 0x3],
                [0x8, 0x0, 0x0, 0x4, 0x9, 0x1],
                [0xA, 0x2, 0x2, 0x4, 0x8, 0x2]]
    # Ok South
    assert GridTools.is_connected_by_direction(data_map, (0, 0), 'S') is True
    # Ok East
    assert GridTools.is_connected_by_direction(data_map, (0, 0), 'E') is True
    # Ok West
    assert GridTools.is_connected_by_direction(data_map, (1, 1), 'W') is True
    # Ok North
    assert GridTools.is_connected_by_direction(data_map, (1, 1), 'N') is True
    # Blocked East
    assert GridTools.is_connected_by_direction(data_map, (3, 2), 'E') is False
    # Blocked West
    assert GridTools.is_connected_by_direction(data_map, (4, 2), 'W') is False
    # Blocked North
    assert GridTools.is_connected_by_direction(data_map, (0, 0), 'N') is False
    # Blocked South
    assert GridTools.is_connected_by_direction(data_map, (0, 3), 'S') is False


def test_create_graph():
    data_map = [[0x9, 0x1, 0x1, 0x5, 0xA, 0x2],
                [0x8, 0x0, 0x0, 0x0, 0x3, 0x3],
                [0x8, 0x0, 0x0, 0x4, 0x9, 0x1],
                [0xA, 0x2, 0x2, 0x4, 0x8, 0x2]]

    graph = GridTools.create_graph(data_map)

    assert len(graph.nodes) == 24
    assert len(graph.edges) == 62
    # testing some edges
    assert graph.has_edge((0, 0), (0, 1)) is True
    assert graph.has_edge((0, 1), (0, 0)) is True
    assert graph.has_edge((0, 0), (0, 2)) is False
    assert graph.has_edge((3, 1), (3, 2)) is True
    assert graph.has_edge((4, 2), (3, 2)) is False
    assert graph.has_edge((3, 2), (4, 2)) is False


def test_adapt_path_from_selected_one_close_added():
    data_map = [[0x9, 0x1, 0x1, 0x5, 0xA, 0x2],
                [0x8, 0x0, 0x0, 0x0, 0x3, 0x3],
                [0x8, 0x0, 0x0, 0x4, 0x9, 0x1],
                [0xA, 0x2, 0x2, 0x4, 0x8, 0x2]]
    graph = GridTools.create_graph(data_map)
    orgin = (0, 0)
    path = []
    selected = (0, 1)
    expected_result = [(0, 1)]

    result = GridTools.adapt_path_from_selected(graph, orgin, path, selected)

    assert result == expected_result


def test_adapt_path_from_selected_one_far_added():
    data_map = [[0x9, 0x1, 0x1, 0x5, 0xA, 0x2],
                [0x8, 0x0, 0x0, 0x0, 0x3, 0x3],
                [0x8, 0x0, 0x0, 0x4, 0x9, 0x1],
                [0xA, 0x2, 0x2, 0x4, 0x8, 0x2]]
    graph = GridTools.create_graph(data_map)
    orgin = (0, 0)
    path = []
    selected = (0, 2)
    expected_result = []

    result = GridTools.adapt_path_from_selected(graph, orgin, path, selected)

    assert result == expected_result


def test_adapt_path_from_selected_one_close_added_to_path():
    data_map = [[0x9, 0x1, 0x1, 0x5, 0xA, 0x2],
                [0x8, 0x0, 0x0, 0x0, 0x3, 0x3],
                [0x8, 0x0, 0x0, 0x4, 0x9, 0x1],
                [0xA, 0x2, 0x2, 0x4, 0x8, 0x2]]
    graph = GridTools.create_graph(data_map)
    orgin = (3, 1)
    path = [(4, 1)]
    selected = (5, 1)
    expected_result = [(4, 1), (5, 1)]

    result = GridTools.adapt_path_from_selected(graph, orgin, path, selected)

    assert result == expected_result


def test_adapt_path_from_selected_one_not_connected_added_to_path():
    data_map = [[0x9, 0x1, 0x1, 0x5, 0xA, 0x2],
                [0x8, 0x0, 0x0, 0x0, 0x3, 0x3],
                [0x8, 0x0, 0x0, 0x4, 0x9, 0x1],
                [0xA, 0x2, 0x2, 0x4, 0x8, 0x2]]
    graph = GridTools.create_graph(data_map)
    orgin = (3, 1)
    path = [(4, 1), (5, 1)]
    selected = (5, 2)
    expected_result = [(4, 1), (5, 1)]

    result = GridTools.adapt_path_from_selected(graph, orgin, path, selected)

    assert result == expected_result


def test_adapt_path_from_selected_delete_last():
    data_map = [[0x9, 0x1, 0x1, 0x5, 0xA, 0x2],
                [0x8, 0x0, 0x0, 0x0, 0x3, 0x3],
                [0x8, 0x0, 0x0, 0x4, 0x9, 0x1],
                [0xA, 0x2, 0x2, 0x4, 0x8, 0x2]]
    graph = GridTools.create_graph(data_map)
    orgin = (2, 1)
    path = [(3, 1), (4, 1), (5, 1)]
    selected = (5, 1)
    expected_result = [(3, 1), (4, 1)]

    result = GridTools.adapt_path_from_selected(graph, orgin, path, selected)

    assert result == expected_result


def test_adapt_path_from_selected_delete_middle():
    data_map = [[0x9, 0x1, 0x1, 0x5, 0xA, 0x2],
                [0x8, 0x0, 0x0, 0x0, 0x3, 0x3],
                [0x8, 0x0, 0x0, 0x4, 0x9, 0x1],
                [0xA, 0x2, 0x2, 0x4, 0x8, 0x2]]
    graph = GridTools.create_graph(data_map)
    orgin = (2, 1)
    path = [(3, 1), (4, 1), (5, 1)]
    selected = (4, 1)
    expected_result = [(3, 1)]

    result = GridTools.adapt_path_from_selected(graph, orgin, path, selected)

    assert result == expected_result


def test_adapt_path_from_selected_delete_first():
    data_map = [[0x9, 0x1, 0x1, 0x5, 0xA, 0x2],
                [0x8, 0x0, 0x0, 0x0, 0x3, 0x3],
                [0x8, 0x0, 0x0, 0x4, 0x9, 0x1],
                [0xA, 0x2, 0x2, 0x4, 0x8, 0x2]]
    graph = GridTools.create_graph(data_map)
    orgin = (2, 1)
    path = [(3, 1), (4, 1), (5, 1)]
    selected = (3, 1)
    expected_result = []

    result = GridTools.adapt_path_from_selected(graph, orgin, path, selected)

    assert result == expected_result
