"""
Check things related to STL files
"""

try:
    from . import generic as g
except BaseException:
    import generic as g


class STLTests(g.unittest.TestCase):
    def test_header(self):
        m = g.get_mesh("featuretype.STL")
        # make sure we have the right mesh
        assert g.np.isclose(m.volume, 11.627733431196749, atol=1e-6)

        # should have saved the header from the STL file
        assert len(m.metadata["header"]) > 0

        # should have saved the STL face attributes
        assert len(m.face_attributes["stl"]) == len(m.faces)
        assert len(m.faces) > 1000
        # add a non-correlated face attribute, which should be ignored
        m.face_attributes["nah"] = 10

        # remove all faces except three random ones
        m.update_faces([1, 3, 4])
        # faces and face attributes should be untouched
        assert len(m.faces) == 3
        assert len(m.face_attributes["stl"]) == 3
        # attribute that wasn't len(m.faces) shouldn't have been touched
        assert m.face_attributes["nah"] == 10

    def test_attrib(self):
        m = g.get_mesh("featuretype.STL")

        len_vertices = len(m.vertices)
        # assign some random vertex attributes
        random = g.random(len(m.vertices))
        m.vertex_attributes["random"] = random
        m.vertex_attributes["nah"] = 20

        # should have saved the STL face attributes
        assert len(m.face_attributes["stl"]) == len(m.faces)
        assert len(m.faces) > 1000
        # add a non-correlated face attribute, which should be ignored
        m.face_attributes["nah"] = 10

        # remove all faces except three random ones
        m.update_faces([1, 3, 4])
        # faces and face attributes should be untouched
        assert len(m.faces) == 3
        assert len(m.face_attributes["stl"]) == 3
        # attribute that wasn't len(m.faces) shouldn't have been touched
        assert m.face_attributes["nah"] == 10

        # check all vertices are still in place
        assert m.vertex_attributes["nah"] == 20
        assert g.np.allclose(random, m.vertex_attributes["random"])
        assert len(m.vertices) == len_vertices

        # remove all vertices except four
        v_mask = [0, 1, 2, 3]
        m.update_vertices(v_mask)
        # make sure things are still correct
        assert m.vertex_attributes["nah"] == 20
        assert g.np.allclose(m.vertex_attributes["random"], random[v_mask])
        assert len(m.vertices) == len(v_mask)

    def test_ascii_multibody(self):
        s = g.get_mesh("multibody.stl")
        assert len(s.geometry) == 2
        assert set(s.geometry.keys()) == {"bodyA", "bodyB"}

    def test_ascii_solid_name(self):
        mesh = g.trimesh.creation.icosphere(subdivisions=1, radius=1.0)
        mesh.metadata = {"name": "solid_A"}
        assert (
            g.trimesh.exchange.stl.export_stl_ascii(mesh).splitlines()[0]
            == "solid solid_A"
        )

    def test_empty(self):
        # demo files to check
        empty_files = ["stl_empty_ascii.stl", "stl_empty_bin.stl"]

        for empty_file in empty_files:
            e = g.get_mesh("emptyIO/" + empty_file)

            # result should be an empty scene without vertices
            assert isinstance(e, g.trimesh.Scene)
            assert not hasattr(e, "vertices")

            # create export
            try:
                e.export(file_type="ply")
            except BaseException:
                return
            raise ValueError("Shouldn't export empty scenes!")

    def test_vertex_order(self):
        for stl in ["featuretype.STL", "ADIS16480.STL", "1002_tray_bottom.STL"]:
            # removing doubles should respect the vertex order
            m_raw = g.get_mesh(stl, process=False)
            m_proc = g.get_mesh(stl, process=True, keep_vertex_order=True)

            verts_raw = g.trimesh.grouping.hashable_rows(m_raw.vertices)
            verts_proc = g.trimesh.grouping.hashable_rows(m_proc.vertices)

            # go through all processed verts
            # find index in unprocessed mesh
            idxs = []
            for vert in verts_proc:
                idxs.append(g.np.where(verts_raw == vert)[0][0])

            # indices should be increasing
            assert (g.np.diff(idxs) > 0).all()

            tris_raw = m_raw.triangles
            tris_proc = m_proc.triangles

            # of course mesh needs to have same faces as before
            assert g.np.allclose(
                g.np.sort(tris_raw, axis=0), g.np.sort(tris_proc, axis=0)
            )

    def test_ascii_keyword(self):
        m = g.get_mesh("ascii.stl.zip", force="mesh")
        assert m.is_watertight


if __name__ == "__main__":
    g.trimesh.util.attach_to_log()
    g.unittest.main()
